1
#pragma once
2

            
3
#include <cstdint>
4

            
5
#include "envoy/access_log/access_log.h"
6
#include "envoy/api/api.h"
7
#include "envoy/common/random_generator.h"
8
#include "envoy/config/core/v3/health_check.pb.h"
9
#include "envoy/data/core/v3/health_check_event.pb.h"
10
#include "envoy/grpc/status.h"
11
#include "envoy/network/socket.h"
12
#include "envoy/server/health_checker_config.h"
13
#include "envoy/type/v3/http.pb.h"
14
#include "envoy/type/v3/range.pb.h"
15

            
16
#include "source/common/common/dump_state_utils.h"
17
#include "source/common/common/logger.h"
18
#include "source/common/grpc/codec.h"
19
#include "source/common/http/codec_client.h"
20
#include "source/common/http/response_decoder_impl_base.h"
21
#include "source/common/router/header_parser.h"
22
#include "source/common/stream_info/stream_info_impl.h"
23
#include "source/common/upstream/health_checker_impl.h"
24
#include "source/extensions/health_checkers/common/health_checker_base_impl.h"
25

            
26
#include "src/proto/grpc/health/v1/health.pb.h"
27

            
28
namespace Envoy {
29
namespace Upstream {
30

            
31
class HttpHealthCheckerFactory : public Server::Configuration::CustomHealthCheckerFactory {
32
public:
33
  Upstream::HealthCheckerSharedPtr
34
  createCustomHealthChecker(const envoy::config::core::v3::HealthCheck& config,
35
                            Server::Configuration::HealthCheckerFactoryContext& context) override;
36

            
37
11094
  std::string name() const override { return "envoy.health_checkers.http"; }
38
460
  ProtobufTypes::MessagePtr createEmptyConfigProto() override {
39
460
    return ProtobufTypes::MessagePtr{new envoy::config::core::v3::HealthCheck::HttpHealthCheck()};
40
460
  }
41
};
42

            
43
DECLARE_FACTORY(HttpHealthCheckerFactory);
44

            
45
/**
46
 * HTTP health checker implementation. Connection keep alive is used where possible.
47
 */
48
class HttpHealthCheckerImpl : public HealthCheckerImplBase {
49
public:
50
  HttpHealthCheckerImpl(const Cluster& cluster, const envoy::config::core::v3::HealthCheck& config,
51
                        Server::Configuration::HealthCheckerFactoryContext& context,
52
                        HealthCheckEventLoggerPtr&& event_logger);
53

            
54
  // Returns the HTTP protocol used for the health checker.
55
  Http::Protocol protocol() const;
56

            
57
  /**
58
   * Utility class checking if given http status matches configured expectations.
59
   */
60
  class HttpStatusChecker {
61
  public:
62
    HttpStatusChecker(
63
        const Protobuf::RepeatedPtrField<envoy::type::v3::Int64Range>& expected_statuses,
64
        const Protobuf::RepeatedPtrField<envoy::type::v3::Int64Range>& retriable_statuses,
65
        uint64_t default_expected_status);
66

            
67
    bool inRetriableRanges(uint64_t http_status) const;
68
    bool inExpectedRanges(uint64_t http_status) const;
69

            
70
  private:
71
    static bool inRanges(uint64_t http_status,
72
                         const std::vector<std::pair<uint64_t, uint64_t>>& ranges);
73
    static void validateRange(uint64_t start, uint64_t end, absl::string_view range_type);
74

            
75
    std::vector<std::pair<uint64_t, uint64_t>> expected_ranges_;
76
    std::vector<std::pair<uint64_t, uint64_t>> retriable_ranges_;
77
  };
78

            
79
private:
80
  struct HttpActiveHealthCheckSession : public ActiveHealthCheckSession,
81
                                        public Http::ResponseDecoderImplBase,
82
                                        public Http::StreamCallbacks {
83
    HttpActiveHealthCheckSession(HttpHealthCheckerImpl& parent, const HostSharedPtr& host);
84
    ~HttpActiveHealthCheckSession() override;
85

            
86
    void onResponseComplete();
87
    enum class HealthCheckResult { Succeeded, Degraded, Failed, Retriable };
88
    HealthCheckResult healthCheckResult();
89
    bool shouldClose() const;
90

            
91
    // ActiveHealthCheckSession
92
    void onInterval() override;
93
    void onTimeout() override;
94
    void onDeferredDelete() final;
95

            
96
    // Http::StreamDecoder
97
    void decodeData(Buffer::Instance& data, bool end_stream) override;
98
1
    void decodeMetadata(Http::MetadataMapPtr&&) override {}
99

            
100
    // Http::ResponseDecoder
101
1
    void decode1xxHeaders(Http::ResponseHeaderMapPtr&&) override {}
102
    void decodeHeaders(Http::ResponseHeaderMapPtr&& headers, bool end_stream) override;
103
646
    void decodeTrailers(Http::ResponseTrailerMapPtr&&) override { onResponseComplete(); }
104
    void dumpState(std::ostream& os, int indent_level) const override {
105
      DUMP_STATE_UNIMPLEMENTED(HttpActiveHealthCheckSession);
106
    }
107

            
108
    // Http::StreamCallbacks
109
    void onResetStream(Http::StreamResetReason reason,
110
                       absl::string_view transport_failure_reason) override;
111
1
    void onAboveWriteBufferHighWatermark() override {}
112
1
    void onBelowWriteBufferLowWatermark() override {}
113

            
114
    void onEvent(Network::ConnectionEvent event);
115
    void onGoAway(Http::GoAwayErrorCode error_code);
116

            
117
    class ConnectionCallbackImpl : public Network::ConnectionCallbacks {
118
    public:
119
242
      ConnectionCallbackImpl(HttpActiveHealthCheckSession& parent) : parent_(parent) {}
120
      // Network::ConnectionCallbacks
121
393
      void onEvent(Network::ConnectionEvent event) override { parent_.onEvent(event); }
122
1
      void onAboveWriteBufferHighWatermark() override {}
123
1
      void onBelowWriteBufferLowWatermark() override {}
124

            
125
    private:
126
      HttpActiveHealthCheckSession& parent_;
127
    };
128

            
129
    class HttpConnectionCallbackImpl : public Http::ConnectionCallbacks {
130
    public:
131
242
      HttpConnectionCallbackImpl(HttpActiveHealthCheckSession& parent) : parent_(parent) {}
132
      // Http::ConnectionCallbacks
133
9
      void onGoAway(Http::GoAwayErrorCode error_code) override { parent_.onGoAway(error_code); }
134

            
135
    private:
136
      HttpActiveHealthCheckSession& parent_;
137
    };
138

            
139
    ConnectionCallbackImpl connection_callback_impl_{*this};
140
    HttpConnectionCallbackImpl http_connection_callback_impl_{*this};
141
    HttpHealthCheckerImpl& parent_;
142
    Http::CodecClientPtr client_;
143
    Http::ResponseHeaderMapPtr response_headers_;
144
    Buffer::InstancePtr response_body_;
145
    const std::string& hostname_;
146
    Network::ConnectionInfoProviderSharedPtr local_connection_info_provider_;
147
    // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
148
    const Http::Protocol protocol_;
149
    bool expect_reset_ : 1;
150
    bool reuse_connection_ : 1;
151
    bool request_in_flight_ : 1;
152
  };
153

            
154
  using HttpActiveHealthCheckSessionPtr = std::unique_ptr<HttpActiveHealthCheckSession>;
155

            
156
  virtual Http::CodecClient* createCodecClient(Upstream::Host::CreateConnectionData& data) PURE;
157

            
158
  // HealthCheckerImplBase
159
242
  ActiveHealthCheckSessionPtr makeSession(HostSharedPtr host) override {
160
242
    return std::make_unique<HttpActiveHealthCheckSession>(*this, host);
161
242
  }
162
64
  envoy::data::core::v3::HealthCheckerType healthCheckerType() const override {
163
64
    return envoy::data::core::v3::HTTP;
164
64
  }
165

            
166
  Http::CodecType codecClientType(const envoy::type::v3::CodecClientType& type);
167

            
168
  const std::string path_;
169
  const std::string host_value_;
170
  Buffer::OwnedImpl request_payload_;
171
  PayloadMatcher::MatchSegments receive_bytes_;
172
  const envoy::config::core::v3::RequestMethod method_;
173
  uint64_t response_buffer_size_;
174
  absl::optional<Matchers::StringMatcherImpl> service_name_matcher_;
175
  Router::HeaderParserPtr request_headers_parser_;
176
  const HttpStatusChecker http_status_checker_;
177

            
178
protected:
179
  const Http::CodecType codec_client_type_;
180
  Random::RandomGenerator& random_generator_;
181
};
182

            
183
/**
184
 * Production implementation of the HTTP health checker that allocates a real codec client.
185
 */
186
class ProdHttpHealthCheckerImpl : public HttpHealthCheckerImpl {
187
public:
188
  using HttpHealthCheckerImpl::HttpHealthCheckerImpl;
189

            
190
  // HttpHealthCheckerImpl
191
  Http::CodecClient* createCodecClient(Upstream::Host::CreateConnectionData& data) override;
192
};
193

            
194
} // namespace Upstream
195
} // namespace Envoy