summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quiche/http2/adapter/oghttp2_session.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/third_party/quiche/src/quiche/http2/adapter/oghttp2_session.h')
-rw-r--r--chromium/net/third_party/quiche/src/quiche/http2/adapter/oghttp2_session.h549
1 files changed, 549 insertions, 0 deletions
diff --git a/chromium/net/third_party/quiche/src/quiche/http2/adapter/oghttp2_session.h b/chromium/net/third_party/quiche/src/quiche/http2/adapter/oghttp2_session.h
new file mode 100644
index 00000000000..8757f0923ec
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quiche/http2/adapter/oghttp2_session.h
@@ -0,0 +1,549 @@
+#ifndef QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_
+#define QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_
+
+#include <cstdint>
+#include <limits>
+#include <list>
+#include <memory>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "absl/types/variant.h"
+#include "quiche/http2/adapter/data_source.h"
+#include "quiche/http2/adapter/event_forwarder.h"
+#include "quiche/http2/adapter/header_validator.h"
+#include "quiche/http2/adapter/http2_protocol.h"
+#include "quiche/http2/adapter/http2_session.h"
+#include "quiche/http2/adapter/http2_util.h"
+#include "quiche/http2/adapter/http2_visitor_interface.h"
+#include "quiche/http2/adapter/window_manager.h"
+#include "quiche/http2/core/http2_trace_logging.h"
+#include "quiche/http2/core/priority_write_scheduler.h"
+#include "quiche/common/platform/api/quiche_bug_tracker.h"
+#include "quiche/common/platform/api/quiche_export.h"
+#include "quiche/common/quiche_linked_hash_map.h"
+#include "quiche/spdy/core/http2_frame_decoder_adapter.h"
+#include "quiche/spdy/core/no_op_headers_handler.h"
+#include "quiche/spdy/core/spdy_framer.h"
+#include "quiche/spdy/core/spdy_header_block.h"
+#include "quiche/spdy/core/spdy_protocol.h"
+
+namespace http2 {
+namespace adapter {
+
+// This class manages state associated with a single multiplexed HTTP/2 session.
+class QUICHE_EXPORT_PRIVATE OgHttp2Session
+ : public Http2Session,
+ public spdy::SpdyFramerVisitorInterface,
+ public spdy::ExtensionVisitorInterface {
+ public:
+ struct QUICHE_EXPORT_PRIVATE Options {
+ // Returns whether to send a WINDOW_UPDATE based on the window limit, window
+ // size, and delta that would be sent in the WINDOW_UPDATE.
+ WindowManager::ShouldWindowUpdateFn should_window_update_fn =
+ DeltaAtLeastHalfLimit;
+ // The perspective of this session.
+ Perspective perspective = Perspective::kClient;
+ // The maximum HPACK table size to use.
+ absl::optional<size_t> max_hpack_encoding_table_capacity = absl::nullopt;
+ // The maximum number of decoded header bytes that a stream can receive.
+ absl::optional<uint32_t> max_header_list_bytes = absl::nullopt;
+ // The maximum size of an individual header field, including name and value.
+ absl::optional<uint32_t> max_header_field_size = absl::nullopt;
+ // Whether to automatically send PING acks when receiving a PING.
+ bool auto_ping_ack = true;
+ // Whether (as server) to send a RST_STREAM NO_ERROR when sending a fin on
+ // an incomplete stream.
+ bool rst_stream_no_error_when_incomplete = false;
+ // Whether (as server) to queue trailers until after a stream's data source
+ // has indicated the end of data. If false, the server will assume that
+ // submitting trailers indicates the end of data.
+ bool trailers_require_end_data = false;
+ // Whether to mark all input data as consumed upon encountering a connection
+ // error while processing bytes. If true, subsequent processing will also
+ // mark all input data as consumed.
+ bool blackhole_data_on_connection_error = true;
+ // Whether to advertise support for the extended CONNECT semantics described
+ // in RFC 8441. If true, this endpoint will send the appropriate setting in
+ // initial SETTINGS.
+ bool allow_extended_connect = true;
+ };
+
+ OgHttp2Session(Http2VisitorInterface& visitor, Options options);
+ ~OgHttp2Session() override;
+
+ // Enqueues a frame for transmission to the peer.
+ void EnqueueFrame(std::unique_ptr<spdy::SpdyFrameIR> frame);
+
+ // Starts a graceful shutdown sequence. No-op if a GOAWAY has already been
+ // sent.
+ void StartGracefulShutdown();
+
+ // Invokes the visitor's OnReadyToSend() method for serialized frames and
+ // DataFrameSource::Send() for data frames.
+ int Send();
+
+ int32_t SubmitRequest(absl::Span<const Header> headers,
+ std::unique_ptr<DataFrameSource> data_source,
+ void* user_data);
+ int SubmitResponse(Http2StreamId stream_id, absl::Span<const Header> headers,
+ std::unique_ptr<DataFrameSource> data_source);
+ int SubmitTrailer(Http2StreamId stream_id, absl::Span<const Header> trailers);
+ void SubmitMetadata(Http2StreamId stream_id,
+ std::unique_ptr<MetadataSource> source);
+ void SubmitSettings(absl::Span<const Http2Setting> settings);
+
+ bool IsServerSession() const {
+ return options_.perspective == Perspective::kServer;
+ }
+ Http2StreamId GetHighestReceivedStreamId() const {
+ return highest_received_stream_id_;
+ }
+ void SetStreamUserData(Http2StreamId stream_id, void* user_data);
+ void* GetStreamUserData(Http2StreamId stream_id);
+
+ // Resumes a stream that was previously blocked. Returns true on success.
+ bool ResumeStream(Http2StreamId stream_id);
+
+ // Returns the peer's outstanding stream receive window for the given stream.
+ int GetStreamSendWindowSize(Http2StreamId stream_id) const;
+
+ // Returns the current upper bound on the flow control receive window for this
+ // stream.
+ int GetStreamReceiveWindowLimit(Http2StreamId stream_id) const;
+
+ // Returns the outstanding stream receive window, or -1 if the stream does not
+ // exist.
+ int GetStreamReceiveWindowSize(Http2StreamId stream_id) const;
+
+ // Returns the outstanding connection receive window.
+ int GetReceiveWindowSize() const;
+
+ // Returns the size of the HPACK encoder's dynamic table, including the
+ // per-entry overhead from the specification.
+ int GetHpackEncoderDynamicTableSize() const;
+
+ // Returns the maximum capacity of the HPACK encoder's dynamic table.
+ int GetHpackEncoderDynamicTableCapacity() const;
+
+ // Returns the size of the HPACK decoder's dynamic table, including the
+ // per-entry overhead from the specification.
+ int GetHpackDecoderDynamicTableSize() const;
+
+ // Returns the size of the HPACK decoder's most recently applied size limit.
+ int GetHpackDecoderSizeLimit() const;
+
+ // From Http2Session.
+ int64_t ProcessBytes(absl::string_view bytes) override;
+ int Consume(Http2StreamId stream_id, size_t num_bytes) override;
+ bool want_read() const override {
+ return !received_goaway_ && !decoder_.HasError();
+ }
+ bool want_write() const override {
+ return !fatal_send_error_ &&
+ (!frames_.empty() || !buffered_data_.empty() ||
+ !connection_metadata_.empty() || HasReadyStream() ||
+ !goaway_rejected_streams_.empty());
+ }
+ int GetRemoteWindowSize() const override { return connection_send_window_; }
+
+ // From SpdyFramerVisitorInterface
+ void OnError(http2::Http2DecoderAdapter::SpdyFramerError error,
+ std::string detailed_error) override;
+ void OnCommonHeader(spdy::SpdyStreamId /*stream_id*/, size_t /*length*/,
+ uint8_t /*type*/, uint8_t /*flags*/) override;
+ void OnDataFrameHeader(spdy::SpdyStreamId stream_id, size_t length,
+ bool fin) override;
+ void OnStreamFrameData(spdy::SpdyStreamId stream_id, const char* data,
+ size_t len) override;
+ void OnStreamEnd(spdy::SpdyStreamId stream_id) override;
+ void OnStreamPadLength(spdy::SpdyStreamId /*stream_id*/,
+ size_t /*value*/) override;
+ void OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) override;
+ spdy::SpdyHeadersHandlerInterface* OnHeaderFrameStart(
+ spdy::SpdyStreamId stream_id) override;
+ void OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) override;
+ void OnRstStream(spdy::SpdyStreamId stream_id,
+ spdy::SpdyErrorCode error_code) override;
+ void OnSettings() override;
+ void OnSetting(spdy::SpdySettingsId id, uint32_t value) override;
+ void OnSettingsEnd() override;
+ void OnSettingsAck() override;
+ void OnPing(spdy::SpdyPingId unique_id, bool is_ack) override;
+ void OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
+ spdy::SpdyErrorCode error_code) override;
+ bool OnGoAwayFrameData(const char* goaway_data, size_t len) override;
+ void OnHeaders(spdy::SpdyStreamId stream_id, bool has_priority, int weight,
+ spdy::SpdyStreamId parent_stream_id, bool exclusive, bool fin,
+ bool end) override;
+ void OnWindowUpdate(spdy::SpdyStreamId stream_id,
+ int delta_window_size) override;
+ void OnPushPromise(spdy::SpdyStreamId stream_id,
+ spdy::SpdyStreamId promised_stream_id, bool end) override;
+ void OnContinuation(spdy::SpdyStreamId stream_id, bool end) override;
+ void OnAltSvc(spdy::SpdyStreamId /*stream_id*/, absl::string_view /*origin*/,
+ const spdy::SpdyAltSvcWireFormat::
+ AlternativeServiceVector& /*altsvc_vector*/) override;
+ void OnPriority(spdy::SpdyStreamId stream_id,
+ spdy::SpdyStreamId parent_stream_id, int weight,
+ bool exclusive) override;
+ void OnPriorityUpdate(spdy::SpdyStreamId prioritized_stream_id,
+ absl::string_view priority_field_value) override;
+ bool OnUnknownFrame(spdy::SpdyStreamId stream_id,
+ uint8_t frame_type) override;
+
+ // Invoked when header processing encounters an invalid or otherwise
+ // problematic header.
+ void OnHeaderStatus(Http2StreamId stream_id,
+ Http2VisitorInterface::OnHeaderResult result);
+
+ // Returns true if a recognized extension frame is received.
+ bool OnFrameHeader(spdy::SpdyStreamId stream_id, size_t length, uint8_t type,
+ uint8_t flags) override;
+
+ // Handles the payload for a recognized extension frame.
+ void OnFramePayload(const char* data, size_t len) override;
+
+ private:
+ using MetadataSequence = std::vector<std::unique_ptr<MetadataSource>>;
+
+ struct QUICHE_EXPORT_PRIVATE StreamState {
+ StreamState(int32_t stream_receive_window, int32_t stream_send_window,
+ WindowManager::WindowUpdateListener listener,
+ WindowManager::ShouldWindowUpdateFn should_window_update_fn)
+ : window_manager(stream_receive_window, std::move(listener),
+ std::move(should_window_update_fn),
+ /*update_window_on_notify=*/false),
+ send_window(stream_send_window) {}
+
+ WindowManager window_manager;
+ std::unique_ptr<DataFrameSource> outbound_body;
+ MetadataSequence outbound_metadata;
+ std::unique_ptr<spdy::SpdyHeaderBlock> trailers;
+ void* user_data = nullptr;
+ int32_t send_window;
+ absl::optional<HeaderType> received_header_type;
+ absl::optional<size_t> remaining_content_length;
+ bool half_closed_local = false;
+ bool half_closed_remote = false;
+ // Indicates that `outbound_body` temporarily cannot produce data.
+ bool data_deferred = false;
+ bool can_receive_body = true;
+ };
+ using StreamStateMap = absl::flat_hash_map<Http2StreamId, StreamState>;
+
+ struct QUICHE_EXPORT_PRIVATE PendingStreamState {
+ spdy::SpdyHeaderBlock headers;
+ std::unique_ptr<DataFrameSource> data_source;
+ void* user_data = nullptr;
+ };
+
+ class QUICHE_EXPORT_PRIVATE PassthroughHeadersHandler
+ : public spdy::SpdyHeadersHandlerInterface {
+ public:
+ explicit PassthroughHeadersHandler(OgHttp2Session& session,
+ Http2VisitorInterface& visitor)
+ : session_(session), visitor_(visitor) {}
+
+ void set_stream_id(Http2StreamId stream_id) {
+ stream_id_ = stream_id;
+ result_ = Http2VisitorInterface::HEADER_OK;
+ }
+
+ void set_frame_contains_fin() { frame_contains_fin_ = true; }
+ void set_header_type(HeaderType type) { type_ = type; }
+ HeaderType header_type() const { return type_; }
+
+ void OnHeaderBlockStart() override;
+ void OnHeader(absl::string_view key, absl::string_view value) override;
+ void OnHeaderBlockEnd(size_t /* uncompressed_header_bytes */,
+ size_t /* compressed_header_bytes */) override;
+ absl::string_view status_header() const {
+ QUICHE_DCHECK(type_ == HeaderType::RESPONSE ||
+ type_ == HeaderType::RESPONSE_100);
+ return validator_.status_header();
+ }
+ absl::optional<size_t> content_length() const {
+ return validator_.content_length();
+ }
+ void AllowConnect() { validator_.AllowConnect(); }
+ void SetMaxFieldSize(uint32_t field_size) {
+ validator_.SetMaxFieldSize(field_size);
+ }
+ bool CanReceiveBody() const;
+
+ private:
+ OgHttp2Session& session_;
+ Http2VisitorInterface& visitor_;
+ Http2StreamId stream_id_ = 0;
+ Http2VisitorInterface::OnHeaderResult result_ =
+ Http2VisitorInterface::HEADER_OK;
+ // Validates header blocks according to the HTTP/2 specification.
+ HeaderValidator validator_;
+ HeaderType type_ = HeaderType::RESPONSE;
+ bool frame_contains_fin_ = false;
+ };
+
+ struct QUICHE_EXPORT_PRIVATE ProcessBytesResultVisitor;
+
+ // Queues the connection preface, if not already done. If not
+ // `sending_outbound_settings` and the preface has not yet been queued, this
+ // method will generate and enqueue initial SETTINGS.
+ void MaybeSetupPreface(bool sending_outbound_settings);
+
+ // Gets the settings to be sent in the initial SETTINGS frame sent as part of
+ // the connection preface.
+ std::vector<Http2Setting> GetInitialSettings() const;
+
+ // Prepares and returns a SETTINGS frame with the given `settings`.
+ std::unique_ptr<spdy::SpdySettingsIR> PrepareSettingsFrame(
+ absl::Span<const Http2Setting> settings);
+
+ // Updates internal state to match the SETTINGS advertised to the peer.
+ void HandleOutboundSettings(const spdy::SpdySettingsIR& settings_frame);
+
+ void SendWindowUpdate(Http2StreamId stream_id, size_t update_delta);
+
+ enum class SendResult {
+ // All data was flushed.
+ SEND_OK,
+ // Not all data was flushed (due to flow control or TCP back pressure).
+ SEND_BLOCKED,
+ // An error occurred while sending data.
+ SEND_ERROR,
+ };
+
+ // Returns the int corresponding to the `result`, updating state as needed.
+ int InterpretSendResult(SendResult result);
+
+ enum class ProcessBytesError {
+ // A general, unspecified error.
+ kUnspecified,
+ // The (server-side) session received an invalid client connection preface.
+ kInvalidConnectionPreface,
+ // A user/visitor callback failed with a fatal error.
+ kVisitorCallbackFailed,
+ };
+ using ProcessBytesResult = absl::variant<int64_t, ProcessBytesError>;
+
+ // Attempts to process `bytes` and returns the number of bytes proccessed on
+ // success or the processing error on failure.
+ ProcessBytesResult ProcessBytesImpl(absl::string_view bytes);
+
+ // Returns true if at least one stream has data or control frames to write.
+ bool HasReadyStream() const;
+
+ // Returns the next stream that has something to write. If there are no such
+ // streams, returns zero.
+ Http2StreamId GetNextReadyStream();
+
+ // Sends the buffered connection preface or serialized frame data, if any.
+ SendResult MaybeSendBufferedData();
+
+ // Serializes and sends queued frames.
+ SendResult SendQueuedFrames();
+
+ // Returns false if a fatal connection error occurred.
+ bool AfterFrameSent(uint8_t frame_type_int, uint32_t stream_id,
+ size_t payload_length, uint8_t flags,
+ uint32_t error_code);
+
+ // Writes DATA frames for stream `stream_id`.
+ SendResult WriteForStream(Http2StreamId stream_id);
+
+ SendResult SendMetadata(Http2StreamId stream_id, MetadataSequence& sequence);
+
+ void SendHeaders(Http2StreamId stream_id, spdy::SpdyHeaderBlock headers,
+ bool end_stream);
+
+ void SendTrailers(Http2StreamId stream_id, spdy::SpdyHeaderBlock trailers);
+
+ // Encapsulates the RST_STREAM NO_ERROR behavior described in RFC 7540
+ // Section 8.1.
+ void MaybeFinWithRstStream(StreamStateMap::iterator iter);
+
+ // Performs flow control accounting for data sent by the peer.
+ void MarkDataBuffered(Http2StreamId stream_id, size_t bytes);
+
+ // Creates a stream for `stream_id` if not already present and returns an
+ // iterator pointing to it.
+ StreamStateMap::iterator CreateStream(Http2StreamId stream_id);
+
+ // Creates a stream for `stream_id`, stores the `data_source` and `user_data`
+ // in the stream state, and sends the `headers`.
+ void StartRequest(Http2StreamId stream_id, spdy::SpdyHeaderBlock headers,
+ std::unique_ptr<DataFrameSource> data_source,
+ void* user_data);
+
+ // Sends headers for pending streams as long as the stream limit allows.
+ void StartPendingStreams();
+
+ // Closes the given `stream_id` with the given `error_code`.
+ void CloseStream(Http2StreamId stream_id, Http2ErrorCode error_code);
+
+ // Calculates the next expected header type for a stream in a given state.
+ HeaderType NextHeaderType(absl::optional<HeaderType> current_type);
+
+ // Returns true if the session can create a new stream.
+ bool CanCreateStream() const;
+
+ // Informs the visitor of the connection `error` and stops processing on the
+ // connection. If server-side, also sends a GOAWAY with `error_code`.
+ void LatchErrorAndNotify(Http2ErrorCode error_code,
+ Http2VisitorInterface::ConnectionError error);
+
+ void CloseStreamIfReady(uint8_t frame_type, uint32_t stream_id);
+
+ // Informs the visitor of rejected, non-active streams due to GOAWAY receipt.
+ void CloseGoAwayRejectedStreams();
+
+ // Updates internal state to prepare for sending an immediate GOAWAY.
+ void PrepareForImmediateGoAway();
+
+ // Handles the potential end of received metadata for the given `stream_id`.
+ void MaybeHandleMetadataEndForStream(Http2StreamId stream_id);
+
+ void DecrementQueuedFrameCount(uint32_t stream_id, uint8_t frame_type);
+
+ void HandleContentLengthError(Http2StreamId stream_id);
+
+ // Invoked when sending a flow control window update to the peer.
+ void UpdateReceiveWindow(Http2StreamId stream_id, int32_t delta);
+
+ // Updates stream send window accounting to respect the peer's advertised
+ // initial window setting.
+ void UpdateStreamSendWindowSizes(uint32_t new_value);
+
+ // Updates stream receive window managers to use the newly advertised stream
+ // initial window.
+ void UpdateStreamReceiveWindowSizes(uint32_t new_value);
+
+ // Receives events when inbound frames are parsed.
+ Http2VisitorInterface& visitor_;
+
+ // Forwards received events to the session if it can accept them.
+ EventForwarder event_forwarder_;
+
+ // Logs received frames when enabled.
+ Http2TraceLogger receive_logger_;
+ // Logs sent frames when enabled.
+ Http2FrameLogger send_logger_;
+
+ // Encodes outbound frames.
+ spdy::SpdyFramer framer_{spdy::SpdyFramer::ENABLE_COMPRESSION};
+
+ // Decodes inbound frames.
+ http2::Http2DecoderAdapter decoder_;
+
+ // Maintains the state of active streams known to this session.
+ StreamStateMap stream_map_;
+
+ // Maintains the state of pending streams known to this session. A pending
+ // stream is kept in this list until it can be created while complying with
+ // `max_outbound_concurrent_streams_`.
+ quiche::QuicheLinkedHashMap<Http2StreamId, PendingStreamState>
+ pending_streams_;
+
+ // The queue of outbound frames.
+ std::list<std::unique_ptr<spdy::SpdyFrameIR>> frames_;
+ // Buffered data (connection preface, serialized frames) that has not yet been
+ // sent.
+ std::string buffered_data_;
+
+ // Maintains the set of streams ready to write data to the peer.
+ using WriteScheduler = PriorityWriteScheduler<Http2StreamId>;
+ WriteScheduler write_scheduler_;
+
+ // Stores the queue of callbacks to invoke upon receiving SETTINGS acks. At
+ // most one callback is invoked for each SETTINGS ack.
+ using SettingsAckCallback = std::function<void()>;
+ std::list<SettingsAckCallback> settings_ack_callbacks_;
+
+ // Delivers header name-value pairs to the visitor.
+ PassthroughHeadersHandler headers_handler_;
+
+ // Ignores header data, e.g., for an unknown or rejected stream.
+ spdy::NoOpHeadersHandler noop_headers_handler_;
+
+ // Tracks the remaining client connection preface, in the case of a server
+ // session.
+ absl::string_view remaining_preface_;
+
+ WindowManager connection_window_manager_;
+
+ // Tracks the streams that have been marked for reset. A stream is removed
+ // from this set once it is closed.
+ absl::flat_hash_set<Http2StreamId> streams_reset_;
+
+ // The number of frames currently queued per stream.
+ absl::flat_hash_map<Http2StreamId, int> queued_frames_;
+ // Includes streams that are currently ready to write trailers.
+ absl::flat_hash_set<Http2StreamId> trailers_ready_;
+ // Includes streams that are currently ready to write metadata.
+ absl::flat_hash_set<Http2StreamId> metadata_ready_;
+ // Includes streams that will not be written due to receipt of GOAWAY.
+ absl::flat_hash_set<Http2StreamId> goaway_rejected_streams_;
+
+ MetadataSequence connection_metadata_;
+
+ Http2StreamId next_stream_id_ = 1;
+ // The highest received stream ID is the highest stream ID in any frame read
+ // from the peer. The highest processed stream ID is the highest stream ID for
+ // which this endpoint created a stream in the stream map.
+ Http2StreamId highest_received_stream_id_ = 0;
+ Http2StreamId highest_processed_stream_id_ = 0;
+ Http2StreamId metadata_stream_id_ = 0;
+ Http2StreamId received_goaway_stream_id_ = 0;
+ size_t metadata_length_ = 0;
+ int32_t connection_send_window_ = kInitialFlowControlWindowSize;
+ // The initial flow control receive window size for any newly created streams.
+ int32_t initial_stream_receive_window_ = kInitialFlowControlWindowSize;
+ // The initial flow control send window size for any newly created streams.
+ int32_t initial_stream_send_window_ = kInitialFlowControlWindowSize;
+ uint32_t max_frame_payload_ = 16384u;
+ // The maximum number of concurrent streams that this connection can open to
+ // its peer and allow from its peer, respectively. Although the initial value
+ // is unlimited, the spec encourages a value of at least 100. We limit
+ // ourselves to opening 100 until told otherwise by the peer and allow an
+ // unlimited number from the peer until updated from SETTINGS we send.
+ uint32_t max_outbound_concurrent_streams_ = 100u;
+ uint32_t pending_max_inbound_concurrent_streams_ =
+ std::numeric_limits<uint32_t>::max();
+ uint32_t max_inbound_concurrent_streams_ =
+ std::numeric_limits<uint32_t>::max();
+ const Options options_;
+
+ // The HPACK encoder header table capacity that will be applied when
+ // acking SETTINGS from the peer. Only contains a value if the peer advertises
+ // a larger table capacity than currently used; a smaller value can safely be
+ // applied immediately upon receipt.
+ absl::optional<uint32_t> encoder_header_table_capacity_when_acking_;
+
+ bool received_goaway_ = false;
+ bool queued_preface_ = false;
+ bool peer_supports_metadata_ = false;
+ bool end_metadata_ = false;
+ bool sent_non_ack_settings_ = false;
+
+ // Recursion guard for ProcessBytes().
+ bool processing_bytes_ = false;
+ // Recursion guard for Send().
+ bool sending_ = false;
+
+ // Replace this with a stream ID, for multiple GOAWAY support.
+ bool queued_goaway_ = false;
+ bool queued_immediate_goaway_ = false;
+ bool latched_error_ = false;
+
+ // True if a fatal sending error has occurred.
+ bool fatal_send_error_ = false;
+
+ // True if a fatal processing visitor callback failed.
+ bool fatal_visitor_callback_failure_ = false;
+};
+
+} // namespace adapter
+} // namespace http2
+
+#endif // QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_