| #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/header_validator_base.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/platform/api/quiche_flags.h" | 
 | #include "quiche/common/quiche_linked_hash_map.h" | 
 | #include "quiche/spdy/core/http2_frame_decoder_adapter.h" | 
 | #include "quiche/spdy/core/http2_header_block.h" | 
 | #include "quiche/spdy/core/no_op_headers_handler.h" | 
 | #include "quiche/spdy/core/spdy_framer.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 OgHttp2Session : public Http2Session, | 
 |                                      public spdy::SpdyFramerVisitorInterface { | 
 |  public: | 
 |   struct QUICHE_EXPORT 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; | 
 |     // Whether to allow `obs-text` (characters from hexadecimal 0x80 to 0xff) in | 
 |     // header field values. | 
 |     bool allow_obs_text = true; | 
 |     // If true, validates header field names and values according to RFC 7230 | 
 |     // and RFC 7540. | 
 |     bool validate_http_headers = 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() || HasReadyStream() || | 
 |             !goaway_rejected_streams_.empty()); | 
 |   } | 
 |   int GetRemoteWindowSize() const override { return connection_send_window_; } | 
 |   bool peer_enables_connect_protocol() { | 
 |     return peer_enables_connect_protocol_; | 
 |   } | 
 |  | 
 |   // 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, size_t payload_length, | 
 |                  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, size_t payload_length, | 
 |                       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; | 
 |   void OnUnknownFrameStart(spdy::SpdyStreamId stream_id, size_t length, | 
 |                            uint8_t type, uint8_t flags) override; | 
 |   void OnUnknownFramePayload(spdy::SpdyStreamId stream_id, | 
 |                              absl::string_view payload) override; | 
 |  | 
 |   // Invoked when header processing encounters an invalid or otherwise | 
 |   // problematic header. | 
 |   void OnHeaderStatus(Http2StreamId stream_id, | 
 |                       Http2VisitorInterface::OnHeaderResult result); | 
 |  | 
 |  private: | 
 |   struct QUICHE_EXPORT 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; | 
 |     std::unique_ptr<spdy::Http2HeaderBlock> 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 PendingStreamState { | 
 |     spdy::Http2HeaderBlock headers; | 
 |     std::unique_ptr<DataFrameSource> data_source; | 
 |     void* user_data = nullptr; | 
 |   }; | 
 |  | 
 |   class QUICHE_EXPORT PassthroughHeadersHandler | 
 |       : public spdy::SpdyHeadersHandlerInterface { | 
 |    public: | 
 |     PassthroughHeadersHandler(OgHttp2Session& session, | 
 |                               Http2VisitorInterface& 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 SetAllowExtendedConnect() { validator_->SetAllowExtendedConnect(); } | 
 |     void SetMaxFieldSize(uint32_t field_size) { | 
 |       validator_->SetMaxFieldSize(field_size); | 
 |     } | 
 |     void SetAllowObsText(bool allow) { | 
 |       validator_->SetObsTextOption(allow ? ObsTextOption::kAllow | 
 |                                          : ObsTextOption::kDisallow); | 
 |     } | 
 |     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. | 
 |     std::unique_ptr<HeaderValidatorBase> validator_; | 
 |     HeaderType type_ = HeaderType::RESPONSE; | 
 |     bool frame_contains_fin_ = false; | 
 |   }; | 
 |  | 
 |   struct QUICHE_EXPORT 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); | 
 |  | 
 |   void SerializeMetadata(Http2StreamId stream_id, | 
 |                          std::unique_ptr<MetadataSource> source); | 
 |  | 
 |   void SendHeaders(Http2StreamId stream_id, spdy::Http2HeaderBlock headers, | 
 |                    bool end_stream); | 
 |  | 
 |   void SendTrailers(Http2StreamId stream_id, spdy::Http2HeaderBlock 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::Http2HeaderBlock 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_; | 
 |  | 
 |   const Options options_; | 
 |  | 
 |   // 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 will not be written due to receipt of GOAWAY. | 
 |   absl::flat_hash_set<Http2StreamId> goaway_rejected_streams_; | 
 |  | 
 |   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 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_ = kDefaultFramePayloadSizeLimit; | 
 |   // 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(); | 
 |  | 
 |   // 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 process_metadata_ = false; | 
 |   bool sent_non_ack_settings_ = false; | 
 |  | 
 |   // Recursion guard for ProcessBytes(). | 
 |   bool processing_bytes_ = false; | 
 |   // Recursion guard for Send(). | 
 |   bool sending_ = false; | 
 |  | 
 |   bool peer_enables_connect_protocol_ = 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_ |