1 #ifndef QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_ 2 #define QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_ 3 4 #include <cstdint> 5 #include <limits> 6 #include <list> 7 #include <memory> 8 #include <vector> 9 10 #include "absl/strings/string_view.h" 11 #include "absl/types/optional.h" 12 #include "absl/types/variant.h" 13 #include "quiche/http2/adapter/data_source.h" 14 #include "quiche/http2/adapter/event_forwarder.h" 15 #include "quiche/http2/adapter/header_validator.h" 16 #include "quiche/http2/adapter/header_validator_base.h" 17 #include "quiche/http2/adapter/http2_protocol.h" 18 #include "quiche/http2/adapter/http2_session.h" 19 #include "quiche/http2/adapter/http2_util.h" 20 #include "quiche/http2/adapter/http2_visitor_interface.h" 21 #include "quiche/http2/adapter/window_manager.h" 22 #include "quiche/http2/core/http2_trace_logging.h" 23 #include "quiche/http2/core/priority_write_scheduler.h" 24 #include "quiche/common/platform/api/quiche_bug_tracker.h" 25 #include "quiche/common/platform/api/quiche_export.h" 26 #include "quiche/common/platform/api/quiche_flags.h" 27 #include "quiche/common/quiche_linked_hash_map.h" 28 #include "quiche/spdy/core/http2_frame_decoder_adapter.h" 29 #include "quiche/spdy/core/http2_header_block.h" 30 #include "quiche/spdy/core/no_op_headers_handler.h" 31 #include "quiche/spdy/core/spdy_framer.h" 32 #include "quiche/spdy/core/spdy_protocol.h" 33 34 namespace http2 { 35 namespace adapter { 36 37 // This class manages state associated with a single multiplexed HTTP/2 session. 38 class QUICHE_EXPORT OgHttp2Session : public Http2Session, 39 public spdy::SpdyFramerVisitorInterface { 40 public: 41 struct QUICHE_EXPORT Options { 42 // Returns whether to send a WINDOW_UPDATE based on the window limit, window 43 // size, and delta that would be sent in the WINDOW_UPDATE. 44 WindowManager::ShouldWindowUpdateFn should_window_update_fn = 45 DeltaAtLeastHalfLimit; 46 // The perspective of this session. 47 Perspective perspective = Perspective::kClient; 48 // The maximum HPACK table size to use. 49 absl::optional<size_t> max_hpack_encoding_table_capacity = absl::nullopt; 50 // The maximum number of decoded header bytes that a stream can receive. 51 absl::optional<uint32_t> max_header_list_bytes = absl::nullopt; 52 // The maximum size of an individual header field, including name and value. 53 absl::optional<uint32_t> max_header_field_size = absl::nullopt; 54 // Whether to automatically send PING acks when receiving a PING. 55 bool auto_ping_ack = true; 56 // Whether (as server) to send a RST_STREAM NO_ERROR when sending a fin on 57 // an incomplete stream. 58 bool rst_stream_no_error_when_incomplete = false; 59 // Whether (as server) to queue trailers until after a stream's data source 60 // has indicated the end of data. If false, the server will assume that 61 // submitting trailers indicates the end of data. 62 bool trailers_require_end_data = false; 63 // Whether to mark all input data as consumed upon encountering a connection 64 // error while processing bytes. If true, subsequent processing will also 65 // mark all input data as consumed. 66 bool blackhole_data_on_connection_error = true; 67 // Whether to advertise support for the extended CONNECT semantics described 68 // in RFC 8441. If true, this endpoint will send the appropriate setting in 69 // initial SETTINGS. 70 bool allow_extended_connect = true; 71 // Whether to allow `obs-text` (characters from hexadecimal 0x80 to 0xff) in 72 // header field values. 73 bool allow_obs_text = true; 74 // If true, validates header field names and values according to RFC 7230 75 // and RFC 7540. 76 bool validate_http_headers = true; 77 }; 78 79 OgHttp2Session(Http2VisitorInterface& visitor, Options options); 80 ~OgHttp2Session() override; 81 82 // Enqueues a frame for transmission to the peer. 83 void EnqueueFrame(std::unique_ptr<spdy::SpdyFrameIR> frame); 84 85 // Starts a graceful shutdown sequence. No-op if a GOAWAY has already been 86 // sent. 87 void StartGracefulShutdown(); 88 89 // Invokes the visitor's OnReadyToSend() method for serialized frames and 90 // DataFrameSource::Send() for data frames. 91 int Send(); 92 93 int32_t SubmitRequest(absl::Span<const Header> headers, 94 std::unique_ptr<DataFrameSource> data_source, 95 void* user_data); 96 int SubmitResponse(Http2StreamId stream_id, absl::Span<const Header> headers, 97 std::unique_ptr<DataFrameSource> data_source); 98 int SubmitTrailer(Http2StreamId stream_id, absl::Span<const Header> trailers); 99 void SubmitMetadata(Http2StreamId stream_id, 100 std::unique_ptr<MetadataSource> source); 101 void SubmitSettings(absl::Span<const Http2Setting> settings); 102 IsServerSession()103 bool IsServerSession() const { 104 return options_.perspective == Perspective::kServer; 105 } GetHighestReceivedStreamId()106 Http2StreamId GetHighestReceivedStreamId() const { 107 return highest_received_stream_id_; 108 } 109 void SetStreamUserData(Http2StreamId stream_id, void* user_data); 110 void* GetStreamUserData(Http2StreamId stream_id); 111 112 // Resumes a stream that was previously blocked. Returns true on success. 113 bool ResumeStream(Http2StreamId stream_id); 114 115 // Returns the peer's outstanding stream receive window for the given stream. 116 int GetStreamSendWindowSize(Http2StreamId stream_id) const; 117 118 // Returns the current upper bound on the flow control receive window for this 119 // stream. 120 int GetStreamReceiveWindowLimit(Http2StreamId stream_id) const; 121 122 // Returns the outstanding stream receive window, or -1 if the stream does not 123 // exist. 124 int GetStreamReceiveWindowSize(Http2StreamId stream_id) const; 125 126 // Returns the outstanding connection receive window. 127 int GetReceiveWindowSize() const; 128 129 // Returns the size of the HPACK encoder's dynamic table, including the 130 // per-entry overhead from the specification. 131 int GetHpackEncoderDynamicTableSize() const; 132 133 // Returns the maximum capacity of the HPACK encoder's dynamic table. 134 int GetHpackEncoderDynamicTableCapacity() const; 135 136 // Returns the size of the HPACK decoder's dynamic table, including the 137 // per-entry overhead from the specification. 138 int GetHpackDecoderDynamicTableSize() const; 139 140 // Returns the size of the HPACK decoder's most recently applied size limit. 141 int GetHpackDecoderSizeLimit() const; 142 143 // From Http2Session. 144 int64_t ProcessBytes(absl::string_view bytes) override; 145 int Consume(Http2StreamId stream_id, size_t num_bytes) override; want_read()146 bool want_read() const override { 147 return !received_goaway_ && !decoder_.HasError(); 148 } want_write()149 bool want_write() const override { 150 return !fatal_send_error_ && 151 (!frames_.empty() || !buffered_data_.empty() || HasReadyStream() || 152 !goaway_rejected_streams_.empty()); 153 } GetRemoteWindowSize()154 int GetRemoteWindowSize() const override { return connection_send_window_; } peer_enables_connect_protocol()155 bool peer_enables_connect_protocol() { 156 return peer_enables_connect_protocol_; 157 } 158 159 // From SpdyFramerVisitorInterface 160 void OnError(http2::Http2DecoderAdapter::SpdyFramerError error, 161 std::string detailed_error) override; 162 void OnCommonHeader(spdy::SpdyStreamId /*stream_id*/, size_t /*length*/, 163 uint8_t /*type*/, uint8_t /*flags*/) override; 164 void OnDataFrameHeader(spdy::SpdyStreamId stream_id, size_t length, 165 bool fin) override; 166 void OnStreamFrameData(spdy::SpdyStreamId stream_id, const char* data, 167 size_t len) override; 168 void OnStreamEnd(spdy::SpdyStreamId stream_id) override; 169 void OnStreamPadLength(spdy::SpdyStreamId /*stream_id*/, 170 size_t /*value*/) override; 171 void OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) override; 172 spdy::SpdyHeadersHandlerInterface* OnHeaderFrameStart( 173 spdy::SpdyStreamId stream_id) override; 174 void OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) override; 175 void OnRstStream(spdy::SpdyStreamId stream_id, 176 spdy::SpdyErrorCode error_code) override; 177 void OnSettings() override; 178 void OnSetting(spdy::SpdySettingsId id, uint32_t value) override; 179 void OnSettingsEnd() override; 180 void OnSettingsAck() override; 181 void OnPing(spdy::SpdyPingId unique_id, bool is_ack) override; 182 void OnGoAway(spdy::SpdyStreamId last_accepted_stream_id, 183 spdy::SpdyErrorCode error_code) override; 184 bool OnGoAwayFrameData(const char* goaway_data, size_t len) override; 185 void OnHeaders(spdy::SpdyStreamId stream_id, size_t payload_length, 186 bool has_priority, int weight, 187 spdy::SpdyStreamId parent_stream_id, bool exclusive, bool fin, 188 bool end) override; 189 void OnWindowUpdate(spdy::SpdyStreamId stream_id, 190 int delta_window_size) override; 191 void OnPushPromise(spdy::SpdyStreamId stream_id, 192 spdy::SpdyStreamId promised_stream_id, bool end) override; 193 void OnContinuation(spdy::SpdyStreamId stream_id, size_t payload_length, 194 bool end) override; 195 void OnAltSvc(spdy::SpdyStreamId /*stream_id*/, absl::string_view /*origin*/, 196 const spdy::SpdyAltSvcWireFormat:: 197 AlternativeServiceVector& /*altsvc_vector*/) override; 198 void OnPriority(spdy::SpdyStreamId stream_id, 199 spdy::SpdyStreamId parent_stream_id, int weight, 200 bool exclusive) override; 201 void OnPriorityUpdate(spdy::SpdyStreamId prioritized_stream_id, 202 absl::string_view priority_field_value) override; 203 bool OnUnknownFrame(spdy::SpdyStreamId stream_id, 204 uint8_t frame_type) override; 205 void OnUnknownFrameStart(spdy::SpdyStreamId stream_id, size_t length, 206 uint8_t type, uint8_t flags) override; 207 void OnUnknownFramePayload(spdy::SpdyStreamId stream_id, 208 absl::string_view payload) override; 209 210 // Invoked when header processing encounters an invalid or otherwise 211 // problematic header. 212 void OnHeaderStatus(Http2StreamId stream_id, 213 Http2VisitorInterface::OnHeaderResult result); 214 215 private: 216 struct QUICHE_EXPORT StreamState { StreamStateStreamState217 StreamState(int32_t stream_receive_window, int32_t stream_send_window, 218 WindowManager::WindowUpdateListener listener, 219 WindowManager::ShouldWindowUpdateFn should_window_update_fn) 220 : window_manager(stream_receive_window, std::move(listener), 221 std::move(should_window_update_fn), 222 /*update_window_on_notify=*/false), 223 send_window(stream_send_window) {} 224 225 WindowManager window_manager; 226 std::unique_ptr<DataFrameSource> outbound_body; 227 std::unique_ptr<spdy::Http2HeaderBlock> trailers; 228 void* user_data = nullptr; 229 int32_t send_window; 230 absl::optional<HeaderType> received_header_type; 231 absl::optional<size_t> remaining_content_length; 232 bool half_closed_local = false; 233 bool half_closed_remote = false; 234 // Indicates that `outbound_body` temporarily cannot produce data. 235 bool data_deferred = false; 236 bool sent_head_method = false; 237 bool can_receive_body = true; 238 }; 239 using StreamStateMap = absl::flat_hash_map<Http2StreamId, StreamState>; 240 241 struct QUICHE_EXPORT PendingStreamState { 242 spdy::Http2HeaderBlock headers; 243 std::unique_ptr<DataFrameSource> data_source; 244 void* user_data = nullptr; 245 }; 246 247 class QUICHE_EXPORT PassthroughHeadersHandler 248 : public spdy::SpdyHeadersHandlerInterface { 249 public: 250 PassthroughHeadersHandler(OgHttp2Session& session, 251 Http2VisitorInterface& visitor); 252 set_stream_id(Http2StreamId stream_id)253 void set_stream_id(Http2StreamId stream_id) { 254 stream_id_ = stream_id; 255 result_ = Http2VisitorInterface::HEADER_OK; 256 } 257 set_frame_contains_fin()258 void set_frame_contains_fin() { frame_contains_fin_ = true; } set_header_type(HeaderType type)259 void set_header_type(HeaderType type) { type_ = type; } header_type()260 HeaderType header_type() const { return type_; } 261 262 void OnHeaderBlockStart() override; 263 void OnHeader(absl::string_view key, absl::string_view value) override; 264 void OnHeaderBlockEnd(size_t /* uncompressed_header_bytes */, 265 size_t /* compressed_header_bytes */) override; status_header()266 absl::string_view status_header() const { 267 QUICHE_DCHECK(type_ == HeaderType::RESPONSE || 268 type_ == HeaderType::RESPONSE_100); 269 return validator_->status_header(); 270 } content_length()271 absl::optional<size_t> content_length() const { 272 return validator_->content_length(); 273 } SetAllowExtendedConnect()274 void SetAllowExtendedConnect() { validator_->SetAllowExtendedConnect(); } SetMaxFieldSize(uint32_t field_size)275 void SetMaxFieldSize(uint32_t field_size) { 276 validator_->SetMaxFieldSize(field_size); 277 } SetAllowObsText(bool allow)278 void SetAllowObsText(bool allow) { 279 validator_->SetObsTextOption(allow ? ObsTextOption::kAllow 280 : ObsTextOption::kDisallow); 281 } 282 bool CanReceiveBody() const; 283 284 private: 285 OgHttp2Session& session_; 286 Http2VisitorInterface& visitor_; 287 Http2StreamId stream_id_ = 0; 288 Http2VisitorInterface::OnHeaderResult result_ = 289 Http2VisitorInterface::HEADER_OK; 290 // Validates header blocks according to the HTTP/2 specification. 291 std::unique_ptr<HeaderValidatorBase> validator_; 292 HeaderType type_ = HeaderType::RESPONSE; 293 bool frame_contains_fin_ = false; 294 }; 295 296 struct QUICHE_EXPORT ProcessBytesResultVisitor; 297 298 // Queues the connection preface, if not already done. If not 299 // `sending_outbound_settings` and the preface has not yet been queued, this 300 // method will generate and enqueue initial SETTINGS. 301 void MaybeSetupPreface(bool sending_outbound_settings); 302 303 // Gets the settings to be sent in the initial SETTINGS frame sent as part of 304 // the connection preface. 305 std::vector<Http2Setting> GetInitialSettings() const; 306 307 // Prepares and returns a SETTINGS frame with the given `settings`. 308 std::unique_ptr<spdy::SpdySettingsIR> PrepareSettingsFrame( 309 absl::Span<const Http2Setting> settings); 310 311 // Updates internal state to match the SETTINGS advertised to the peer. 312 void HandleOutboundSettings(const spdy::SpdySettingsIR& settings_frame); 313 314 void SendWindowUpdate(Http2StreamId stream_id, size_t update_delta); 315 316 enum class SendResult { 317 // All data was flushed. 318 SEND_OK, 319 // Not all data was flushed (due to flow control or TCP back pressure). 320 SEND_BLOCKED, 321 // An error occurred while sending data. 322 SEND_ERROR, 323 }; 324 325 // Returns the int corresponding to the `result`, updating state as needed. 326 int InterpretSendResult(SendResult result); 327 328 enum class ProcessBytesError { 329 // A general, unspecified error. 330 kUnspecified, 331 // The (server-side) session received an invalid client connection preface. 332 kInvalidConnectionPreface, 333 // A user/visitor callback failed with a fatal error. 334 kVisitorCallbackFailed, 335 }; 336 using ProcessBytesResult = absl::variant<int64_t, ProcessBytesError>; 337 338 // Attempts to process `bytes` and returns the number of bytes proccessed on 339 // success or the processing error on failure. 340 ProcessBytesResult ProcessBytesImpl(absl::string_view bytes); 341 342 // Returns true if at least one stream has data or control frames to write. 343 bool HasReadyStream() const; 344 345 // Returns the next stream that has something to write. If there are no such 346 // streams, returns zero. 347 Http2StreamId GetNextReadyStream(); 348 349 // Sends the buffered connection preface or serialized frame data, if any. 350 SendResult MaybeSendBufferedData(); 351 352 // Serializes and sends queued frames. 353 SendResult SendQueuedFrames(); 354 355 // Returns false if a fatal connection error occurred. 356 bool AfterFrameSent(uint8_t frame_type_int, uint32_t stream_id, 357 size_t payload_length, uint8_t flags, 358 uint32_t error_code); 359 360 // Writes DATA frames for stream `stream_id`. 361 SendResult WriteForStream(Http2StreamId stream_id); 362 363 void SerializeMetadata(Http2StreamId stream_id, 364 std::unique_ptr<MetadataSource> source); 365 366 void SendHeaders(Http2StreamId stream_id, spdy::Http2HeaderBlock headers, 367 bool end_stream); 368 369 void SendTrailers(Http2StreamId stream_id, spdy::Http2HeaderBlock trailers); 370 371 // Encapsulates the RST_STREAM NO_ERROR behavior described in RFC 7540 372 // Section 8.1. 373 void MaybeFinWithRstStream(StreamStateMap::iterator iter); 374 375 // Performs flow control accounting for data sent by the peer. 376 void MarkDataBuffered(Http2StreamId stream_id, size_t bytes); 377 378 // Creates a stream for `stream_id` if not already present and returns an 379 // iterator pointing to it. 380 StreamStateMap::iterator CreateStream(Http2StreamId stream_id); 381 382 // Creates a stream for `stream_id`, stores the `data_source` and `user_data` 383 // in the stream state, and sends the `headers`. 384 void StartRequest(Http2StreamId stream_id, spdy::Http2HeaderBlock headers, 385 std::unique_ptr<DataFrameSource> data_source, 386 void* user_data); 387 388 // Sends headers for pending streams as long as the stream limit allows. 389 void StartPendingStreams(); 390 391 // Closes the given `stream_id` with the given `error_code`. 392 void CloseStream(Http2StreamId stream_id, Http2ErrorCode error_code); 393 394 // Calculates the next expected header type for a stream in a given state. 395 HeaderType NextHeaderType(absl::optional<HeaderType> current_type); 396 397 // Returns true if the session can create a new stream. 398 bool CanCreateStream() const; 399 400 // Informs the visitor of the connection `error` and stops processing on the 401 // connection. If server-side, also sends a GOAWAY with `error_code`. 402 void LatchErrorAndNotify(Http2ErrorCode error_code, 403 Http2VisitorInterface::ConnectionError error); 404 405 void CloseStreamIfReady(uint8_t frame_type, uint32_t stream_id); 406 407 // Informs the visitor of rejected, non-active streams due to GOAWAY receipt. 408 void CloseGoAwayRejectedStreams(); 409 410 // Updates internal state to prepare for sending an immediate GOAWAY. 411 void PrepareForImmediateGoAway(); 412 413 // Handles the potential end of received metadata for the given `stream_id`. 414 void MaybeHandleMetadataEndForStream(Http2StreamId stream_id); 415 416 void DecrementQueuedFrameCount(uint32_t stream_id, uint8_t frame_type); 417 418 void HandleContentLengthError(Http2StreamId stream_id); 419 420 // Invoked when sending a flow control window update to the peer. 421 void UpdateReceiveWindow(Http2StreamId stream_id, int32_t delta); 422 423 // Updates stream send window accounting to respect the peer's advertised 424 // initial window setting. 425 void UpdateStreamSendWindowSizes(uint32_t new_value); 426 427 // Updates stream receive window managers to use the newly advertised stream 428 // initial window. 429 void UpdateStreamReceiveWindowSizes(uint32_t new_value); 430 431 // Receives events when inbound frames are parsed. 432 Http2VisitorInterface& visitor_; 433 434 const Options options_; 435 436 // Forwards received events to the session if it can accept them. 437 EventForwarder event_forwarder_; 438 439 // Logs received frames when enabled. 440 Http2TraceLogger receive_logger_; 441 // Logs sent frames when enabled. 442 Http2FrameLogger send_logger_; 443 444 // Encodes outbound frames. 445 spdy::SpdyFramer framer_{spdy::SpdyFramer::ENABLE_COMPRESSION}; 446 447 // Decodes inbound frames. 448 http2::Http2DecoderAdapter decoder_; 449 450 // Maintains the state of active streams known to this session. 451 StreamStateMap stream_map_; 452 453 // Maintains the state of pending streams known to this session. A pending 454 // stream is kept in this list until it can be created while complying with 455 // `max_outbound_concurrent_streams_`. 456 quiche::QuicheLinkedHashMap<Http2StreamId, PendingStreamState> 457 pending_streams_; 458 459 // The queue of outbound frames. 460 std::list<std::unique_ptr<spdy::SpdyFrameIR>> frames_; 461 // Buffered data (connection preface, serialized frames) that has not yet been 462 // sent. 463 std::string buffered_data_; 464 465 // Maintains the set of streams ready to write data to the peer. 466 using WriteScheduler = PriorityWriteScheduler<Http2StreamId>; 467 WriteScheduler write_scheduler_; 468 469 // Stores the queue of callbacks to invoke upon receiving SETTINGS acks. At 470 // most one callback is invoked for each SETTINGS ack. 471 using SettingsAckCallback = std::function<void()>; 472 std::list<SettingsAckCallback> settings_ack_callbacks_; 473 474 // Delivers header name-value pairs to the visitor. 475 PassthroughHeadersHandler headers_handler_; 476 477 // Ignores header data, e.g., for an unknown or rejected stream. 478 spdy::NoOpHeadersHandler noop_headers_handler_; 479 480 // Tracks the remaining client connection preface, in the case of a server 481 // session. 482 absl::string_view remaining_preface_; 483 484 WindowManager connection_window_manager_; 485 486 // Tracks the streams that have been marked for reset. A stream is removed 487 // from this set once it is closed. 488 absl::flat_hash_set<Http2StreamId> streams_reset_; 489 490 // The number of frames currently queued per stream. 491 absl::flat_hash_map<Http2StreamId, int> queued_frames_; 492 // Includes streams that are currently ready to write trailers. 493 absl::flat_hash_set<Http2StreamId> trailers_ready_; 494 // Includes streams that will not be written due to receipt of GOAWAY. 495 absl::flat_hash_set<Http2StreamId> goaway_rejected_streams_; 496 497 Http2StreamId next_stream_id_ = 1; 498 // The highest received stream ID is the highest stream ID in any frame read 499 // from the peer. The highest processed stream ID is the highest stream ID for 500 // which this endpoint created a stream in the stream map. 501 Http2StreamId highest_received_stream_id_ = 0; 502 Http2StreamId highest_processed_stream_id_ = 0; 503 Http2StreamId received_goaway_stream_id_ = 0; 504 size_t metadata_length_ = 0; 505 int32_t connection_send_window_ = kInitialFlowControlWindowSize; 506 // The initial flow control receive window size for any newly created streams. 507 int32_t initial_stream_receive_window_ = kInitialFlowControlWindowSize; 508 // The initial flow control send window size for any newly created streams. 509 int32_t initial_stream_send_window_ = kInitialFlowControlWindowSize; 510 uint32_t max_frame_payload_ = kDefaultFramePayloadSizeLimit; 511 // The maximum number of concurrent streams that this connection can open to 512 // its peer and allow from its peer, respectively. Although the initial value 513 // is unlimited, the spec encourages a value of at least 100. We limit 514 // ourselves to opening 100 until told otherwise by the peer and allow an 515 // unlimited number from the peer until updated from SETTINGS we send. 516 uint32_t max_outbound_concurrent_streams_ = 100u; 517 uint32_t pending_max_inbound_concurrent_streams_ = 518 std::numeric_limits<uint32_t>::max(); 519 uint32_t max_inbound_concurrent_streams_ = 520 std::numeric_limits<uint32_t>::max(); 521 522 // The HPACK encoder header table capacity that will be applied when 523 // acking SETTINGS from the peer. Only contains a value if the peer advertises 524 // a larger table capacity than currently used; a smaller value can safely be 525 // applied immediately upon receipt. 526 absl::optional<uint32_t> encoder_header_table_capacity_when_acking_; 527 528 bool received_goaway_ = false; 529 bool queued_preface_ = false; 530 bool peer_supports_metadata_ = false; 531 bool end_metadata_ = false; 532 bool process_metadata_ = false; 533 bool sent_non_ack_settings_ = false; 534 535 // Recursion guard for ProcessBytes(). 536 bool processing_bytes_ = false; 537 // Recursion guard for Send(). 538 bool sending_ = false; 539 540 bool peer_enables_connect_protocol_ = false; 541 542 // Replace this with a stream ID, for multiple GOAWAY support. 543 bool queued_goaway_ = false; 544 bool queued_immediate_goaway_ = false; 545 bool latched_error_ = false; 546 547 // True if a fatal sending error has occurred. 548 bool fatal_send_error_ = false; 549 550 // True if a fatal processing visitor callback failed. 551 bool fatal_visitor_callback_failure_ = false; 552 }; 553 554 } // namespace adapter 555 } // namespace http2 556 557 #endif // QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_ 558