1
#pragma once
2

            
3
#include "envoy/network/connection.h"
4
#include "envoy/network/transport_socket.h"
5

            
6
#include "source/common/buffer/buffer_impl.h"
7
#include "source/common/common/logger.h"
8
#include "source/common/http/http1/balsa_parser.h"
9
#include "source/extensions/transport_sockets/common/passthrough.h"
10

            
11
namespace Envoy {
12
namespace Extensions {
13
namespace TransportSockets {
14
namespace Http11Connect {
15

            
16
// If the transport socket options contain http11ProxyInfo and the transport is
17
// secure, this will prepend a CONNECT request to the outbound data and strip
18
// the CONNECT response from the inbound data.
19
class UpstreamHttp11ConnectSocket : public TransportSockets::PassthroughSocket,
20
                                    public Logger::Loggable<Logger::Id::connection> {
21
public:
22
  // Processes response_payload and returns true if it is a valid connect
23
  // response with status code 200.
24
  // @param response_payload the HTTP response bytes
25
  // @param header_complete will be set to true if the response payload contains complete headers.
26
  // @param bytes_processed will return how many bytes of response_payload were processed.
27
  static bool isValidConnectResponse(absl::string_view response_payload, bool& headers_complete,
28
                                     size_t& bytes_processed);
29

            
30
  // Helper method to create a properly formatted CONNECT request with Host header.
31
  // @param target the target hostname:port or IP:port to connect to.
32
  // @return a properly formatted CONNECT request string per RFC 9110 section 9.3.6.
33
  static std::string formatConnectRequest(absl::string_view target);
34

            
35
  UpstreamHttp11ConnectSocket(
36
      Network::TransportSocketPtr&& transport_socket,
37
      Network::TransportSocketOptionsConstSharedPtr options,
38
      std::shared_ptr<const Upstream::HostDescription> host,
39
      absl::optional<Network::TransportSocketOptions::Http11ProxyInfo> proxy_info = absl::nullopt);
40

            
41
  void setTransportSocketCallbacks(Network::TransportSocketCallbacks& callbacks) override;
42
  Network::IoResult doWrite(Buffer::Instance& buffer, bool end_stream) override;
43
  Network::IoResult doRead(Buffer::Instance& buffer) override;
44

            
45
private:
46
  void generateHeader();
47
  Network::IoResult writeHeader();
48

            
49
  inline void
50
  handleProxyInfoConnect(const Network::TransportSocketOptions::Http11ProxyInfo& proxy_info);
51
  inline void handleHostMetadataConnect(std::shared_ptr<const Upstream::HostDescription> host);
52

            
53
  Network::TransportSocketOptionsConstSharedPtr options_;
54
  Network::TransportSocketCallbacks* callbacks_{};
55
  Buffer::OwnedImpl header_buffer_{};
56
  bool need_to_strip_connect_response_{};
57
};
58

            
59
class UpstreamHttp11ConnectSocketFactory : public PassthroughFactory {
60
public:
61
  UpstreamHttp11ConnectSocketFactory(
62
      Network::UpstreamTransportSocketFactoryPtr transport_socket_factory,
63
      absl::optional<Network::TransportSocketOptions::Http11ProxyInfo> proxy_info = absl::nullopt);
64

            
65
  // Network::TransportSocketFactory
66
  Network::TransportSocketPtr
67
  createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options,
68
                        std::shared_ptr<const Upstream::HostDescription> host) const override;
69
  void hashKey(std::vector<uint8_t>& key,
70
               Network::TransportSocketOptionsConstSharedPtr options) const override;
71

            
72
  OptRef<const Network::TransportSocketOptions::Http11ProxyInfo>
73
5
  defaultHttp11ProxyInfo() const override {
74
5
    if (!proxy_info_.has_value()) {
75
3
      return {};
76
3
    }
77
2
    return {proxy_info_.value()};
78
5
  }
79

            
80
private:
81
  const absl::optional<Network::TransportSocketOptions::Http11ProxyInfo> proxy_info_;
82
};
83

            
84
// This is a utility class for isValidConnectResponse. It is only exposed for
85
// coverage testing purposes. See isValidConnectResponse for intended use.
86
class SelfContainedParser : public Http::Http1::ParserCallbacks {
87
public:
88
  SelfContainedParser()
89
32
      : parser_(Http::Http1::MessageType::Response, this, 2000, /* enable_trailers = */ false,
90
32
                /* allow_custom_methods = */ false) {}
91
31
  Http::Http1::CallbackResult onMessageBegin() override {
92
31
    return Http::Http1::CallbackResult::Success;
93
31
  }
94
  Http::Http1::CallbackResult onUrl(const char*, size_t) override {
95
    return Http::Http1::CallbackResult::Success;
96
  }
97
31
  Http::Http1::CallbackResult onStatus(const char*, size_t) override {
98
31
    return Http::Http1::CallbackResult::Success;
99
31
  }
100
7
  Http::Http1::CallbackResult onHeaderField(const char*, size_t) override {
101
7
    return Http::Http1::CallbackResult::Success;
102
7
  }
103
7
  Http::Http1::CallbackResult onHeaderValue(const char*, size_t) override {
104
7
    return Http::Http1::CallbackResult::Success;
105
7
  }
106
28
  Http::Http1::CallbackResult onHeadersComplete() override {
107
28
    headers_complete_ = true;
108
28
    parser_.pause();
109
28
    return Http::Http1::CallbackResult::Success;
110
28
  }
111
2
  void bufferBody(const char*, size_t) override {}
112
5
  Http::Http1::CallbackResult onMessageComplete() override {
113
5
    return Http::Http1::CallbackResult::Success;
114
5
  }
115
  void onChunkHeader(bool) override {}
116

            
117
59
  bool headersComplete() const { return headers_complete_; }
118
110
  Http::Http1::BalsaParser& parser() { return parser_; }
119

            
120
private:
121
  bool headers_complete_ = false;
122
  Http::Http1::BalsaParser parser_;
123
};
124

            
125
} // namespace Http11Connect
126
} // namespace TransportSockets
127
} // namespace Extensions
128
} // namespace Envoy