Project import generated by Copybara. PiperOrigin-RevId: 237361882 Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h new file mode 100644 index 0000000..00f241e --- /dev/null +++ b/quic/core/http/quic_spdy_session.h
@@ -0,0 +1,283 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_SESSION_H_ +#define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_SESSION_H_ + +#include <cstddef> +#include <memory> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/http/quic_header_list.h" +#include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h" +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h" +#include "net/third_party/quiche/src/quic/core/quic_session.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h" + +namespace quic { + +namespace test { +class QuicSpdySessionPeer; +} // namespace test + +// QuicHpackDebugVisitor gathers data used for understanding HPACK HoL +// dynamics. Specifically, it is to help predict the compression +// penalty of avoiding HoL by chagning how the dynamic table is used. +// In chromium, the concrete instance populates an UMA +// histogram with the data. +class QUIC_EXPORT_PRIVATE QuicHpackDebugVisitor { + public: + QuicHpackDebugVisitor(); + QuicHpackDebugVisitor(const QuicHpackDebugVisitor&) = delete; + QuicHpackDebugVisitor& operator=(const QuicHpackDebugVisitor&) = delete; + + virtual ~QuicHpackDebugVisitor(); + + // For each HPACK indexed representation processed, |elapsed| is + // the time since the corresponding entry was added to the dynamic + // table. + virtual void OnUseEntry(QuicTime::Delta elapsed) = 0; +}; + +// A QUIC session with a headers stream. +class QUIC_EXPORT_PRIVATE QuicSpdySession + : public QuicSession, + public QpackEncoder::DecoderStreamErrorDelegate, + public QpackEncoderStreamSender::Delegate, + public QpackDecoder::EncoderStreamErrorDelegate, + public QpackDecoderStreamSender::Delegate { + public: + // Does not take ownership of |connection| or |visitor|. + QuicSpdySession(QuicConnection* connection, + QuicSession::Visitor* visitor, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions); + QuicSpdySession(const QuicSpdySession&) = delete; + QuicSpdySession& operator=(const QuicSpdySession&) = delete; + + ~QuicSpdySession() override; + + void Initialize() override; + + // QpackEncoder::DecoderStreamErrorDelegate implementation. + void OnDecoderStreamError(QuicStringPiece error_message) override; + + // QpackEncoderStreamSender::Delegate implemenation. + void WriteEncoderStreamData(QuicStringPiece data) override; + + // QpackDecoder::EncoderStreamErrorDelegate implementation. + void OnEncoderStreamError(QuicStringPiece error_message) override; + + // QpackDecoderStreamSender::Delegate implementation. + void WriteDecoderStreamData(QuicStringPiece data) override; + + // Called by |headers_stream_| when headers with a priority have been + // received for a stream. This method will only be called for server streams. + virtual void OnStreamHeadersPriority(QuicStreamId stream_id, + spdy::SpdyPriority priority); + + // Called by |headers_stream_| when headers have been completely received + // for a stream. |fin| will be true if the fin flag was set in the headers + // frame. + virtual void OnStreamHeaderList(QuicStreamId stream_id, + bool fin, + size_t frame_len, + const QuicHeaderList& header_list); + + // Called by |headers_stream_| when push promise headers have been + // completely received. |fin| will be true if the fin flag was set + // in the headers. + virtual void OnPromiseHeaderList(QuicStreamId stream_id, + QuicStreamId promised_stream_id, + size_t frame_len, + const QuicHeaderList& header_list); + + // Called by |headers_stream_| when a PRIORITY frame has been received for a + // stream. This method will only be called for server streams. + virtual void OnPriorityFrame(QuicStreamId stream_id, + spdy::SpdyPriority priority); + + // Sends contents of |iov| to h2_deframer_, returns number of bytes processed. + size_t ProcessHeaderData(const struct iovec& iov); + + // Writes |headers| for the stream |id| to the dedicated headers stream. + // If |fin| is true, then no more data will be sent for the stream |id|. + // If provided, |ack_notifier_delegate| will be registered to be notified when + // we have seen ACKs for all packets resulting from this call. + virtual size_t WriteHeadersOnHeadersStream( + QuicStreamId id, + spdy::SpdyHeaderBlock headers, + bool fin, + spdy::SpdyPriority priority, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + + // Writes a PRIORITY frame the to peer. Returns the size in bytes of the + // resulting PRIORITY frame for QUIC_VERSION_43 and above. Otherwise, does + // nothing and returns 0. + size_t WritePriority(QuicStreamId id, + QuicStreamId parent_stream_id, + int weight, + bool exclusive); + + // Write |headers| for |promised_stream_id| on |original_stream_id| in a + // PUSH_PROMISE frame to peer. + // Return the size, in bytes, of the resulting PUSH_PROMISE frame. + virtual size_t WritePushPromise(QuicStreamId original_stream_id, + QuicStreamId promised_stream_id, + spdy::SpdyHeaderBlock headers); + + // Sends SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame. + size_t SendMaxHeaderListSize(size_t value); + + QpackEncoder* qpack_encoder(); + QpackDecoder* qpack_decoder(); + QuicHeadersStream* headers_stream() { return headers_stream_.get(); } + + bool server_push_enabled() const { return server_push_enabled_; } + + // Called by |QuicHeadersStream::UpdateEnableServerPush()| with + // value from SETTINGS_ENABLE_PUSH. + void set_server_push_enabled(bool enable) { server_push_enabled_ = enable; } + + // Return true if this session wants to release headers stream's buffer + // aggressively. + virtual bool ShouldReleaseHeadersStreamSequencerBuffer(); + + void CloseConnectionWithDetails(QuicErrorCode error, + const QuicString& details); + + void set_max_inbound_header_list_size(size_t max_inbound_header_list_size) { + max_inbound_header_list_size_ = max_inbound_header_list_size; + } + + protected: + // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and + // CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to + // make sure that all data streams are QuicSpdyStreams. + QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override = 0; + QuicSpdyStream* CreateIncomingStream(PendingStream pending) override = 0; + virtual QuicSpdyStream* CreateOutgoingBidirectionalStream() = 0; + virtual QuicSpdyStream* CreateOutgoingUnidirectionalStream() = 0; + + QuicSpdyStream* GetSpdyDataStream(const QuicStreamId stream_id); + + // If an incoming stream can be created, return true. + virtual bool ShouldCreateIncomingStream(QuicStreamId id) = 0; + + // If an outgoing bidirectional/unidirectional stream can be created, return + // true. + virtual bool ShouldCreateOutgoingBidirectionalStream() = 0; + virtual bool ShouldCreateOutgoingUnidirectionalStream() = 0; + + // Returns true if there are open HTTP requests. + bool ShouldKeepConnectionAlive() const override; + + // Overridden to buffer incoming streams for version 99. + bool ShouldBufferIncomingStream(QuicStreamId id) const override; + + size_t WriteHeadersOnHeadersStreamImpl( + QuicStreamId id, + spdy::SpdyHeaderBlock headers, + bool fin, + QuicStreamId parent_stream_id, + int weight, + bool exclusive, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + + void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; + + bool supports_push_promise() { return supports_push_promise_; } + + // Optional, enables instrumentation related to go/quic-hpack. + void SetHpackEncoderDebugVisitor( + std::unique_ptr<QuicHpackDebugVisitor> visitor); + void SetHpackDecoderDebugVisitor( + std::unique_ptr<QuicHpackDebugVisitor> visitor); + + // Sets the maximum size of the header compression table spdy_framer_ is + // willing to use to encode header blocks. + void UpdateHeaderEncoderTableSize(uint32_t value); + + // Called when SETTINGS_ENABLE_PUSH is received, only supported on + // server side. + void UpdateEnableServerPush(bool value); + + bool IsConnected() { return connection()->connected(); } + + // Sets how much encoded data the hpack decoder of h2_deframer_ is willing to + // buffer. + void set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes) { + h2_deframer_.GetHpackDecoder()->set_max_decode_buffer_size_bytes( + max_decode_buffer_size_bytes); + } + + void set_max_uncompressed_header_bytes( + size_t set_max_uncompressed_header_bytes); + + private: + friend class test::QuicSpdySessionPeer; + + class SpdyFramerVisitor; + + // The following methods are called by the SimpleVisitor. + + // Called when a HEADERS frame has been received. + void OnHeaders(spdy::SpdyStreamId stream_id, + bool has_priority, + spdy::SpdyPriority priority, + bool fin); + + // Called when a PUSH_PROMISE frame has been received. + void OnPushPromise(spdy::SpdyStreamId stream_id, + spdy::SpdyStreamId promised_stream_id, + bool end); + + // Called when a PRIORITY frame has been received. + void OnPriority(spdy::SpdyStreamId stream_id, spdy::SpdyPriority priority); + + // Called when the complete list of headers is available. + void OnHeaderList(const QuicHeaderList& header_list); + + // Called when the size of the compressed frame payload is available. + void OnCompressedFrameSize(size_t frame_len); + + std::unique_ptr<QpackEncoder> qpack_encoder_; + std::unique_ptr<QpackDecoder> qpack_decoder_; + + // TODO(123528590): Remove this member. + std::unique_ptr<QuicHeadersStream> headers_stream_; + + // The maximum size of a header block that will be accepted from the peer, + // defined per spec as key + value + overhead per field (uncompressed). + size_t max_inbound_header_list_size_; + + // Set during handshake. If true, resources in x-associated-content and link + // headers will be pushed. + bool server_push_enabled_; + + // Data about the stream whose headers are being processed. + QuicStreamId stream_id_; + QuicStreamId promised_stream_id_; + bool fin_; + size_t frame_len_; + size_t uncompressed_frame_len_; + + bool supports_push_promise_; + + spdy::SpdyFramer spdy_framer_; + http2::Http2DecoderAdapter h2_deframer_; + std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_SESSION_H_