Line data Source code
1 : #pragma once
2 :
3 : #include <cstdint>
4 : #include <functional>
5 : #include <list>
6 : #include <memory>
7 : #include <ostream>
8 : #include <string>
9 : #include <vector>
10 :
11 : #include "envoy/buffer/buffer.h"
12 : #include "envoy/common/random_generator.h"
13 : #include "envoy/common/scope_tracker.h"
14 : #include "envoy/config/core/v3/protocol.pb.h"
15 : #include "envoy/event/deferred_deletable.h"
16 : #include "envoy/http/codec.h"
17 : #include "envoy/network/connection.h"
18 :
19 : #include "source/common/buffer/buffer_impl.h"
20 : #include "source/common/buffer/watermark_buffer.h"
21 : #include "source/common/common/assert.h"
22 : #include "source/common/common/linked_object.h"
23 : #include "source/common/common/logger.h"
24 : #include "source/common/common/statusor.h"
25 : #include "source/common/common/thread.h"
26 : #include "source/common/http/codec_helper.h"
27 : #include "source/common/http/header_map_impl.h"
28 : #include "source/common/http/http2/codec_stats.h"
29 : #include "source/common/http/http2/metadata_decoder.h"
30 : #include "source/common/http/http2/metadata_encoder.h"
31 : #include "source/common/http/http2/protocol_constraints.h"
32 : #include "source/common/http/status.h"
33 : #include "source/common/http/utility.h"
34 :
35 : #include "absl/types/optional.h"
36 : #include "nghttp2/nghttp2.h"
37 : #include "quiche/http2/adapter/http2_adapter.h"
38 : #include "quiche/http2/adapter/oghttp2_adapter.h"
39 :
40 : namespace Envoy {
41 : namespace Http {
42 : namespace Http2 {
43 :
44 : class Http2CodecImplTestFixture;
45 :
46 : // This is not the full client magic, but it's the smallest size that should be able to
47 : // differentiate between HTTP/1 and HTTP/2.
48 : const std::string CLIENT_MAGIC_PREFIX = "PRI * HTTP/2";
49 : constexpr uint64_t H2_FRAME_HEADER_SIZE = 9;
50 :
51 : class ReceivedSettingsImpl : public ReceivedSettings {
52 : public:
53 : explicit ReceivedSettingsImpl(const nghttp2_settings& settings);
54 :
55 : // ReceivedSettings
56 106 : const absl::optional<uint32_t>& maxConcurrentStreams() const override {
57 106 : return concurrent_stream_limit_;
58 106 : }
59 :
60 : private:
61 : absl::optional<uint32_t> concurrent_stream_limit_{};
62 : };
63 :
64 : class Utility {
65 : public:
66 : /**
67 : * Deal with https://tools.ietf.org/html/rfc7540#section-8.1.2.5
68 : * @param key supplies the incoming header key.
69 : * @param value supplies the incoming header value.
70 : * @param cookies supplies the header string to fill if this is a cookie header that needs to be
71 : * rebuilt.
72 : */
73 : static bool reconstituteCrumbledCookies(const HeaderString& key, const HeaderString& value,
74 : HeaderString& cookies);
75 : };
76 :
77 : class ConnectionImpl;
78 :
79 : // Abstract factory. Used to enable injection of factories for testing.
80 : class Http2SessionFactory {
81 : public:
82 : using ConnectionImplType = ConnectionImpl;
83 0 : virtual ~Http2SessionFactory() = default;
84 :
85 : // Returns a new HTTP/2 session to be used with |connection|.
86 : virtual std::unique_ptr<http2::adapter::Http2Adapter>
87 : create(const nghttp2_session_callbacks* callbacks, ConnectionImplType* connection,
88 : const http2::adapter::OgHttp2Adapter::Options& options) PURE;
89 :
90 : // Returns a new HTTP/2 session to be used with |connection|.
91 : virtual std::unique_ptr<http2::adapter::Http2Adapter>
92 : create(const nghttp2_session_callbacks* callbacks, ConnectionImplType* connection,
93 : const nghttp2_option* options) PURE;
94 :
95 : // Initializes the |session|.
96 : virtual void init(ConnectionImplType* connection,
97 : const envoy::config::core::v3::Http2ProtocolOptions& options) PURE;
98 : };
99 :
100 : class ProdNghttp2SessionFactory : public Http2SessionFactory {
101 : public:
102 : std::unique_ptr<http2::adapter::Http2Adapter>
103 : create(const nghttp2_session_callbacks* callbacks, ConnectionImpl* connection,
104 : const http2::adapter::OgHttp2Adapter::Options& options) override;
105 :
106 : std::unique_ptr<http2::adapter::Http2Adapter> create(const nghttp2_session_callbacks* callbacks,
107 : ConnectionImpl* connection,
108 : const nghttp2_option* options) override;
109 :
110 : void init(ConnectionImpl* connection,
111 : const envoy::config::core::v3::Http2ProtocolOptions& options) override;
112 :
113 : // Returns a global factory instance. Note that this is possible because no
114 : // internal state is maintained; the thread safety of create() and init()'s
115 : // side effects is guaranteed by Envoy's worker based threading model.
116 361 : static ProdNghttp2SessionFactory& get() {
117 361 : static ProdNghttp2SessionFactory* instance = new ProdNghttp2SessionFactory();
118 361 : return *instance;
119 361 : }
120 : };
121 :
122 : /**
123 : * Base class for HTTP/2 client and server codecs.
124 : */
125 : class ConnectionImpl : public virtual Connection,
126 : protected Logger::Loggable<Logger::Id::http2>,
127 : public ScopeTrackedObject {
128 : public:
129 : ConnectionImpl(Network::Connection& connection, CodecStats& stats,
130 : Random::RandomGenerator& random_generator,
131 : const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
132 : const uint32_t max_headers_kb, const uint32_t max_headers_count);
133 :
134 : ~ConnectionImpl() override;
135 :
136 : // Http::Connection
137 : // NOTE: the `dispatch` method is also overridden in the ServerConnectionImpl class
138 : Http::Status dispatch(Buffer::Instance& data) override;
139 : void goAway() override;
140 3318 : Protocol protocol() override { return Protocol::Http2; }
141 : void shutdownNotice() override;
142 : Status protocolErrorForTest(); // Used in tests to simulate errors.
143 0 : bool wantsToWrite() override { return adapter_->want_write(); }
144 : // Propagate network connection watermark events to each stream on the connection.
145 0 : void onUnderlyingConnectionAboveWriteBufferHighWatermark() override {
146 0 : for (auto& stream : active_streams_) {
147 0 : stream->runHighWatermarkCallbacks();
148 0 : }
149 0 : }
150 : void onUnderlyingConnectionBelowWriteBufferLowWatermark() override;
151 :
152 361 : void setVisitor(std::unique_ptr<http2::adapter::Http2VisitorInterface> visitor) {
153 361 : visitor_ = std::move(visitor);
154 361 : }
155 :
156 : // ScopeTrackedObject
157 : void dumpState(std::ostream& os, int indent_level) const override;
158 :
159 : protected:
160 : friend class ProdNghttp2SessionFactory;
161 :
162 : /**
163 : * Wrapper for static nghttp2 callback dispatchers.
164 : */
165 : class Http2Callbacks {
166 : public:
167 : Http2Callbacks();
168 : ~Http2Callbacks();
169 :
170 2860 : const nghttp2_session_callbacks* callbacks() { return callbacks_; }
171 :
172 : private:
173 : nghttp2_session_callbacks* callbacks_;
174 : };
175 :
176 : /**
177 : * Wrapper for static nghttp2 session options.
178 : */
179 : class Http2Options {
180 : public:
181 : Http2Options(const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
182 : uint32_t max_headers_kb);
183 : ~Http2Options();
184 :
185 279 : const nghttp2_option* options() { return options_; }
186 2581 : const http2::adapter::OgHttp2Adapter::Options& ogOptions() { return og_options_; }
187 :
188 : protected:
189 : nghttp2_option* options_;
190 : http2::adapter::OgHttp2Adapter::Options og_options_;
191 : };
192 :
193 : class ClientHttp2Options : public Http2Options {
194 : public:
195 : ClientHttp2Options(const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
196 : uint32_t max_headers_kb);
197 : };
198 :
199 : /**
200 : * Base class for client and server side streams.
201 : */
202 : struct StreamImpl : public virtual StreamEncoder,
203 : public LinkedObject<StreamImpl>,
204 : public Event::DeferredDeletable,
205 : public Http::MultiplexedStreamImplBase,
206 : public ScopeTrackedObject {
207 :
208 : StreamImpl(ConnectionImpl& parent, uint32_t buffer_limit);
209 :
210 : // Http::MultiplexedStreamImplBase
211 : void destroy() override;
212 : void onPendingFlushTimer() override;
213 : CodecEventCallbacks*
214 424 : registerCodecEventCallbacks(CodecEventCallbacks* codec_callbacks) override {
215 424 : extend_stream_lifetime_flag_ = true;
216 424 : return MultiplexedStreamImplBase::registerCodecEventCallbacks(codec_callbacks);
217 424 : }
218 :
219 459 : StreamImpl* base() { return this; }
220 : void resetStreamWorker(StreamResetReason reason);
221 : static void buildHeaders(std::vector<nghttp2_nv>& final_headers, const HeaderMap& headers);
222 : static std::vector<http2::adapter::Header> buildHeaders(const HeaderMap& headers);
223 : void saveHeader(HeaderString&& name, HeaderString&& value);
224 : void encodeHeadersBase(const HeaderMap& headers, bool end_stream);
225 : virtual void submitHeaders(const HeaderMap& headers, bool end_stream) PURE;
226 : void encodeTrailersBase(const HeaderMap& headers);
227 : void submitTrailers(const HeaderMap& trailers);
228 : // Returns true if the stream should defer the local reset stream until after the next call to
229 : // sendPendingFrames so pending outbound frames have one final chance to be flushed. If we
230 : // submit a reset, nghttp2 will cancel outbound frames that have not yet been sent.
231 : virtual bool useDeferredReset() const PURE;
232 : virtual StreamDecoder& decoder() PURE;
233 : virtual HeaderMap& headers() PURE;
234 : virtual void allocTrailers() PURE;
235 : virtual HeaderMapPtr cloneTrailers(const HeaderMap& trailers) PURE;
236 :
237 : // Http::StreamEncoder
238 : void encodeData(Buffer::Instance& data, bool end_stream) override;
239 4947 : Stream& getStream() override { return *this; }
240 : void encodeMetadata(const MetadataMapVector& metadata_map_vector) override;
241 0 : Http1StreamEncoderOptionsOptRef http1StreamEncoderOptions() override { return absl::nullopt; }
242 :
243 : // Http::Stream
244 2102 : void addCallbacks(StreamCallbacks& callbacks) override { addCallbacksHelper(callbacks); }
245 394 : void removeCallbacks(StreamCallbacks& callbacks) override { removeCallbacksHelper(callbacks); }
246 : void resetStream(StreamResetReason reason) override;
247 : void readDisable(bool disable) override;
248 212 : uint32_t bufferLimit() const override { return pending_recv_data_->highWatermark(); }
249 148 : const Network::ConnectionInfoProvider& connectionInfoProvider() override {
250 148 : return parent_.connection_.connectionInfoProvider();
251 148 : }
252 138 : absl::string_view responseDetails() override { return details_; }
253 212 : Buffer::BufferMemoryAccountSharedPtr account() const override { return buffer_memory_account_; }
254 : void setAccount(Buffer::BufferMemoryAccountSharedPtr account) override;
255 :
256 : // ScopeTrackedObject
257 : void dumpState(std::ostream& os, int indent_level) const override;
258 :
259 : // This code assumes that details is a static string, so that we
260 : // can avoid copying it.
261 206 : void setDetails(absl::string_view details) {
262 : // TODO(asraa): In some cases nghttp2's error handling may cause processing of multiple
263 : // invalid frames for a single stream. If a temporal stream error is returned from a callback,
264 : // remaining frames in the buffer will still be partially processed. For example, remaining
265 : // frames will still parse through nghttp2's push promise error handling and in
266 : // onBeforeFrame(Send/Received) callbacks, which may return invalid frame errors and attempt
267 : // to set details again. In these cases, we simply do not overwrite details. When internal
268 : // error latching is implemented in the codec for exception removal, we should prevent calling
269 : // setDetails in an error state.
270 206 : if (details_.empty()) {
271 203 : details_ = details;
272 203 : }
273 206 : }
274 :
275 1974 : void setWriteBufferWatermarks(uint32_t high_watermark) {
276 1974 : pending_recv_data_->setWatermarks(high_watermark);
277 1974 : pending_send_data_->setWatermarks(high_watermark);
278 1974 : }
279 :
280 : // If the receive buffer encounters watermark callbacks, enable/disable reads on this stream.
281 : void pendingRecvBufferHighWatermark();
282 : void pendingRecvBufferLowWatermark();
283 :
284 : // If the send buffer encounters watermark callbacks, propagate this information to the streams.
285 : // The router and connection manager will propagate them on as appropriate.
286 : void pendingSendBufferHighWatermark();
287 : void pendingSendBufferLowWatermark();
288 :
289 : // Does any necessary WebSocket/Upgrade conversion, then passes the headers
290 : // to the decoder_.
291 : virtual void decodeHeaders() PURE;
292 : virtual void decodeTrailers() PURE;
293 : bool maybeDeferDecodeTrailers();
294 : // Consumes any decoded data, buffering if backed up.
295 : void decodeData();
296 :
297 : // Get MetadataEncoder for this stream.
298 : NewMetadataEncoder& getMetadataEncoder();
299 : // Get MetadataDecoder for this stream.
300 : MetadataDecoder& getMetadataDecoder();
301 : // Callback function for MetadataDecoder.
302 : void onMetadataDecoded(MetadataMapPtr&& metadata_map_ptr);
303 :
304 61182 : bool buffersOverrun() const { return read_disable_count_ > 0; }
305 38910 : bool shouldAllowPeerAdditionalStreamWindow() const {
306 38911 : return !buffersOverrun() && !pending_recv_data_->highWatermarkTriggered();
307 38910 : }
308 :
309 : void encodeDataHelper(Buffer::Instance& data, bool end_stream,
310 : bool skip_encoding_empty_trailers);
311 : // Called from either process_buffered_data_callback_.
312 : void processBufferedData();
313 :
314 : // Called when the frame with END_STREAM is sent for this stream.
315 467 : void onEndStreamEncoded() {
316 467 : if (codec_callbacks_) {
317 153 : codec_callbacks_->onCodecEncodeComplete();
318 153 : }
319 467 : }
320 :
321 360 : const StreamInfo::BytesMeterSharedPtr& bytesMeter() override { return bytes_meter_; }
322 : ConnectionImpl& parent_;
323 : int32_t stream_id_{-1};
324 : uint32_t unconsumed_bytes_{0};
325 : uint32_t read_disable_count_{0};
326 : StreamInfo::BytesMeterSharedPtr bytes_meter_{std::make_shared<StreamInfo::BytesMeter>()};
327 :
328 : Buffer::BufferMemoryAccountSharedPtr buffer_memory_account_;
329 : // Note that in current implementation the watermark callbacks of the pending_recv_data_ are
330 : // never called. The watermark value is set to the size of the stream window. As a result this
331 : // watermark can never overflow because the peer can never send more bytes than the stream
332 : // window without triggering protocol error. This buffer is drained after each DATA frame was
333 : // dispatched through the filter chain unless
334 : // envoy.reloadable_features.defer_processing_backedup_streams is enabled,
335 : // in which case this buffer may accumulate data.
336 : // See source/docs/flow_control.md for more information.
337 : Buffer::InstancePtr pending_recv_data_;
338 : Buffer::InstancePtr pending_send_data_;
339 : HeaderMapPtr pending_trailers_to_encode_;
340 : std::unique_ptr<MetadataDecoder> metadata_decoder_;
341 : std::unique_ptr<NewMetadataEncoder> metadata_encoder_;
342 : absl::optional<StreamResetReason> deferred_reset_;
343 : // Holds the reset reason for this stream. Useful if we have buffered data
344 : // to determine whether we should continue processing that data.
345 : absl::optional<StreamResetReason> reset_reason_;
346 : HeaderString cookies_;
347 : bool local_end_stream_sent_ : 1;
348 : bool remote_end_stream_ : 1;
349 : bool remote_rst_ : 1;
350 : bool data_deferred_ : 1;
351 : bool received_noninformational_headers_ : 1;
352 : bool pending_receive_buffer_high_watermark_called_ : 1;
353 : bool pending_send_buffer_high_watermark_called_ : 1;
354 : bool reset_due_to_messaging_error_ : 1;
355 : bool defer_processing_backedup_streams_ : 1;
356 : // Latch whether this stream is operating with this flag.
357 : bool extend_stream_lifetime_flag_ : 1;
358 : absl::string_view details_;
359 :
360 : /**
361 : * Tracks buffering that may occur for a stream if it is backed up.
362 : */
363 : struct BufferedStreamManager {
364 : bool body_buffered_{false};
365 : bool trailers_buffered_{false};
366 :
367 : // We received a call to onStreamClose for the stream, but deferred it
368 : // as the stream had pending data to process and the stream was not reset.
369 : bool buffered_on_stream_close_{false};
370 :
371 : // Segment size for processing body data. Defaults to the value of high
372 : // watermark of the *pending_recv_data_* buffer.
373 : // If 0, we will process all buffered data.
374 : uint32_t defer_processing_segment_size_{0};
375 :
376 22169 : bool decodeAsChunks() const { return defer_processing_segment_size_ > 0; }
377 352 : bool hasBufferedBodyOrTrailers() const { return body_buffered_ || trailers_buffered_; }
378 : };
379 :
380 : BufferedStreamManager stream_manager_;
381 : Event::SchedulableCallbackPtr process_buffered_data_callback_;
382 :
383 : protected:
384 : // Http::MultiplexedStreamImplBase
385 267 : bool hasPendingData() override {
386 267 : return pending_send_data_->length() > 0 || pending_trailers_to_encode_ != nullptr;
387 267 : }
388 16 : bool continueProcessingBufferedData() const {
389 : // We should stop processing buffered data if either
390 : // 1) Buffers become overrun
391 : // 2) The stream ends up getting reset
392 : // Both of these can end up changing as a result of processing buffered data.
393 16 : return !buffersOverrun() && !reset_reason_.has_value();
394 16 : }
395 :
396 : // Avoid inversion in the case where we saw trailers, acquiring the
397 : // remote_end_stream_ being set to true, but the trailers ended up being
398 : // buffered.
399 : // All buffered body must be consumed before we send end stream.
400 22659 : bool sendEndStream() const {
401 22659 : return remote_end_stream_ && !stream_manager_.trailers_buffered_ &&
402 22659 : !stream_manager_.body_buffered_;
403 22659 : }
404 :
405 : // Schedules a callback either in the current or next iteration to process
406 : // buffered data.
407 : void scheduleProcessingOfBufferedData(bool schedule_next_iteration);
408 :
409 : // Marks data consumed by the stream, granting the peer additional stream
410 : // window.
411 : void grantPeerAdditionalStreamWindow();
412 : };
413 :
414 : // Encapsulates the logic for sending DATA frames on a given stream.
415 : class StreamDataFrameSource : public http2::adapter::DataFrameSource {
416 : public:
417 513 : explicit StreamDataFrameSource(StreamImpl& stream) : stream_(stream) {}
418 :
419 : // Returns a pair of the next payload length, and whether that payload is the end of the data
420 : // for this stream.
421 : std::pair<int64_t, bool> SelectPayloadLength(size_t max_length) override;
422 : // Queues the frame header and a DATA frame payload of the specified length for writing.
423 : bool Send(absl::string_view frame_header, size_t payload_length) override;
424 : // Whether the codec should send the END_STREAM flag on the final DATA frame.
425 10977 : bool send_fin() const override { return send_fin_; }
426 :
427 : private:
428 : StreamImpl& stream_;
429 : bool send_fin_ = false;
430 : };
431 :
432 : using StreamImplPtr = std::unique_ptr<StreamImpl>;
433 :
434 : /**
435 : * Client side stream (request).
436 : */
437 : struct ClientStreamImpl : public StreamImpl, public RequestEncoder {
438 : ClientStreamImpl(ConnectionImpl& parent, uint32_t buffer_limit,
439 : ResponseDecoder& response_decoder)
440 : : StreamImpl(parent, buffer_limit), response_decoder_(response_decoder),
441 : headers_or_trailers_(
442 475 : ResponseHeaderMapImpl::create(parent_.max_headers_kb_, parent_.max_headers_count_)) {}
443 :
444 : // Http::MultiplexedStreamImplBase
445 : // Client streams do not need a flush timer because we currently assume that any failure
446 : // to flush would be covered by a request/stream/etc. timeout.
447 0 : void setFlushTimeout(std::chrono::milliseconds /*timeout*/) override {}
448 0 : CodecEventCallbacks* registerCodecEventCallbacks(CodecEventCallbacks*) override {
449 0 : ENVOY_BUG(false, "CodecEventCallbacks for HTTP2 client stream unimplemented.");
450 0 : return nullptr;
451 0 : }
452 : // StreamImpl
453 : void submitHeaders(const HeaderMap& headers, bool end_stream) override;
454 : // Do not use deferred reset on upstream connections.
455 121 : bool useDeferredReset() const override { return false; }
456 439 : StreamDecoder& decoder() override { return response_decoder_; }
457 : void decodeHeaders() override;
458 : void decodeTrailers() override;
459 43818 : HeaderMap& headers() override {
460 43818 : if (absl::holds_alternative<ResponseHeaderMapPtr>(headers_or_trailers_)) {
461 43788 : return *absl::get<ResponseHeaderMapPtr>(headers_or_trailers_);
462 43788 : } else {
463 30 : return *absl::get<ResponseTrailerMapPtr>(headers_or_trailers_);
464 30 : }
465 43818 : }
466 14 : void allocTrailers() override {
467 : // If we are waiting for informational headers, make a new response header map, otherwise
468 : // we are about to receive trailers. The codec makes sure this is the only valid sequence.
469 14 : if (received_noninformational_headers_) {
470 10 : headers_or_trailers_.emplace<ResponseTrailerMapPtr>(
471 10 : ResponseTrailerMapImpl::create(parent_.max_headers_kb_, parent_.max_headers_count_));
472 10 : } else {
473 4 : headers_or_trailers_.emplace<ResponseHeaderMapPtr>(
474 4 : ResponseHeaderMapImpl::create(parent_.max_headers_kb_, parent_.max_headers_count_));
475 4 : }
476 14 : }
477 0 : HeaderMapPtr cloneTrailers(const HeaderMap& trailers) override {
478 0 : return createHeaderMap<RequestTrailerMapImpl>(trailers);
479 0 : }
480 :
481 : // RequestEncoder
482 : Status encodeHeaders(const RequestHeaderMap& headers, bool end_stream) override;
483 14 : void encodeTrailers(const RequestTrailerMap& trailers) override {
484 14 : encodeTrailersBase(trailers);
485 14 : }
486 0 : void enableTcpTunneling() override {}
487 :
488 : // ScopeTrackedObject
489 : void dumpState(std::ostream& os, int indent_level) const override;
490 :
491 : ResponseDecoder& response_decoder_;
492 : absl::variant<ResponseHeaderMapPtr, ResponseTrailerMapPtr> headers_or_trailers_;
493 : std::string upgrade_type_;
494 : };
495 :
496 : using ClientStreamImplPtr = std::unique_ptr<ClientStreamImpl>;
497 :
498 : /**
499 : * Server side stream (response).
500 : */
501 : struct ServerStreamImpl : public StreamImpl, public ResponseEncoder {
502 : ServerStreamImpl(ConnectionImpl& parent, uint32_t buffer_limit)
503 : : StreamImpl(parent, buffer_limit),
504 : headers_or_trailers_(
505 1499 : RequestHeaderMapImpl::create(parent_.max_headers_kb_, parent_.max_headers_count_)) {}
506 :
507 : // StreamImpl
508 : void destroy() override;
509 : void submitHeaders(const HeaderMap& headers, bool end_stream) override;
510 : // Enable deferred reset on downstream connections so outbound HTTP internal error replies are
511 : // written out before force resetting the stream, assuming there is enough H2 connection flow
512 : // control window is available.
513 15 : bool useDeferredReset() const override { return true; }
514 21738 : StreamDecoder& decoder() override { return *request_decoder_; }
515 : void decodeHeaders() override;
516 : void decodeTrailers() override;
517 12235 : HeaderMap& headers() override {
518 12235 : if (absl::holds_alternative<RequestHeaderMapSharedPtr>(headers_or_trailers_)) {
519 12139 : return *absl::get<RequestHeaderMapSharedPtr>(headers_or_trailers_);
520 12139 : } else {
521 96 : return *absl::get<RequestTrailerMapPtr>(headers_or_trailers_);
522 96 : }
523 12235 : }
524 16 : void allocTrailers() override {
525 16 : headers_or_trailers_.emplace<RequestTrailerMapPtr>(
526 16 : RequestTrailerMapImpl::create(parent_.max_headers_kb_, parent_.max_headers_count_));
527 16 : }
528 0 : HeaderMapPtr cloneTrailers(const HeaderMap& trailers) override {
529 0 : return createHeaderMap<ResponseTrailerMapImpl>(trailers);
530 0 : }
531 : void resetStream(StreamResetReason reason) override;
532 :
533 : // ResponseEncoder
534 : void encode1xxHeaders(const ResponseHeaderMap& headers) override;
535 : void encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) override;
536 44 : void encodeTrailers(const ResponseTrailerMap& trailers) override {
537 44 : encodeTrailersBase(trailers);
538 44 : }
539 1499 : void setRequestDecoder(Http::RequestDecoder& decoder) override { request_decoder_ = &decoder; }
540 : void setDeferredLoggingHeadersAndTrailers(Http::RequestHeaderMapConstSharedPtr,
541 : Http::ResponseHeaderMapConstSharedPtr,
542 : Http::ResponseTrailerMapConstSharedPtr,
543 0 : StreamInfo::StreamInfo&) override {}
544 :
545 : // ScopeTrackedObject
546 : void dumpState(std::ostream& os, int indent_level) const override;
547 :
548 : absl::variant<RequestHeaderMapSharedPtr, RequestTrailerMapPtr> headers_or_trailers_;
549 :
550 0 : bool streamErrorOnInvalidHttpMessage() const override {
551 0 : return parent_.stream_error_on_invalid_http_messaging_;
552 0 : }
553 :
554 : private:
555 : RequestDecoder* request_decoder_{};
556 : };
557 :
558 : using ServerStreamImplPtr = std::unique_ptr<ServerStreamImpl>;
559 :
560 3221 : ConnectionImpl* base() { return this; }
561 : // NOTE: Always use non debug nullptr checks against the return value of this function. There are
562 : // edge cases (such as for METADATA frames) where nghttp2 will issue a callback for a stream_id
563 : // that is not associated with an existing stream.
564 : const StreamImpl* getStream(int32_t stream_id) const;
565 : StreamImpl* getStream(int32_t stream_id);
566 : // Same as getStream, but without the ASSERT.
567 : const StreamImpl* getStreamUnchecked(int32_t stream_id) const;
568 : StreamImpl* getStreamUnchecked(int32_t stream_id);
569 : int saveHeader(const nghttp2_frame* frame, HeaderString&& name, HeaderString&& value);
570 :
571 : /**
572 : * Copies any frames pending internally by nghttp2 into outbound buffer.
573 : * The `sendPendingFrames()` can be called in 3 different contexts:
574 : * 1. dispatching_ == true, aka the dispatching context. The `sendPendingFrames()` is no-op and
575 : * always returns success to avoid reentering nghttp2 library.
576 : * 2. Server codec only. dispatching_ == false.
577 : * The `sendPendingFrames()` returns the status of the protocol constraint checks. Outbound
578 : * frame accounting is performed.
579 : * 3. dispatching_ == false. The `sendPendingFrames()` always returns success. No outbound
580 : * frame accounting.
581 : *
582 : * TODO(yanavlasov): harmonize behavior for cases 2, 3.
583 : */
584 : Status sendPendingFrames();
585 :
586 : /**
587 : * Call the sendPendingFrames() method and schedule disconnect callback when
588 : * sendPendingFrames() returns an error.
589 : * Return true if the disconnect callback has been scheduled.
590 : */
591 : bool sendPendingFramesAndHandleError();
592 : void sendSettings(const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
593 : bool disable_push);
594 : void sendSettingsHelper(const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
595 : bool disable_push);
596 : void sendSettingsHelperOld(const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
597 : bool disable_push);
598 : // Callback triggered when the peer's SETTINGS frame is received.
599 903 : virtual void onSettings(const nghttp2_settings& settings) {
600 903 : ReceivedSettingsImpl received_settings(settings);
601 903 : callbacks().onSettings(received_settings);
602 903 : }
603 :
604 : /**
605 : * Check if header name contains underscore character.
606 : * Underscore character is allowed in header names by the RFC-7230 and this check is implemented
607 : * as a security measure due to systems that treat '_' and '-' as interchangeable.
608 : * The ServerConnectionImpl may drop header or reject request based on the
609 : * `common_http_protocol_options.headers_with_underscores_action` configuration option in the
610 : * HttpConnectionManager.
611 : */
612 20847 : virtual absl::optional<int> checkHeaderNameForUnderscores(absl::string_view /* header_name */) {
613 20847 : return absl::nullopt;
614 20847 : }
615 :
616 : /**
617 : * Save `status` into codec_callback_status_.
618 : * Return codec callback return code corresponding to `status`.
619 : */
620 : int setAndCheckCodecCallbackStatus(Status&& status);
621 :
622 : /**
623 : * Callback for terminating connection when protocol constrain has been violated
624 : * outside of the dispatch context.
625 : */
626 : void scheduleProtocolConstraintViolationCallback();
627 : void onProtocolConstraintViolation();
628 :
629 : // Whether to use the new HTTP/2 library.
630 : bool use_oghttp2_library_;
631 : static Http2Callbacks http2_callbacks_;
632 :
633 : // If deferred processing, the streams will be in LRU order based on when the
634 : // stream encoded to the http2 connection. The LRU property is used when
635 : // raising low watermark on the http2 connection to prioritize how streams get
636 : // notified, prefering those that haven't recently written.
637 : std::list<StreamImplPtr> active_streams_;
638 :
639 : // Tracks the stream id of the current stream we're processing.
640 : // This should only be set while we're in the context of dispatching to nghttp2.
641 : absl::optional<int32_t> current_stream_id_;
642 : std::unique_ptr<http2::adapter::Http2VisitorInterface> visitor_;
643 : std::unique_ptr<http2::adapter::Http2Adapter> adapter_;
644 :
645 : CodecStats& stats_;
646 : Network::Connection& connection_;
647 : const uint32_t max_headers_kb_;
648 : const uint32_t max_headers_count_;
649 : uint32_t per_stream_buffer_limit_;
650 : bool allow_metadata_;
651 : const bool stream_error_on_invalid_http_messaging_;
652 :
653 : // Status for any errors encountered by the nghttp2 callbacks.
654 : // nghttp2 library uses single return code to indicate callback failure and
655 : // `codec_callback_status_` is used to save right error information returned by a callback. The
656 : // `codec_callback_status_` is valid iff nghttp call returned NGHTTP2_ERR_CALLBACK_FAILURE.
657 : Status codec_callback_status_;
658 :
659 : // Set if the type of frame that is about to be sent is PING or SETTINGS with the ACK flag set, or
660 : // RST_STREAM.
661 : bool is_outbound_flood_monitored_control_frame_ = 0;
662 : ProtocolConstraints protocol_constraints_;
663 :
664 : // For the flood mitigation to work the onSend callback must be called once for each outbound
665 : // frame. This is what the nghttp2 library is doing, however this is not documented. The
666 : // Http2FloodMitigationTest.* tests in test/integration/http2_integration_test.cc will break if
667 : // this changes in the future. Also it is important that onSend does not do partial writes, as the
668 : // nghttp2 library will keep calling this callback to write the rest of the frame.
669 : ssize_t onSend(const uint8_t* data, size_t length);
670 :
671 : // Called when a stream encodes to the http2 connection which enables us to
672 : // keep the active_streams list in LRU if deferred processing.
673 2198 : void updateActiveStreamsOnEncode(StreamImpl& stream) {
674 2198 : if (stream.defer_processing_backedup_streams_) {
675 2198 : LinkedList::moveIntoList(stream.removeFromList(active_streams_), active_streams_);
676 2198 : }
677 2198 : }
678 :
679 : // dumpState helper method.
680 : virtual void dumpStreams(std::ostream& os, int indent_level) const;
681 :
682 : // Send a keepalive ping, and set the idle timer for ping timeout.
683 : void sendKeepalive();
684 :
685 0 : const MonotonicTime& lastReceivedDataTime() { return last_received_data_time_; }
686 :
687 : private:
688 : friend class Http2CodecImplTestFixture;
689 :
690 : virtual ConnectionCallbacks& callbacks() PURE;
691 : virtual Status onBeginHeaders(const nghttp2_frame* frame) PURE;
692 : int onData(int32_t stream_id, const uint8_t* data, size_t len);
693 : Status onBeforeFrameReceived(int32_t stream_id, size_t length, uint8_t type, uint8_t flags);
694 : Status onFrameReceived(const nghttp2_frame* frame);
695 : int onBeforeFrameSend(int32_t stream_id, size_t length, uint8_t type, uint8_t flags);
696 : int onFrameSend(int32_t stream_id, size_t length, uint8_t type, uint8_t flags,
697 : uint32_t error_code);
698 : int onError(absl::string_view error);
699 : virtual int onHeader(const nghttp2_frame* frame, HeaderString&& name, HeaderString&& value) PURE;
700 : int onInvalidFrame(int32_t stream_id, int error_code);
701 : // Pass through invoking with the actual stream.
702 : Status onStreamClose(int32_t stream_id, uint32_t error_code);
703 : // Should be invoked directly in buffered onStreamClose scenarios
704 : // where nghttp2 might have already forgotten about the stream.
705 : Status onStreamClose(StreamImpl* stream, uint32_t error_code);
706 : int onMetadataReceived(int32_t stream_id, const uint8_t* data, size_t len);
707 : int onMetadataFrameComplete(int32_t stream_id, bool end_metadata);
708 :
709 : // Adds buffer fragment for a new outbound frame to the supplied Buffer::OwnedImpl.
710 : void addOutboundFrameFragment(Buffer::OwnedImpl& output, const uint8_t* data, size_t length);
711 : virtual Status trackInboundFrames(int32_t stream_id, size_t length, uint8_t type, uint8_t flags,
712 : uint32_t padding_length) PURE;
713 : void onKeepaliveResponse();
714 : void onKeepaliveResponseTimeout();
715 : bool slowContainsStreamId(int32_t stream_id) const;
716 : virtual StreamResetReason getMessagingErrorResetReason() const PURE;
717 :
718 : // Tracks the current slice we're processing in the dispatch loop.
719 : const Buffer::RawSlice* current_slice_ = nullptr;
720 : // Streams that are pending deferred reset. Using an ordered map provides determinism in the rare
721 : // case where there are multiple streams waiting for deferred reset. The stream id is also used to
722 : // remove streams from the map when they are closed in order to avoid calls to resetStreamWorker
723 : // after the stream has been removed from the active list.
724 : std::map<int32_t, StreamImpl*> pending_deferred_reset_streams_;
725 : bool dispatching_ : 1;
726 : bool raised_goaway_ : 1;
727 : Event::SchedulableCallbackPtr protocol_constraint_violation_callback_;
728 : Random::RandomGenerator& random_;
729 : MonotonicTime last_received_data_time_{};
730 : Event::TimerPtr keepalive_send_timer_;
731 : Event::TimerPtr keepalive_timeout_timer_;
732 : std::chrono::milliseconds keepalive_interval_;
733 : std::chrono::milliseconds keepalive_timeout_;
734 : uint32_t keepalive_interval_jitter_percent_;
735 : };
736 :
737 : /**
738 : * HTTP/2 client connection codec.
739 : */
740 : class ClientConnectionImpl : public ClientConnection, public ConnectionImpl {
741 : public:
742 : using SessionFactory = Http2SessionFactory;
743 : ClientConnectionImpl(Network::Connection& connection, ConnectionCallbacks& callbacks,
744 : CodecStats& stats, Random::RandomGenerator& random_generator,
745 : const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
746 : const uint32_t max_response_headers_kb,
747 : const uint32_t max_response_headers_count,
748 : SessionFactory& http2_session_factory);
749 :
750 : // Http::ClientConnection
751 : RequestEncoder& newStream(ResponseDecoder& response_decoder) override;
752 :
753 : private:
754 : // ConnectionImpl
755 155 : ConnectionCallbacks& callbacks() override { return callbacks_; }
756 : Status onBeginHeaders(const nghttp2_frame* frame) override;
757 : int onHeader(const nghttp2_frame* frame, HeaderString&& name, HeaderString&& value) override;
758 : Status trackInboundFrames(int32_t stream_id, size_t length, uint8_t type, uint8_t flags,
759 : uint32_t) override;
760 : void dumpStreams(std::ostream& os, int indent_level) const override;
761 : StreamResetReason getMessagingErrorResetReason() const override;
762 : Http::ConnectionCallbacks& callbacks_;
763 : std::chrono::milliseconds idle_session_requires_ping_interval_;
764 : };
765 :
766 : /**
767 : * HTTP/2 server connection codec.
768 : */
769 : class ServerConnectionImpl : public ServerConnection, public ConnectionImpl {
770 : public:
771 : ServerConnectionImpl(Network::Connection& connection, ServerConnectionCallbacks& callbacks,
772 : CodecStats& stats, Random::RandomGenerator& random_generator,
773 : const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
774 : const uint32_t max_request_headers_kb,
775 : const uint32_t max_request_headers_count,
776 : envoy::config::core::v3::HttpProtocolOptions::HeadersWithUnderscoresAction
777 : headers_with_underscores_action,
778 : Server::OverloadManager& overload_manager);
779 :
780 : private:
781 : // ConnectionImpl
782 763 : ConnectionCallbacks& callbacks() override { return callbacks_; }
783 : Status onBeginHeaders(const nghttp2_frame* frame) override;
784 : int onHeader(const nghttp2_frame* frame, HeaderString&& name, HeaderString&& value) override;
785 : Status trackInboundFrames(int32_t stream_id, size_t length, uint8_t type, uint8_t flags,
786 : uint32_t padding_length) override;
787 : absl::optional<int> checkHeaderNameForUnderscores(absl::string_view header_name) override;
788 0 : StreamResetReason getMessagingErrorResetReason() const override {
789 0 : return StreamResetReason::LocalReset;
790 0 : }
791 :
792 : // Http::Connection
793 : // The reason for overriding the dispatch method is to do flood mitigation only when
794 : // processing data from downstream client. Doing flood mitigation when processing upstream
795 : // responses makes clean-up tricky, which needs to be improved (see comments for the
796 : // ClientConnectionImpl::checkProtocolConstraintsStatus method). The dispatch method on the
797 : // ServerConnectionImpl objects is called only when processing data from the downstream client in
798 : // the ConnectionManagerImpl::onData method.
799 : Http::Status dispatch(Buffer::Instance& data) override;
800 :
801 : ServerConnectionCallbacks& callbacks_;
802 :
803 : // The action to take when a request header name contains underscore characters.
804 : envoy::config::core::v3::HttpProtocolOptions::HeadersWithUnderscoresAction
805 : headers_with_underscores_action_;
806 : Server::LoadShedPoint* should_send_go_away_on_dispatch_{nullptr};
807 : bool sent_go_away_on_dispatch_{false};
808 : };
809 :
810 : } // namespace Http2
811 : } // namespace Http
812 : } // namespace Envoy
|