/proc/self/cwd/source/common/http/http1/codec_impl.h
Line | Count | Source (jump to first uncovered line) |
1 | | #pragma once |
2 | | |
3 | | #include <array> |
4 | | #include <cstdint> |
5 | | #include <list> |
6 | | #include <memory> |
7 | | #include <string> |
8 | | |
9 | | #include "envoy/common/optref.h" |
10 | | #include "envoy/common/scope_tracker.h" |
11 | | #include "envoy/config/core/v3/protocol.pb.h" |
12 | | #include "envoy/http/codec.h" |
13 | | #include "envoy/network/connection.h" |
14 | | #include "envoy/server/overload/overload_manager.h" |
15 | | |
16 | | #include "source/common/buffer/watermark_buffer.h" |
17 | | #include "source/common/common/assert.h" |
18 | | #include "source/common/common/statusor.h" |
19 | | #include "source/common/http/codec_helper.h" |
20 | | #include "source/common/http/codes.h" |
21 | | #include "source/common/http/header_map_impl.h" |
22 | | #include "source/common/http/http1/codec_stats.h" |
23 | | #include "source/common/http/http1/header_formatter.h" |
24 | | #include "source/common/http/http1/parser.h" |
25 | | #include "source/common/http/status.h" |
26 | | |
27 | | namespace Envoy { |
28 | | namespace Http { |
29 | | namespace Http1 { |
30 | | |
31 | | // The default limit of 80 KiB is the vanilla http_parser behaviour. |
32 | | inline constexpr uint32_t MAX_RESPONSE_HEADERS_KB = 80; |
33 | | |
34 | | class ConnectionImpl; |
35 | | |
36 | | /** |
37 | | * Base class for HTTP/1.1 request and response encoders. |
38 | | */ |
39 | | class StreamEncoderImpl : public virtual StreamEncoder, |
40 | | public Stream, |
41 | | public Logger::Loggable<Logger::Id::http>, |
42 | | public StreamCallbackHelper, |
43 | | public Http1StreamEncoderOptions { |
44 | | public: |
45 | 39.5k | ~StreamEncoderImpl() override { |
46 | | // When the stream goes away, undo any read blocks to resume reading. |
47 | 43.8k | while (read_disable_calls_ != 0) { |
48 | 4.30k | StreamEncoderImpl::readDisable(false); |
49 | 4.30k | } |
50 | 39.5k | } |
51 | | // Http::StreamEncoder |
52 | | void encodeData(Buffer::Instance& data, bool end_stream) override; |
53 | | void encodeMetadata(const MetadataMapVector&) override; |
54 | 823k | Stream& getStream() override { return *this; } |
55 | 0 | Http1StreamEncoderOptionsOptRef http1StreamEncoderOptions() override { return *this; } |
56 | | |
57 | | // Http::Http1StreamEncoderOptions |
58 | 274 | void disableChunkEncoding() override { disable_chunk_encoding_ = true; } |
59 | | |
60 | | // Http::Stream |
61 | 25.7k | void addCallbacks(StreamCallbacks& callbacks) override { addCallbacksHelper(callbacks); } |
62 | 6.82k | void removeCallbacks(StreamCallbacks& callbacks) override { removeCallbacksHelper(callbacks); } |
63 | | CodecEventCallbacks* registerCodecEventCallbacks(CodecEventCallbacks* codec_callbacks) override; |
64 | | // After this is called, for the HTTP/1 codec, the connection should be closed, i.e. no further |
65 | | // progress may be made with the codec. |
66 | | void resetStream(StreamResetReason reason) override; |
67 | | void readDisable(bool disable) override; |
68 | | uint32_t bufferLimit() const override; |
69 | 1.41k | absl::string_view responseDetails() override { return details_; } |
70 | | const Network::ConnectionInfoProvider& connectionInfoProvider() override; |
71 | 3.87k | void setFlushTimeout(std::chrono::milliseconds) override { |
72 | | // HTTP/1 has one stream per connection, thus any data encoded is immediately written to the |
73 | | // connection, invoking any watermarks as necessary. There is no internal buffering that would |
74 | | // require a flush timeout not already covered by other timeouts. |
75 | 3.87k | } |
76 | | |
77 | 3.87k | Buffer::BufferMemoryAccountSharedPtr account() const override { return buffer_memory_account_; } |
78 | | |
79 | 3.91k | void setAccount(Buffer::BufferMemoryAccountSharedPtr account) override { |
80 | | // TODO(kbaichoo): implement account tracking for H1. Particularly, binding |
81 | | // the account to the buffers used. The current wiring is minimal, and used |
82 | | // to ensure the memory_account gets notified that the downstream request is |
83 | | // closing. |
84 | 3.91k | buffer_memory_account_ = account; |
85 | 3.91k | } |
86 | | |
87 | 16.8k | void setIsResponseToHeadRequest(bool value) { is_response_to_head_request_ = value; } |
88 | 16.8k | void setIsResponseToConnectRequest(bool value) { is_response_to_connect_request_ = value; } |
89 | 14.3k | void setDetails(absl::string_view details) { details_ = details; } |
90 | | |
91 | 758k | const StreamInfo::BytesMeterSharedPtr& bytesMeter() override { return bytes_meter_; } |
92 | | |
93 | | protected: |
94 | | StreamEncoderImpl(ConnectionImpl& connection, StreamInfo::BytesMeterSharedPtr&& bytes_meter); |
95 | | void encodeHeadersBase(const RequestOrResponseHeaderMap& headers, absl::optional<uint64_t> status, |
96 | | bool end_stream, bool bodiless_request); |
97 | | void encodeTrailersBase(const HeaderMap& headers); |
98 | | |
99 | | Buffer::BufferMemoryAccountSharedPtr buffer_memory_account_; |
100 | | ConnectionImpl& connection_; |
101 | | uint32_t read_disable_calls_{}; |
102 | | bool disable_chunk_encoding_ : 1; |
103 | | bool chunk_encoding_ : 1; |
104 | | bool connect_request_ : 1; |
105 | | bool is_tcp_tunneling_ : 1; |
106 | | bool is_response_to_head_request_ : 1; |
107 | | bool is_response_to_connect_request_ : 1; |
108 | | |
109 | | private: |
110 | | /** |
111 | | * Called to encode an individual header. |
112 | | * @param key supplies the header to encode as a string_view. |
113 | | * @param value supplies the value to encode as a string_view. |
114 | | */ |
115 | | void encodeHeader(absl::string_view key, absl::string_view value); |
116 | | |
117 | | /** |
118 | | * Called to finalize a stream encode. |
119 | | */ |
120 | | void endEncode(); |
121 | | |
122 | | /** |
123 | | * Encapsulates notification to various objects that the encode completed. |
124 | | */ |
125 | | void notifyEncodeComplete(); |
126 | | |
127 | | void encodeFormattedHeader(absl::string_view key, absl::string_view value, |
128 | | HeaderKeyFormatterOptConstRef formatter); |
129 | | |
130 | | void flushOutput(bool end_encode = false); |
131 | | |
132 | | absl::string_view details_; |
133 | | StreamInfo::BytesMeterSharedPtr bytes_meter_; |
134 | | CodecEventCallbacks* codec_callbacks_{nullptr}; |
135 | | }; |
136 | | |
137 | | /** |
138 | | * HTTP/1.1 response encoder. |
139 | | */ |
140 | | class ResponseEncoderImpl : public StreamEncoderImpl, public ResponseEncoder { |
141 | | public: |
142 | | ResponseEncoderImpl(ConnectionImpl& connection, StreamInfo::BytesMeterSharedPtr&& bytes_meter, |
143 | | bool stream_error_on_invalid_http_message) |
144 | | : StreamEncoderImpl(connection, std::move(bytes_meter)), |
145 | 27.9k | stream_error_on_invalid_http_message_(stream_error_on_invalid_http_message) {} Unexecuted instantiation: Envoy::Http::Http1::ResponseEncoderImpl::ResponseEncoderImpl(Envoy::Http::Http1::ConnectionImpl&, std::__1::shared_ptr<Envoy::StreamInfo::BytesMeter>&&, bool) Envoy::Http::Http1::ResponseEncoderImpl::ResponseEncoderImpl(Envoy::Http::Http1::ConnectionImpl&, std::__1::shared_ptr<Envoy::StreamInfo::BytesMeter>&&, bool) Line | Count | Source | 145 | 27.9k | stream_error_on_invalid_http_message_(stream_error_on_invalid_http_message) {} |
|
146 | | |
147 | 27.9k | ~ResponseEncoderImpl() override { |
148 | | // Only the downstream stream should clear the downstream of the |
149 | | // memory account. |
150 | | // |
151 | | // There are cases where a corresponding upstream stream dtor might |
152 | | // be called, but the downstream stream isn't going to terminate soon |
153 | | // such as StreamDecoderFilterCallbacks::recreateStream(). |
154 | 27.9k | if (buffer_memory_account_) { |
155 | 0 | buffer_memory_account_->clearDownstream(); |
156 | 0 | } |
157 | 27.9k | } |
158 | | |
159 | 13.8k | bool startedResponse() { return started_response_; } |
160 | | |
161 | | // Http::ResponseEncoder |
162 | | void encode1xxHeaders(const ResponseHeaderMap& headers) override; |
163 | | void encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) override; |
164 | 28 | void encodeTrailers(const ResponseTrailerMap& trailers) override { encodeTrailersBase(trailers); } |
165 | | |
166 | 664 | bool streamErrorOnInvalidHttpMessage() const override { |
167 | 664 | return stream_error_on_invalid_http_message_; |
168 | 664 | } |
169 | | void setDeferredLoggingHeadersAndTrailers(Http::RequestHeaderMapConstSharedPtr, |
170 | | Http::ResponseHeaderMapConstSharedPtr, |
171 | | Http::ResponseTrailerMapConstSharedPtr, |
172 | 0 | StreamInfo::StreamInfo&) override {} |
173 | | |
174 | | // For H/1, ResponseEncoder doesn't hold a pointer to RequestDecoder. |
175 | | // TODO(paulsohn): Enable H/1 codec to get a pointer to the new |
176 | | // request decoder on recreateStream, here or elsewhere. |
177 | 0 | void setRequestDecoder(Http::RequestDecoder& /*decoder*/) override {} |
178 | | |
179 | | // Http1::StreamEncoderImpl |
180 | | void resetStream(StreamResetReason reason) override; |
181 | | |
182 | | private: |
183 | | bool started_response_{}; |
184 | | const bool stream_error_on_invalid_http_message_; |
185 | | }; |
186 | | |
187 | | /** |
188 | | * HTTP/1.1 request encoder. |
189 | | */ |
190 | | class RequestEncoderImpl : public StreamEncoderImpl, public RequestEncoder { |
191 | | public: |
192 | | RequestEncoderImpl(ConnectionImpl& connection, StreamInfo::BytesMeterSharedPtr&& bytes_meter) |
193 | 11.6k | : StreamEncoderImpl(connection, std::move(bytes_meter)) {} Unexecuted instantiation: Envoy::Http::Http1::RequestEncoderImpl::RequestEncoderImpl(Envoy::Http::Http1::ConnectionImpl&, std::__1::shared_ptr<Envoy::StreamInfo::BytesMeter>&&) Envoy::Http::Http1::RequestEncoderImpl::RequestEncoderImpl(Envoy::Http::Http1::ConnectionImpl&, std::__1::shared_ptr<Envoy::StreamInfo::BytesMeter>&&) Line | Count | Source | 193 | 11.6k | : StreamEncoderImpl(connection, std::move(bytes_meter)) {} |
|
194 | 49 | bool upgradeRequest() const { return upgrade_request_; } |
195 | 17.0k | bool headRequest() const { return head_request_; } |
196 | 5.43k | bool connectRequest() const { return connect_request_; } |
197 | | |
198 | | // Http::RequestEncoder |
199 | | Status encodeHeaders(const RequestHeaderMap& headers, bool end_stream) override; |
200 | 2.43k | void encodeTrailers(const RequestTrailerMap& trailers) override { encodeTrailersBase(trailers); } |
201 | 0 | void enableTcpTunneling() override { is_tcp_tunneling_ = true; } |
202 | | |
203 | | private: |
204 | | bool upgrade_request_{}; |
205 | | bool head_request_{}; |
206 | | }; |
207 | | |
208 | | /** |
209 | | * Base class for HTTP/1.1 client and server connections. |
210 | | * Handles the callbacks of http_parser with its own base routine and then |
211 | | * virtual dispatches to its subclasses. |
212 | | */ |
213 | | class ConnectionImpl : public virtual Connection, |
214 | | protected Logger::Loggable<Logger::Id::http>, |
215 | | public ParserCallbacks, |
216 | | public ScopeTrackedObject { |
217 | | public: |
218 | | /** |
219 | | * @return Network::Connection& the backing network connection. |
220 | | */ |
221 | 77.1k | Network::Connection& connection() { return connection_; } |
222 | 0 | const Network::Connection& connection() const { return connection_; } |
223 | | |
224 | | /** |
225 | | * Called when the active encoder has completed encoding the outbound half of the stream. |
226 | | */ |
227 | | virtual void onEncodeComplete() PURE; |
228 | | |
229 | | virtual StreamInfo::BytesMeter& getBytesMeter() PURE; |
230 | | |
231 | | /** |
232 | | * Called when resetStream() has been called on an active stream. In HTTP/1.1 the only |
233 | | * valid operation after this point is for the connection to get blown away, but we will not |
234 | | * fire any more callbacks in case some stack has to unwind. |
235 | | */ |
236 | | void onResetStreamBase(StreamResetReason reason); |
237 | | |
238 | | /** |
239 | | * Flush all pending output from encoding. |
240 | | */ |
241 | | uint64_t flushOutput(bool end_encode = false); |
242 | | |
243 | 171k | Buffer::Instance& buffer() { return *output_buffer_; } |
244 | | |
245 | 8.63k | void readDisable(bool disable) { |
246 | 8.63k | if (connection_.state() == Network::Connection::State::Open) { |
247 | 8.61k | connection_.readDisable(disable); |
248 | 8.61k | } |
249 | 8.63k | } |
250 | 3.87k | uint32_t bufferLimit() { return connection_.bufferLimit(); } |
251 | 0 | virtual bool supportsHttp10() { return false; } |
252 | | bool maybeDirectDispatch(Buffer::Instance& data); |
253 | 6.24k | virtual void maybeAddSentinelBufferFragment(Buffer::Instance&) {} |
254 | 182 | CodecStats& stats() { return stats_; } |
255 | 22.0k | bool enableTrailers() const { return codec_settings_.enable_trailers_; } |
256 | 11.4k | virtual bool sendFullyQualifiedUrl() const { return codec_settings_.send_fully_qualified_url_; } |
257 | 26.1k | HeaderKeyFormatterOptConstRef formatter() const { |
258 | 26.1k | return makeOptRefFromPtr(encode_only_header_key_formatter_.get()); |
259 | 26.1k | } |
260 | | |
261 | | // Http::Connection |
262 | | Http::Status dispatch(Buffer::Instance& data) override; |
263 | 0 | void goAway() override {} // Called during connection manager drain flow |
264 | 148k | Protocol protocol() override { return protocol_; } |
265 | 0 | void shutdownNotice() override {} // Called during connection manager drain flow |
266 | 893 | bool wantsToWrite() override { return false; } |
267 | 0 | void onUnderlyingConnectionAboveWriteBufferHighWatermark() override { onAboveHighWatermark(); } |
268 | 0 | void onUnderlyingConnectionBelowWriteBufferLowWatermark() override { onBelowLowWatermark(); } |
269 | | |
270 | | // Codec errors found in callbacks are overridden within the http_parser library. This holds those |
271 | | // errors to propagate them through to dispatch() where we can handle the error. |
272 | | Envoy::Http::Status codec_status_; |
273 | | |
274 | | // ScopeTrackedObject |
275 | | void dumpState(std::ostream& os, int indent_level) const override; |
276 | | |
277 | | protected: |
278 | | ConnectionImpl(Network::Connection& connection, CodecStats& stats, const Http1Settings& settings, |
279 | | MessageType type, uint32_t max_headers_kb, const uint32_t max_headers_count); |
280 | | |
281 | 28.4k | bool resetStreamCalled() { return reset_stream_called_; } |
282 | | |
283 | | // This must be protected because it is called through ServerConnectionImpl::sendProtocolError. |
284 | | Status onMessageBeginImpl(); |
285 | | |
286 | | /** |
287 | | * Get memory used to represent HTTP headers or trailers currently being parsed. |
288 | | * Computed by adding the partial header field and value that is currently being parsed and the |
289 | | * estimated header size for previous header lines provided by HeaderMap::byteSize(). |
290 | | */ |
291 | | virtual uint32_t getHeadersSize(); |
292 | | |
293 | | /** |
294 | | * Called from onUrl, onHeaderFields and onHeaderValue to verify that the headers do not exceed |
295 | | * the configured max header size limit. |
296 | | * @return A codecProtocolError status if headers exceed the size limit. |
297 | | */ |
298 | | Status checkMaxHeadersSize(); |
299 | | |
300 | | Network::Connection& connection_; |
301 | | CodecStats& stats_; |
302 | | const Http1Settings codec_settings_; |
303 | | std::unique_ptr<Parser> parser_; |
304 | | Buffer::Instance* current_dispatching_buffer_{}; |
305 | | Buffer::Instance* output_buffer_ = nullptr; // Not owned |
306 | | Http::Code error_code_{Http::Code::BadRequest}; |
307 | | const HeaderKeyFormatterConstPtr encode_only_header_key_formatter_; |
308 | | HeaderString current_header_field_; |
309 | | HeaderString current_header_value_; |
310 | | bool processing_trailers_ : 1; |
311 | | bool handling_upgrade_ : 1; |
312 | | bool reset_stream_called_ : 1; |
313 | | // Deferred end stream headers indicate that we are not going to raise headers until the full |
314 | | // HTTP/1 message has been flushed from the parser. This allows raising an HTTP/2 style headers |
315 | | // block with end stream set to true with no further protocol data remaining. |
316 | | bool deferred_end_stream_headers_ : 1; |
317 | | bool dispatching_ : 1; |
318 | | bool dispatching_slice_already_drained_ : 1; |
319 | | StreamInfo::BytesMeterSharedPtr bytes_meter_before_stream_; |
320 | | const uint32_t max_headers_kb_; |
321 | | const uint32_t max_headers_count_; |
322 | | |
323 | | private: |
324 | | enum class HeaderParsingState { Field, Value, Done }; |
325 | 0 | friend std::ostream& operator<<(std::ostream& os, HeaderParsingState parsing_state) { |
326 | 0 | switch (parsing_state) { |
327 | 0 | case ConnectionImpl::HeaderParsingState::Field: |
328 | 0 | return os << "Field"; |
329 | 0 | case ConnectionImpl::HeaderParsingState::Value: |
330 | 0 | return os << "Value"; |
331 | 0 | case ConnectionImpl::HeaderParsingState::Done: |
332 | 0 | return os << "Done"; |
333 | 0 | } |
334 | 0 | return os; |
335 | 0 | } |
336 | | |
337 | | virtual HeaderMap& headersOrTrailers() PURE; |
338 | | virtual RequestOrResponseHeaderMap& requestOrResponseHeaders() PURE; |
339 | | virtual void allocHeaders(StatefulHeaderKeyFormatterPtr&& formatter) PURE; |
340 | | virtual void allocTrailers() PURE; |
341 | | |
342 | | /** |
343 | | * Called for each header in order to complete an in progress header decode. |
344 | | * @return A status representing success. |
345 | | */ |
346 | | Status completeCurrentHeader(); |
347 | | |
348 | | /** |
349 | | * Check if header name contains underscore character. |
350 | | * Underscore character is allowed in header names by the RFC-7230 and this check is implemented |
351 | | * as a security measure due to systems that treat '_' and '-' as interchangeable. |
352 | | * The ServerConnectionImpl may drop header or reject request based on the |
353 | | * `common_http_protocol_options.headers_with_underscores_action` configuration option in the |
354 | | * HttpConnectionManager. |
355 | | */ |
356 | 0 | virtual bool shouldDropHeaderWithUnderscoresInNames(absl::string_view /* header_name */) const { |
357 | 0 | return false; |
358 | 0 | } |
359 | | |
360 | | /** |
361 | | * Dispatch a memory span. |
362 | | * @param slice supplies the start address. |
363 | | * @len supplies the length of the span. |
364 | | */ |
365 | | Envoy::StatusOr<size_t> dispatchSlice(const char* slice, size_t len); |
366 | | |
367 | | void onDispatch(const Buffer::Instance& data); |
368 | | |
369 | | // ParserCallbacks. |
370 | | CallbackResult onMessageBegin() override; |
371 | | CallbackResult onUrl(const char* data, size_t length) override; |
372 | | CallbackResult onStatus(const char* data, size_t length) override; |
373 | | CallbackResult onHeaderField(const char* data, size_t length) override; |
374 | | CallbackResult onHeaderValue(const char* data, size_t length) override; |
375 | | CallbackResult onHeadersComplete() override; |
376 | | void bufferBody(const char* data, size_t length) override; |
377 | | CallbackResult onMessageComplete() override; |
378 | | void onChunkHeader(bool is_final_chunk) override; |
379 | | |
380 | | // Internal implementations of ParserCallbacks methods, |
381 | | // and virtual methods for connection-specific implementations. |
382 | | virtual Status onMessageBeginBase() PURE; |
383 | | virtual Status onUrlBase(const char* data, size_t length) PURE; |
384 | | virtual Status onStatusBase(const char* data, size_t length) PURE; |
385 | | Status onHeaderFieldImpl(const char* data, size_t length); |
386 | | Status onHeaderValueImpl(const char* data, size_t length); |
387 | | StatusOr<CallbackResult> onHeadersCompleteImpl(); |
388 | | virtual StatusOr<CallbackResult> onHeadersCompleteBase() PURE; |
389 | | StatusOr<CallbackResult> onMessageCompleteImpl(); |
390 | | virtual CallbackResult onMessageCompleteBase() PURE; |
391 | | |
392 | | // These helpers wrap *Impl() calls in the overrides of non-void |
393 | | // ParserCallbacks methods. |
394 | | CallbackResult setAndCheckCallbackStatus(Status&& status); |
395 | | CallbackResult setAndCheckCallbackStatusOr(StatusOr<CallbackResult>&& statusor); |
396 | | |
397 | | /** |
398 | | * Push the accumulated body through the filter pipeline. |
399 | | */ |
400 | | void dispatchBufferedBody(); |
401 | | |
402 | | /** |
403 | | * Called to see if upgrade transition is allowed. |
404 | | */ |
405 | | virtual bool upgradeAllowed() const PURE; |
406 | | |
407 | | /** |
408 | | * Called with body data is available for processing when either: |
409 | | * - There is an accumulated partial body after the parser is done processing bytes read from the |
410 | | * socket |
411 | | * - The parser encounters the last byte of the body |
412 | | * - The codec does a direct dispatch from the read buffer |
413 | | * For performance reasons there is at most one call to onBody per call to HTTP/1 |
414 | | * ConnectionImpl::dispatch call. |
415 | | * @param data supplies the body data |
416 | | */ |
417 | | virtual void onBody(Buffer::Instance& data) PURE; |
418 | | |
419 | | /** |
420 | | * @see onResetStreamBase(). |
421 | | */ |
422 | | virtual void onResetStream(StreamResetReason reason) PURE; |
423 | | |
424 | | /** |
425 | | * Send a protocol error response to remote. |
426 | | */ |
427 | | virtual Status sendProtocolError(absl::string_view details) PURE; |
428 | | |
429 | | /** |
430 | | * Called when output_buffer_ or the underlying connection go from below a low watermark to over |
431 | | * a high watermark. |
432 | | */ |
433 | | virtual void onAboveHighWatermark() PURE; |
434 | | |
435 | | /** |
436 | | * Called when output_buffer_ or the underlying connection go from above a high watermark to |
437 | | * below a low watermark. |
438 | | */ |
439 | | virtual void onBelowLowWatermark() PURE; |
440 | | |
441 | | /** |
442 | | * Check if header name contains underscore character. |
443 | | * The ServerConnectionImpl may drop header or reject request based on configuration. |
444 | | * @return A status representing whether the request is rejected. |
445 | | */ |
446 | 36.4k | virtual Status checkHeaderNameForUnderscores() { return okStatus(); } |
447 | | |
448 | | /** |
449 | | * Additional state to dump on crash. |
450 | | */ |
451 | | virtual void dumpAdditionalState(std::ostream& os, int indent_level) const PURE; |
452 | | |
453 | | HeaderParsingState header_parsing_state_{HeaderParsingState::Field}; |
454 | | // Used to accumulate the HTTP message body during the current dispatch call. The accumulated body |
455 | | // is pushed through the filter pipeline either at the end of the current dispatch call, or when |
456 | | // the last byte of the body is processed (whichever happens first). |
457 | | Buffer::OwnedImpl buffered_body_; |
458 | | Protocol protocol_{Protocol::Http11}; |
459 | | }; |
460 | | |
461 | | /** |
462 | | * Implementation of Http::ServerConnection for HTTP/1.1. |
463 | | */ |
464 | | class ServerConnectionImpl : public ServerConnection, public ConnectionImpl { |
465 | | public: |
466 | | ServerConnectionImpl(Network::Connection& connection, CodecStats& stats, |
467 | | ServerConnectionCallbacks& callbacks, const Http1Settings& settings, |
468 | | uint32_t max_request_headers_kb, const uint32_t max_request_headers_count, |
469 | | envoy::config::core::v3::HttpProtocolOptions::HeadersWithUnderscoresAction |
470 | | headers_with_underscores_action, |
471 | | Server::OverloadManager& overload_manager); |
472 | 342 | bool supportsHttp10() override { return codec_settings_.accept_http_10_; } |
473 | | |
474 | | protected: |
475 | | /** |
476 | | * An active HTTP/1.1 request. |
477 | | */ |
478 | | struct ActiveRequest : public Event::DeferredDeletable { |
479 | | ActiveRequest(ServerConnectionImpl& connection, StreamInfo::BytesMeterSharedPtr&& bytes_meter) |
480 | | : response_encoder_(connection, std::move(bytes_meter), |
481 | 27.9k | connection.codec_settings_.stream_error_on_invalid_http_message_) {} |
482 | 27.9k | ~ActiveRequest() override = default; |
483 | | |
484 | | void dumpState(std::ostream& os, int indent_level) const; |
485 | | HeaderString request_url_; |
486 | | RequestDecoder* request_decoder_{}; |
487 | | ResponseEncoderImpl response_encoder_; |
488 | | bool remote_complete_{}; |
489 | | }; |
490 | 0 | ActiveRequest* activeRequest() { return active_request_.get(); } |
491 | | // ConnectionImpl |
492 | | CallbackResult onMessageCompleteBase() override; |
493 | | // Add the size of the request_url to the reported header size when processing request headers. |
494 | | uint32_t getHeadersSize() override; |
495 | | |
496 | | private: |
497 | | /** |
498 | | * Manipulate the request's first line, parsing the url and converting to a relative path if |
499 | | * necessary. Compute Host / :authority headers based on 7230#5.7 and 7230#6 |
500 | | * |
501 | | * @param is_connect true if the request has the CONNECT method |
502 | | * @param headers the request's headers |
503 | | * @return Status representing success or failure. This will fail if there is an invalid url in |
504 | | * the request line. |
505 | | */ |
506 | | Status handlePath(RequestHeaderMap& headers, absl::string_view method); |
507 | | |
508 | | // ParserCallbacks. |
509 | | Status onUrlBase(const char* data, size_t length) override; |
510 | 0 | Status onStatusBase(const char*, size_t) override { return okStatus(); } |
511 | | // ConnectionImpl |
512 | | Http::Status dispatch(Buffer::Instance& data) override; |
513 | | void onEncodeComplete() override; |
514 | 689k | StreamInfo::BytesMeter& getBytesMeter() override { |
515 | 689k | if (active_request_) { |
516 | 658k | return *(active_request_->response_encoder_.getStream().bytesMeter()); |
517 | 658k | } |
518 | 31.0k | if (bytes_meter_before_stream_ == nullptr) { |
519 | 30.9k | bytes_meter_before_stream_ = std::make_shared<StreamInfo::BytesMeter>(); |
520 | 30.9k | } |
521 | 31.0k | return *bytes_meter_before_stream_; |
522 | 689k | } |
523 | | Status onMessageBeginBase() override; |
524 | | Envoy::StatusOr<CallbackResult> onHeadersCompleteBase() override; |
525 | | // If upgrade behavior is not allowed, the HCM will have sanitized the headers out. |
526 | 370 | bool upgradeAllowed() const override { return true; } |
527 | | void onBody(Buffer::Instance& data) override; |
528 | | void onResetStream(StreamResetReason reason) override; |
529 | | Status sendProtocolError(absl::string_view details) override; |
530 | | Status sendOverloadError(); |
531 | | void onAboveHighWatermark() override; |
532 | | void onBelowLowWatermark() override; |
533 | 652k | HeaderMap& headersOrTrailers() override { |
534 | 652k | if (absl::holds_alternative<RequestHeaderMapPtr>(headers_or_trailers_)) { |
535 | 638k | return *absl::get<RequestHeaderMapPtr>(headers_or_trailers_); |
536 | 638k | } else { |
537 | 13.8k | return *absl::get<RequestTrailerMapPtr>(headers_or_trailers_); |
538 | 13.8k | } |
539 | 652k | } |
540 | 17.9k | RequestOrResponseHeaderMap& requestOrResponseHeaders() override { |
541 | 17.9k | return *absl::get<RequestHeaderMapPtr>(headers_or_trailers_); |
542 | 17.9k | } |
543 | 27.9k | void allocHeaders(StatefulHeaderKeyFormatterPtr&& formatter) override { |
544 | 27.9k | ASSERT(nullptr == absl::get<RequestHeaderMapPtr>(headers_or_trailers_)); |
545 | 27.9k | ASSERT(!processing_trailers_); |
546 | 27.9k | auto headers = RequestHeaderMapImpl::create(max_headers_kb_, max_headers_count_); |
547 | 27.9k | headers->setFormatter(std::move(formatter)); |
548 | 27.9k | headers_or_trailers_.emplace<RequestHeaderMapPtr>(std::move(headers)); |
549 | 27.9k | } |
550 | 113 | void allocTrailers() override { |
551 | 113 | ASSERT(processing_trailers_); |
552 | 113 | if (!absl::holds_alternative<RequestTrailerMapPtr>(headers_or_trailers_)) { |
553 | 113 | headers_or_trailers_.emplace<RequestTrailerMapPtr>( |
554 | 113 | RequestTrailerMapImpl::create(max_headers_kb_, max_headers_count_)); |
555 | 113 | } |
556 | 113 | } |
557 | | void dumpAdditionalState(std::ostream& os, int indent_level) const override; |
558 | | |
559 | | void releaseOutboundResponse(const Buffer::OwnedBufferFragmentImpl* fragment); |
560 | | void maybeAddSentinelBufferFragment(Buffer::Instance& output_buffer) override; |
561 | | |
562 | | Status doFloodProtectionChecks() const; |
563 | | Status checkHeaderNameForUnderscores() override; |
564 | | Status checkProtocolVersion(RequestHeaderMap& headers); |
565 | | |
566 | | ServerConnectionCallbacks& callbacks_; |
567 | | std::unique_ptr<ActiveRequest> active_request_; |
568 | | const Buffer::OwnedBufferFragmentImpl::Releasor response_buffer_releasor_; |
569 | | uint32_t outbound_responses_{}; |
570 | | // Buffer used to encode the HTTP message before moving it to the network connection's output |
571 | | // buffer. This buffer is always allocated, never nullptr. |
572 | | Buffer::InstancePtr owned_output_buffer_; |
573 | | // TODO(mattklein123): This should be a member of ActiveRequest but this change needs dedicated |
574 | | // thought as some of the reset and no header code paths make this difficult. Headers are |
575 | | // populated on message begin. Trailers are populated on the first parsed trailer field (if |
576 | | // trailers are enabled). The variant is reset to null headers on message complete for assertion |
577 | | // purposes. |
578 | | absl::variant<RequestHeaderMapPtr, RequestTrailerMapPtr> headers_or_trailers_; |
579 | | // The action to take when a request header name contains underscore characters. |
580 | | const envoy::config::core::v3::HttpProtocolOptions::HeadersWithUnderscoresAction |
581 | | headers_with_underscores_action_; |
582 | | Server::LoadShedPoint* abort_dispatch_{nullptr}; |
583 | | }; |
584 | | |
585 | | /** |
586 | | * Implementation of Http::ClientConnection for HTTP/1.1. |
587 | | */ |
588 | | class ClientConnectionImpl : public ClientConnection, public ConnectionImpl { |
589 | | public: |
590 | | ClientConnectionImpl(Network::Connection& connection, CodecStats& stats, |
591 | | ConnectionCallbacks& callbacks, const Http1Settings& settings, |
592 | | const uint32_t max_response_headers_count, |
593 | | bool passing_through_proxy = false); |
594 | | // Http::ClientConnection |
595 | | RequestEncoder& newStream(ResponseDecoder& response_decoder) override; |
596 | | |
597 | | private: |
598 | | struct PendingResponse { |
599 | | PendingResponse(ConnectionImpl& connection, StreamInfo::BytesMeterSharedPtr&& bytes_meter, |
600 | | ResponseDecoder* decoder) |
601 | 11.6k | : encoder_(connection, std::move(bytes_meter)), decoder_(decoder) {} |
602 | | RequestEncoderImpl encoder_; |
603 | | ResponseDecoder* decoder_; |
604 | | }; |
605 | | |
606 | | bool cannotHaveBody(); |
607 | | |
608 | 11.4k | bool sendFullyQualifiedUrl() const override { |
609 | | // Send fully qualified URLs either if the parent connection is configured to do so or this |
610 | | // stream is passing through a proxy and the underlying transport is plaintext. |
611 | 11.4k | return ConnectionImpl::sendFullyQualifiedUrl() || |
612 | 11.4k | (passing_through_proxy_ && !connection().ssl()); |
613 | 11.4k | } |
614 | | |
615 | | // ParserCallbacks. |
616 | 0 | Status onUrlBase(const char*, size_t) override { return okStatus(); } |
617 | | Status onStatusBase(const char* data, size_t length) override; |
618 | | // ConnectionImpl |
619 | | Http::Status dispatch(Buffer::Instance& data) override; |
620 | 6.24k | void onEncodeComplete() override {} |
621 | 136k | StreamInfo::BytesMeter& getBytesMeter() override { |
622 | 136k | if (pending_response_.has_value()) { |
623 | 96.6k | return *(pending_response_->encoder_.getStream().bytesMeter()); |
624 | 96.6k | } |
625 | 39.3k | if (bytes_meter_before_stream_ == nullptr) { |
626 | 18.5k | bytes_meter_before_stream_ = std::make_shared<StreamInfo::BytesMeter>(); |
627 | 18.5k | } |
628 | 39.3k | return *bytes_meter_before_stream_; |
629 | 136k | } |
630 | 14.4k | Status onMessageBeginBase() override { return okStatus(); } |
631 | | Envoy::StatusOr<CallbackResult> onHeadersCompleteBase() override; |
632 | | bool upgradeAllowed() const override; |
633 | | void onBody(Buffer::Instance& data) override; |
634 | | CallbackResult onMessageCompleteBase() override; |
635 | | void onResetStream(StreamResetReason reason) override; |
636 | | Status sendProtocolError(absl::string_view details) override; |
637 | | void onAboveHighWatermark() override; |
638 | | void onBelowLowWatermark() override; |
639 | 105k | HeaderMap& headersOrTrailers() override { |
640 | 105k | if (absl::holds_alternative<ResponseHeaderMapPtr>(headers_or_trailers_)) { |
641 | 105k | return *absl::get<ResponseHeaderMapPtr>(headers_or_trailers_); |
642 | 105k | } else { |
643 | 0 | return *absl::get<ResponseTrailerMapPtr>(headers_or_trailers_); |
644 | 0 | } |
645 | 105k | } |
646 | 11.9k | RequestOrResponseHeaderMap& requestOrResponseHeaders() override { |
647 | 11.9k | return *absl::get<ResponseHeaderMapPtr>(headers_or_trailers_); |
648 | 11.9k | } |
649 | 14.4k | void allocHeaders(StatefulHeaderKeyFormatterPtr&& formatter) override { |
650 | 14.4k | ASSERT(nullptr == absl::get<ResponseHeaderMapPtr>(headers_or_trailers_)); |
651 | 14.4k | ASSERT(!processing_trailers_); |
652 | 14.4k | auto headers = ResponseHeaderMapImpl::create(max_headers_kb_, max_headers_count_); |
653 | 14.4k | headers->setFormatter(std::move(formatter)); |
654 | 14.4k | headers_or_trailers_.emplace<ResponseHeaderMapPtr>(std::move(headers)); |
655 | 14.4k | } |
656 | 0 | void allocTrailers() override { |
657 | 0 | ASSERT(processing_trailers_); |
658 | 0 | if (!absl::holds_alternative<ResponseTrailerMapPtr>(headers_or_trailers_)) { |
659 | 0 | headers_or_trailers_.emplace<ResponseTrailerMapPtr>( |
660 | 0 | ResponseTrailerMapImpl::create(max_headers_kb_, max_headers_count_)); |
661 | 0 | } |
662 | 0 | } |
663 | | void dumpAdditionalState(std::ostream& os, int indent_level) const override; |
664 | | |
665 | | // Buffer used to encode the HTTP message before moving it to the network connection's output |
666 | | // buffer. This buffer is always allocated, never nullptr. |
667 | | Buffer::InstancePtr owned_output_buffer_; |
668 | | |
669 | | absl::optional<PendingResponse> pending_response_; |
670 | | // TODO(mattklein123): The following bool tracks whether a pending response is complete before |
671 | | // dispatching callbacks. This is needed so that pending_response_ stays valid during callbacks |
672 | | // in order to access the stream, but to avoid invoking callbacks that shouldn't be called once |
673 | | // the response is complete. The existence of this variable is hard to reason about and it should |
674 | | // be combined with pending_response_ somehow in a follow up cleanup. |
675 | | bool pending_response_done_{true}; |
676 | | // Set true between receiving non-101 1xx headers and receiving the spurious onMessageComplete. |
677 | | bool ignore_message_complete_for_1xx_{}; |
678 | | // TODO(mattklein123): This should be a member of PendingResponse but this change needs dedicated |
679 | | // thought as some of the reset and no header code paths make this difficult. Headers are |
680 | | // populated on message begin. Trailers are populated when the switch to trailer processing is |
681 | | // detected while parsing the first trailer field (if trailers are enabled). The variant is reset |
682 | | // to null headers on message complete for assertion purposes. |
683 | | absl::variant<ResponseHeaderMapPtr, ResponseTrailerMapPtr> headers_or_trailers_; |
684 | | |
685 | | // True if the upstream connection is pointed at an HTTP/1.1 proxy, and |
686 | | // plaintext HTTP should be sent with fully qualified URLs. |
687 | | bool passing_through_proxy_ = false; |
688 | | }; |
689 | | |
690 | | } // namespace Http1 |
691 | | } // namespace Http |
692 | | } // namespace Envoy |