1
#pragma once
2

            
3
#include <cstdint>
4
#include <memory>
5
#include <string>
6

            
7
#include "envoy/http/codec.h"
8
#include "envoy/tcp/conn_pool.h"
9

            
10
#include "source/common/buffer/buffer_impl.h"
11
#include "source/common/common/logger.h"
12
#include "source/common/http/header_map_impl.h"
13
#include "source/common/router/upstream_request.h"
14
#include "source/common/stream_info/stream_info_impl.h"
15
#include "source/extensions/dynamic_modules/abi/abi.h"
16
#include "source/extensions/dynamic_modules/dynamic_modules.h"
17

            
18
namespace Envoy {
19
namespace Extensions {
20
namespace Upstreams {
21
namespace Http {
22
namespace DynamicModules {
23

            
24
using OnBridgeConfigNewType =
25
    decltype(&envoy_dynamic_module_on_upstream_http_tcp_bridge_config_new);
26
using OnBridgeConfigDestroyType =
27
    decltype(&envoy_dynamic_module_on_upstream_http_tcp_bridge_config_destroy);
28
using OnBridgeNewType = decltype(&envoy_dynamic_module_on_upstream_http_tcp_bridge_new);
29
using OnBridgeEncodeHeadersType =
30
    decltype(&envoy_dynamic_module_on_upstream_http_tcp_bridge_encode_headers);
31
using OnBridgeEncodeDataType =
32
    decltype(&envoy_dynamic_module_on_upstream_http_tcp_bridge_encode_data);
33
using OnBridgeEncodeTrailersType =
34
    decltype(&envoy_dynamic_module_on_upstream_http_tcp_bridge_encode_trailers);
35
using OnBridgeOnUpstreamDataType =
36
    decltype(&envoy_dynamic_module_on_upstream_http_tcp_bridge_on_upstream_data);
37
using OnBridgeDestroyType = decltype(&envoy_dynamic_module_on_upstream_http_tcp_bridge_destroy);
38

            
39
/**
40
 * Configuration for the dynamic module upstream HTTP TCP bridge. This holds the loaded
41
 * dynamic module, resolved function pointers, and the in-module configuration.
42
 */
43
class BridgeConfig {
44
public:
45
  static absl::StatusOr<std::shared_ptr<BridgeConfig>>
46
  create(const std::string& bridge_name, const std::string& bridge_config,
47
         Envoy::Extensions::DynamicModules::DynamicModulePtr module);
48

            
49
  ~BridgeConfig();
50

            
51
  OnBridgeConfigNewType on_bridge_config_new_ = nullptr;
52
  OnBridgeConfigDestroyType on_bridge_config_destroy_ = nullptr;
53
  OnBridgeNewType on_bridge_new_ = nullptr;
54
  OnBridgeEncodeHeadersType on_bridge_encode_headers_ = nullptr;
55
  OnBridgeEncodeDataType on_bridge_encode_data_ = nullptr;
56
  OnBridgeEncodeTrailersType on_bridge_encode_trailers_ = nullptr;
57
  OnBridgeOnUpstreamDataType on_bridge_on_upstream_data_ = nullptr;
58
  OnBridgeDestroyType on_bridge_destroy_ = nullptr;
59

            
60
  envoy_dynamic_module_type_upstream_http_tcp_bridge_config_module_ptr in_module_config_ = nullptr;
61

            
62
private:
63
  BridgeConfig(Envoy::Extensions::DynamicModules::DynamicModulePtr module);
64

            
65
  Envoy::Extensions::DynamicModules::DynamicModulePtr dynamic_module_;
66
};
67

            
68
using BridgeConfigSharedPtr = std::shared_ptr<BridgeConfig>;
69

            
70
/**
71
 * TCP connection pool that wraps the standard TCP pool and creates HttpTcpBridge instances.
72
 */
73
class TcpConnPool : public Router::GenericConnPool, public Envoy::Tcp::ConnectionPool::Callbacks {
74
public:
75
  TcpConnPool(Upstream::HostConstSharedPtr host, Upstream::ThreadLocalCluster& thread_local_cluster,
76
              Upstream::ResourcePriority priority, Upstream::LoadBalancerContext* ctx,
77
              BridgeConfigSharedPtr config);
78
  ~TcpConnPool() override;
79

            
80
  // Router::GenericConnPool
81
  void newStream(Router::GenericConnectionPoolCallbacks* callbacks) override;
82
  bool cancelAnyPendingStream() override;
83
  Upstream::HostDescriptionConstSharedPtr host() const override;
84
  bool valid() const override;
85

            
86
  // Tcp::ConnectionPool::Callbacks
87
  void onPoolFailure(ConnectionPool::PoolFailureReason reason,
88
                     absl::string_view transport_failure_reason,
89
                     Upstream::HostDescriptionConstSharedPtr host) override;
90
  void onPoolReady(Envoy::Tcp::ConnectionPool::ConnectionDataPtr&& conn_data,
91
                   Upstream::HostDescriptionConstSharedPtr host) override;
92

            
93
private:
94
  bool resetUpstreamHandleIfSet();
95

            
96
  absl::optional<Envoy::Upstream::TcpPoolData> conn_pool_data_;
97
  Envoy::Tcp::ConnectionPool::Cancellable* upstream_handle_{};
98
  Router::GenericConnectionPoolCallbacks* callbacks_{};
99
  BridgeConfigSharedPtr config_;
100
};
101

            
102
/**
103
 * The upstream HTTP TCP bridge that delegates protocol transformation to a dynamic module.
104
 * This implements Router::GenericUpstream to receive HTTP from the UpstreamCodecFilter, and
105
 * Tcp::ConnectionPool::UpstreamCallbacks to receive TCP data from the upstream connection.
106
 *
107
 * The module controls the flow by calling explicit ABI callbacks (send_upstream_data,
108
 * send_response, send_response_headers, send_response_data, send_response_trailers) rather
109
 * than returning status codes from event hooks.
110
 */
111
class HttpTcpBridge : public Router::GenericUpstream,
112
                      public Envoy::Tcp::ConnectionPool::UpstreamCallbacks,
113
                      public Logger::Loggable<Logger::Id::dynamic_modules> {
114
public:
115
  HttpTcpBridge(Router::UpstreamToDownstream* upstream_request,
116
                Envoy::Tcp::ConnectionPool::ConnectionDataPtr&& upstream,
117
                BridgeConfigSharedPtr config);
118
  ~HttpTcpBridge() override;
119

            
120
  // Router::GenericUpstream
121
  Envoy::Http::Status encodeHeaders(const Envoy::Http::RequestHeaderMap& headers,
122
                                    bool end_stream) override;
123
  void encodeData(Buffer::Instance& data, bool end_stream) override;
124
  void encodeTrailers(const Envoy::Http::RequestTrailerMap& trailers) override;
125
1
  void encodeMetadata(const Envoy::Http::MetadataMapVector&) override {}
126
1
  void enableTcpTunneling() override {}
127
  void readDisable(bool disable) override;
128
  void resetStream() override;
129
3
  void setAccount(Buffer::BufferMemoryAccountSharedPtr) override {}
130
3
  const StreamInfo::BytesMeterSharedPtr& bytesMeter() override { return bytes_meter_; }
131

            
132
  // Tcp::ConnectionPool::UpstreamCallbacks
133
  void onUpstreamData(Buffer::Instance& data, bool end_stream) override;
134
  void onEvent(Network::ConnectionEvent event) override;
135
  void onAboveWriteBufferHighWatermark() override;
136
  void onBelowWriteBufferLowWatermark() override;
137

            
138
  // Accessors for ABI callbacks.
139
15
  const Envoy::Http::RequestHeaderMap* requestHeaders() const { return request_headers_; }
140
8
  Buffer::Instance* requestBuffer() { return request_buffer_; }
141
3
  Buffer::Instance* responseBuffer() { return response_buffer_; }
142

            
143
  // Called by ABI callbacks to send data upstream.
144
  void sendUpstreamData(absl::string_view data, bool end_stream);
145

            
146
  // Called by ABI callbacks to send a complete local response downstream.
147
  void sendResponse(uint32_t status_code,
148
                    envoy_dynamic_module_type_module_http_header* headers_vector,
149
                    size_t headers_vector_size, absl::string_view body);
150

            
151
  // Called by ABI callbacks to send response headers downstream.
152
  void sendResponseHeaders(uint32_t status_code,
153
                           envoy_dynamic_module_type_module_http_header* headers_vector,
154
                           size_t headers_vector_size, bool end_stream);
155

            
156
  // Called by ABI callbacks to send response body data downstream.
157
  void sendResponseData(absl::string_view data, bool end_stream);
158

            
159
  // Called by ABI callbacks to send response trailers downstream.
160
  void sendResponseTrailers(envoy_dynamic_module_type_module_http_header* trailers_vector,
161
                            size_t trailers_vector_size);
162

            
163
private:
164
  Envoy::Http::ResponseHeaderMapPtr
165
  buildResponseHeaders(uint32_t status_code,
166
                       envoy_dynamic_module_type_module_http_header* headers_vector,
167
                       size_t headers_vector_size);
168

            
169
  Router::UpstreamToDownstream* upstream_request_;
170
  Envoy::Tcp::ConnectionPool::ConnectionDataPtr upstream_conn_data_;
171
  BridgeConfigSharedPtr config_;
172
  envoy_dynamic_module_type_upstream_http_tcp_bridge_module_ptr in_module_bridge_ = nullptr;
173

            
174
  bool downstream_complete_ = false;
175

            
176
  const Envoy::Http::RequestHeaderMap* request_headers_ = nullptr;
177
  Buffer::Instance* request_buffer_ = nullptr;
178
  Buffer::Instance* response_buffer_ = nullptr;
179

            
180
  StreamInfo::BytesMeterSharedPtr bytes_meter_{std::make_shared<StreamInfo::BytesMeter>()};
181
};
182

            
183
} // namespace DynamicModules
184
} // namespace Http
185
} // namespace Upstreams
186
} // namespace Extensions
187
} // namespace Envoy