DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (1aeaa33a64f9)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_net_Http2Session_h
#define mozilla_net_Http2Session_h

// HTTP/2 - RFC 7540
// https://www.rfc-editor.org/rfc/rfc7540.txt

#include "ASpdySession.h"
#include "mozilla/Attributes.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "nsAHttpConnection.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#include "nsDeque.h"
#include "nsHashKeys.h"
#include "nsHttpRequestHead.h"
#include "nsICacheEntryOpenCallback.h"

#include "Http2Compression.h"

class nsISocketTransport;

namespace mozilla {
namespace net {

class Http2PushedStream;
class Http2Stream;
class nsHttpTransaction;

class Http2Session final : public ASpdySession,
                           public nsAHttpConnection,
                           public nsAHttpSegmentReader,
                           public nsAHttpSegmentWriter {
  ~Http2Session();

 public:
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSAHTTPTRANSACTION
  NS_DECL_NSAHTTPCONNECTION(mConnection)
  NS_DECL_NSAHTTPSEGMENTREADER
  NS_DECL_NSAHTTPSEGMENTWRITER

  Http2Session(nsISocketTransport *, uint32_t version,
               bool attemptingEarlyData);

  MOZ_MUST_USE bool AddStream(nsAHttpTransaction *, int32_t, bool,
                              nsIInterfaceRequestor *) override;
  bool CanReuse() override { return !mShouldGoAway && !mClosed; }
  bool RoomForMoreStreams() override;
  uint32_t SpdyVersion() override;
  bool TestJoinConnection(const nsACString &hostname, int32_t port) override;
  bool JoinConnection(const nsACString &hostname, int32_t port) override;

  // When the connection is active this is called up to once every 1 second
  // return the interval (in seconds) that the connection next wants to
  // have this invoked. It might happen sooner depending on the needs of
  // other connections.
  uint32_t ReadTimeoutTick(PRIntervalTime now) override;

  // Idle time represents time since "goodput".. e.g. a data or header frame
  PRIntervalTime IdleTime() override;

  // Registering with a newID of 0 means pick the next available odd ID
  uint32_t RegisterStreamID(Http2Stream *, uint32_t aNewID = 0);

  /*
    HTTP/2 framing

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |         Length (16)           |   Type (8)    |   Flags (8)   |
    +-+-------------+---------------+-------------------------------+
    |R|                 Stream Identifier (31)                      |
    +-+-------------------------------------------------------------+
    |                     Frame Data (0...)                       ...
    +---------------------------------------------------------------+
  */

  enum FrameType {
    FRAME_TYPE_DATA = 0x0,
    FRAME_TYPE_HEADERS = 0x1,
    FRAME_TYPE_PRIORITY = 0x2,
    FRAME_TYPE_RST_STREAM = 0x3,
    FRAME_TYPE_SETTINGS = 0x4,
    FRAME_TYPE_PUSH_PROMISE = 0x5,
    FRAME_TYPE_PING = 0x6,
    FRAME_TYPE_GOAWAY = 0x7,
    FRAME_TYPE_WINDOW_UPDATE = 0x8,
    FRAME_TYPE_CONTINUATION = 0x9,
    FRAME_TYPE_ALTSVC = 0xA,
    FRAME_TYPE_UNUSED = 0xB,
    FRAME_TYPE_ORIGIN = 0xC,
    FRAME_TYPE_LAST = 0xD
  };

  // NO_ERROR is a macro defined on windows, so we'll name the HTTP2 goaway
  // code NO_ERROR to be NO_HTTP_ERROR
  enum errorType {
    NO_HTTP_ERROR = 0,
    PROTOCOL_ERROR = 1,
    INTERNAL_ERROR = 2,
    FLOW_CONTROL_ERROR = 3,
    SETTINGS_TIMEOUT_ERROR = 4,
    STREAM_CLOSED_ERROR = 5,
    FRAME_SIZE_ERROR = 6,
    REFUSED_STREAM_ERROR = 7,
    CANCEL_ERROR = 8,
    COMPRESSION_ERROR = 9,
    CONNECT_ERROR = 10,
    ENHANCE_YOUR_CALM = 11,
    INADEQUATE_SECURITY = 12,
    HTTP_1_1_REQUIRED = 13,
    UNASSIGNED = 31
  };

  // These are frame flags. If they, or other undefined flags, are
  // used on frames other than the comments indicate they MUST be ignored.
  const static uint8_t kFlag_END_STREAM = 0x01;        // data, headers
  const static uint8_t kFlag_END_HEADERS = 0x04;       // headers, continuation
  const static uint8_t kFlag_END_PUSH_PROMISE = 0x04;  // push promise
  const static uint8_t kFlag_ACK = 0x01;               // ping and settings
  const static uint8_t kFlag_PADDED =
      0x08;  // data, headers, push promise, continuation
  const static uint8_t kFlag_PRIORITY = 0x20;  // headers

  enum {
    SETTINGS_TYPE_HEADER_TABLE_SIZE = 1,  // compression table size
    SETTINGS_TYPE_ENABLE_PUSH = 2,        // can be used to disable push
    SETTINGS_TYPE_MAX_CONCURRENT = 3,     // streams recvr allowed to initiate
    SETTINGS_TYPE_INITIAL_WINDOW = 4,     // bytes for flow control default
    SETTINGS_TYPE_MAX_FRAME_SIZE =
        5  // max frame size settings sender allows receipt of
  };

  // This should be big enough to hold all of your control packets,
  // but if it needs to grow for huge headers it can do so dynamically.
  const static uint32_t kDefaultBufferSize = 2048;

  // kDefaultQueueSize must be >= other queue size constants
  const static uint32_t kDefaultQueueSize = 32768;
  const static uint32_t kQueueMinimumCleanup = 24576;
  const static uint32_t kQueueTailRoom = 4096;
  const static uint32_t kQueueReserved = 1024;

  const static uint32_t kMaxStreamID = 0x7800000;

  // This is a sentinel for a deleted stream. It is not a valid
  // 31 bit stream ID.
  const static uint32_t kDeadStreamID = 0xffffdead;

  // below the emergency threshold of local window we ack every received
  // byte. Above that we coalesce bytes into the MinimumToAck size.
  const static int32_t kEmergencyWindowThreshold = 96 * 1024;
  const static uint32_t kMinimumToAck = 4 * 1024 * 1024;

  // The default rwin is 64KB - 1 unless updated by a settings frame
  const static uint32_t kDefaultRwin = 65535;

  // We limit frames to 2^14 bytes of length in order to preserve responsiveness
  // This is the smallest allowed value for SETTINGS_MAX_FRAME_SIZE
  const static uint32_t kMaxFrameData = 0x4000;

  const static uint8_t kFrameLengthBytes = 3;
  const static uint8_t kFrameStreamIDBytes = 4;
  const static uint8_t kFrameFlagBytes = 1;
  const static uint8_t kFrameTypeBytes = 1;
  const static uint8_t kFrameHeaderBytes = kFrameLengthBytes + kFrameFlagBytes +
                                           kFrameTypeBytes +
                                           kFrameStreamIDBytes;

  enum {
    kLeaderGroupID = 0x3,
    kOtherGroupID = 0x5,
    kBackgroundGroupID = 0x7,
    kSpeculativeGroupID = 0x9,
    kFollowerGroupID = 0xB,
    kUrgentStartGroupID = 0xD
    // Hey, you! YES YOU! If you add/remove any groups here, you almost
    // certainly need to change the lookup of the stream/ID hash in
    // Http2Session::OnTransportStatus and |kPriorityGroupCount| below.
    // Yeah, that's right. YOU!
  };
  const static uint8_t kPriorityGroupCount = 6;

  static nsresult RecvHeaders(Http2Session *);
  static nsresult RecvPriority(Http2Session *);
  static nsresult RecvRstStream(Http2Session *);
  static nsresult RecvSettings(Http2Session *);
  static nsresult RecvPushPromise(Http2Session *);
  static nsresult RecvPing(Http2Session *);
  static nsresult RecvGoAway(Http2Session *);
  static nsresult RecvWindowUpdate(Http2Session *);
  static nsresult RecvContinuation(Http2Session *);
  static nsresult RecvAltSvc(Http2Session *);
  static nsresult RecvUnused(Http2Session *);
  static nsresult RecvOrigin(Http2Session *);

  char *EnsureOutputBuffer(uint32_t needed);

  template <typename charType>
  void CreateFrameHeader(charType dest, uint16_t frameLength, uint8_t frameType,
                         uint8_t frameFlags, uint32_t streamID);

  // For writing the data stream to LOG4
  static void LogIO(Http2Session *, Http2Stream *, const char *, const char *,
                    uint32_t);

  // overload of nsAHttpConnection
  void TransactionHasDataToWrite(nsAHttpTransaction *) override;
  void TransactionHasDataToRecv(nsAHttpTransaction *) override;

  // a similar version for Http2Stream
  void TransactionHasDataToWrite(Http2Stream *);

  // an overload of nsAHttpSegementReader
  virtual MOZ_MUST_USE nsresult
  CommitToSegmentSize(uint32_t size, bool forceCommitment) override;
  MOZ_MUST_USE nsresult BufferOutput(const char *, uint32_t, uint32_t *);
  void FlushOutputQueue();
  uint32_t AmountOfOutputBuffered() {
    return mOutputQueueUsed - mOutputQueueSent;
  }

  uint32_t GetServerInitialStreamWindow() { return mServerInitialStreamWindow; }

  MOZ_MUST_USE bool TryToActivate(Http2Stream *stream);
  void ConnectPushedStream(Http2Stream *stream);
  void ConnectSlowConsumer(Http2Stream *stream);

  MOZ_MUST_USE nsresult ConfirmTLSProfile();
  static MOZ_MUST_USE bool ALPNCallback(nsISupports *securityInfo);

  uint64_t Serial() { return mSerial; }

  void PrintDiagnostics(nsCString &log) override;

  // Streams need access to these
  uint32_t SendingChunkSize() { return mSendingChunkSize; }
  uint32_t PushAllowance() { return mPushAllowance; }
  Http2Compressor *Compressor() { return &mCompressor; }
  nsISocketTransport *SocketTransport() { return mSocketTransport; }
  int64_t ServerSessionWindow() { return mServerSessionWindow; }
  void DecrementServerSessionWindow(uint32_t bytes) {
    mServerSessionWindow -= bytes;
  }
  uint32_t InitialRwin() { return mInitialRwin; }

  void SendPing() override;
  MOZ_MUST_USE bool MaybeReTunnel(nsAHttpTransaction *) override;
  bool UseH2Deps() { return mUseH2Deps; }

  // overload of nsAHttpTransaction
  MOZ_MUST_USE nsresult ReadSegmentsAgain(nsAHttpSegmentReader *, uint32_t,
                                          uint32_t *, bool *) final;
  MOZ_MUST_USE nsresult WriteSegmentsAgain(nsAHttpSegmentWriter *, uint32_t,
                                           uint32_t *, bool *) final;
  MOZ_MUST_USE bool Do0RTT() final { return true; }
  MOZ_MUST_USE nsresult Finish0RTT(bool aRestart, bool aAlpnChanged) final;
  void SetFastOpenStatus(uint8_t aStatus) final;

  // For use by an HTTP2Stream
  void Received421(nsHttpConnectionInfo *ci);

  void SendPriorityFrame(uint32_t streamID, uint32_t dependsOn, uint8_t weight);

 private:
  // These internal states do not correspond to the states of the HTTP/2
  // specification
  enum internalStateType {
    BUFFERING_OPENING_SETTINGS,
    BUFFERING_FRAME_HEADER,
    BUFFERING_CONTROL_FRAME,
    PROCESSING_DATA_FRAME_PADDING_CONTROL,
    PROCESSING_DATA_FRAME,
    DISCARDING_DATA_FRAME_PADDING,
    DISCARDING_DATA_FRAME,
    PROCESSING_COMPLETE_HEADERS,
    PROCESSING_CONTROL_RST_STREAM,
    NOT_USING_NETWORK
  };

  static const uint8_t kMagicHello[24];

  MOZ_MUST_USE nsresult ResponseHeadersComplete();
  uint32_t GetWriteQueueSize();
  void ChangeDownstreamState(enum internalStateType);
  void ResetDownstreamState();
  MOZ_MUST_USE nsresult ReadyToProcessDataFrame(enum internalStateType);
  MOZ_MUST_USE nsresult UncompressAndDiscard(bool);
  void GeneratePing(bool);
  void GenerateSettingsAck();
  void GeneratePriority(uint32_t, uint8_t);
  void GenerateRstStream(uint32_t, uint32_t);
  void GenerateGoAway(uint32_t);
  void CleanupStream(Http2Stream *, nsresult, errorType);
  void CleanupStream(uint32_t, nsresult, errorType);
  void CloseStream(Http2Stream *, nsresult);
  void SendHello();
  void RemoveStreamFromQueues(Http2Stream *);
  MOZ_MUST_USE nsresult ParsePadding(uint8_t &, uint16_t &);

  void SetWriteCallbacks();
  void RealignOutputQueue();

  void ProcessPending();
  MOZ_MUST_USE nsresult ProcessConnectedPush(Http2Stream *,
                                             nsAHttpSegmentWriter *, uint32_t,
                                             uint32_t *);
  MOZ_MUST_USE nsresult ProcessSlowConsumer(Http2Stream *,
                                            nsAHttpSegmentWriter *, uint32_t,
                                            uint32_t *);

  MOZ_MUST_USE nsresult SetInputFrameDataStream(uint32_t);
  void CreatePriorityNode(uint32_t, uint32_t, uint8_t, const char *);
  char *CreatePriorityFrame(uint32_t, uint32_t, uint8_t);
  bool VerifyStream(Http2Stream *, uint32_t);
  void SetNeedsCleanup();

  void UpdateLocalRwin(Http2Stream *stream, uint32_t bytes);
  void UpdateLocalStreamWindow(Http2Stream *stream, uint32_t bytes);
  void UpdateLocalSessionWindow(uint32_t bytes);

  void MaybeDecrementConcurrent(Http2Stream *stream);
  bool RoomForMoreConcurrent();
  void IncrementConcurrent(Http2Stream *stream);
  void QueueStream(Http2Stream *stream);

  // a wrapper for all calls to the nshttpconnection level segment writer. Used
  // to track network I/O for timeout purposes
  MOZ_MUST_USE nsresult NetworkRead(nsAHttpSegmentWriter *, char *, uint32_t,
                                    uint32_t *);

  void Shutdown();

  // This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
  // from the first transaction on this session. That object contains the
  // pointer to the real network-level nsHttpConnection object.
  RefPtr<nsAHttpConnection> mConnection;

  // The underlying socket transport object is needed to propogate some events
  nsISocketTransport *mSocketTransport;

  // These are temporary state variables to hold the argument to
  // Read/WriteSegments so it can be accessed by On(read/write)segment
  // further up the stack.
  nsAHttpSegmentReader *mSegmentReader;
  nsAHttpSegmentWriter *mSegmentWriter;

  uint32_t mSendingChunkSize; /* the transmission chunk size */
  uint32_t mNextStreamID;     /* 24 bits */
  uint32_t mLastPushedID;
  uint32_t mConcurrentHighWater; /* max parallelism on session */
  uint32_t mPushAllowance;       /* rwin for unmatched pushes */

  internalStateType mDownstreamState; /* in frame, between frames, etc..  */

  // Maintain 2 indexes - one by stream ID, one by transaction pointer.
  // There are also several lists of streams: ready to write, queued due to
  // max parallelism, streams that need to force a read for push, and the full
  // set of pushed streams.
  // The objects are not ref counted - they get destroyed
  // by the nsClassHashtable implementation when they are removed from
  // the transaction hash.
  nsDataHashtable<nsUint32HashKey, Http2Stream *> mStreamIDHash;
  nsClassHashtable<nsPtrHashKey<nsAHttpTransaction>, Http2Stream>
      mStreamTransactionHash;

  nsDeque mReadyForWrite;
  nsDeque mQueuedStreams;
  nsDeque mPushesReadyForRead;
  nsDeque mSlowConsumersReadyForRead;
  nsTArray<Http2PushedStream *> mPushedStreams;

  // Compression contexts for header transport.
  // HTTP/2 compresses only HTTP headers and does not reset the context in
  // between frames. Even data that is not associated with a stream (e.g invalid
  // stream ID) is passed through these contexts to keep the compression
  // context correct.
  Http2Compressor mCompressor;
  Http2Decompressor mDecompressor;
  nsCString mDecompressBuffer;

  // mInputFrameBuffer is used to store received control packets and the 8 bytes
  // of header on data packets
  uint32_t mInputFrameBufferSize;  // buffer allocation
  uint32_t mInputFrameBufferUsed;  // amt of allocation used
  UniquePtr<char[]> mInputFrameBuffer;

  // mInputFrameDataSize/Read are used for tracking the amount of data consumed
  // in a frame after the 8 byte header. Control frames are always fully
  // buffered and the fixed 8 byte leading header is at mInputFrameBuffer + 0,
  // the first data byte (i.e. the first settings/goaway/etc.. specific byte) is
  // at mInputFrameBuffer + 8 The frame size is mInputFrameDataSize + the
  // constant 8 byte header
  uint32_t mInputFrameDataSize;
  uint32_t mInputFrameDataRead;
  bool mInputFrameFinal;  // This frame was marked FIN
  uint8_t mInputFrameType;
  uint8_t mInputFrameFlags;
  uint32_t mInputFrameID;
  uint16_t mPaddingLength;

  // When a frame has been received that is addressed to a particular stream
  // (e.g. a data frame after the stream-id has been decoded), this points
  // to the stream.
  Http2Stream *mInputFrameDataStream;

  // mNeedsCleanup is a state variable to defer cleanup of a closed stream
  // If needed, It is set in session::OnWriteSegments() and acted on and
  // cleared when the stack returns to session::WriteSegments(). The stream
  // cannot be destroyed directly out of OnWriteSegments because
  // stream::writeSegments() is on the stack at that time.
  Http2Stream *mNeedsCleanup;

  // This reason code in the last processed RESET frame
  uint32_t mDownstreamRstReason;

  // When HEADERS/PROMISE are chained together, this is the expected ID of the
  // next recvd frame which must be the same type
  uint32_t mExpectedHeaderID;
  uint32_t mExpectedPushPromiseID;
  uint32_t mContinuedPromiseStream;

  // for the conversion of downstream http headers into http/2 formatted headers
  // The data here does not persist between frames
  nsCString mFlatHTTPResponseHeaders;
  uint32_t mFlatHTTPResponseHeadersOut;

  // when set, the session will go away when it reaches 0 streams. This flag
  // is set when: the stream IDs are running out (at either the client or the
  // server), when DontReuse() is called, a RST that is not specific to a
  // particular stream is received, a GOAWAY frame has been received from
  // the server.
  bool mShouldGoAway;

  // the session has received a nsAHttpTransaction::Close()  call
  bool mClosed;

  // the session received a GoAway frame with a valid GoAwayID
  bool mCleanShutdown;

  // the session received the opening SETTINGS frame from the server
  bool mReceivedSettings;

  // The TLS comlpiance checks are not done in the ctor beacuse of bad
  // exception handling - so we do them at IO time and cache the result
  bool mTLSProfileConfirmed;

  // A specifc reason code for the eventual GoAway frame. If set to
  // NO_HTTP_ERROR only NO_HTTP_ERROR, PROTOCOL_ERROR, or INTERNAL_ERROR will be
  // sent.
  errorType mGoAwayReason;

  // The error code sent/received on the session goaway frame. UNASSIGNED/31
  // if not transmitted.
  int32_t mClientGoAwayReason;
  int32_t mPeerGoAwayReason;

  // If a GoAway message was received this is the ID of the last valid
  // stream. 0 otherwise. (0 is never a valid stream id.)
  uint32_t mGoAwayID;

  // The last stream processed ID we will send in our GoAway frame.
  uint32_t mOutgoingGoAwayID;

  // The limit on number of concurrent streams for this session. Normally it
  // is basically unlimited, but the SETTINGS control message from the
  // server might bring it down.
  uint32_t mMaxConcurrent;

  // The actual number of concurrent streams at this moment. Generally below
  // mMaxConcurrent, but the max can be lowered in real time to a value
  // below the current value
  uint32_t mConcurrent;

  // The number of server initiated promises, tracked for telemetry
  uint32_t mServerPushedResources;

  // The server rwin for new streams as determined from a SETTINGS frame
  uint32_t mServerInitialStreamWindow;

  // The Local Session window is how much data the server is allowed to send
  // (across all streams) without getting a window update to stream 0. It is
  // signed because asynchronous changes via SETTINGS can drive it negative.
  int64_t mLocalSessionWindow;

  // The Remote Session Window is how much data the client is allowed to send
  // (across all streams) without receiving a window update to stream 0. It is
  // signed because asynchronous changes via SETTINGS can drive it negative.
  int64_t mServerSessionWindow;

  // The initial value of the local stream and session window
  uint32_t mInitialRwin;

  // This is a output queue of bytes ready to be written to the SSL stream.
  // When that streams returns WOULD_BLOCK on direct write the bytes get
  // coalesced together here. This results in larger writes to the SSL layer.
  // The buffer is not dynamically grown to accomodate stream writes, but
  // does expand to accept infallible session wide frames like GoAway and RST.
  uint32_t mOutputQueueSize;
  uint32_t mOutputQueueUsed;
  uint32_t mOutputQueueSent;
  UniquePtr<char[]> mOutputQueueBuffer;

  PRIntervalTime mPingThreshold;
  PRIntervalTime mLastReadEpoch;      // used for ping timeouts
  PRIntervalTime mLastDataReadEpoch;  // used for IdleTime()
  PRIntervalTime mPingSentEpoch;

  PRIntervalTime mPreviousPingThreshold;  // backup for the former value
  bool mPreviousUsed;                     // true when backup is used

  // used as a temporary buffer while enumerating the stream hash during GoAway
  nsDeque mGoAwayStreamsToRestart;

  // Each session gets a unique serial number because the push cache is
  // correlated by the load group and the serial number can be used as part of
  // the cache key to make sure streams aren't shared across sessions.
  uint64_t mSerial;

  // Telemetry for continued headers (pushed and pulled) for quic design
  uint32_t mAggregatedHeaderSize;

  // If push is disabled, we want to be able to send PROTOCOL_ERRORs if we
  // receive a PUSH_PROMISE, but we have to wait for the SETTINGS ACK before
  // we can actually tell the other end to go away. These help us keep track
  // of that state so we can behave appropriately.
  bool mWaitingForSettingsAck;
  bool mGoAwayOnPush;

  bool mUseH2Deps;

  bool mAttemptingEarlyData;
  // The ID(s) of the stream(s) that we are getting 0RTT data from.
  nsTArray<WeakPtr<Http2Stream>> m0RTTStreams;
  // The ID(s) of the stream(s) that are not able to send 0RTT data. We need to
  // remember them put them into mReadyForWrite queue when 0RTT finishes.
  nsTArray<WeakPtr<Http2Stream>> mCannotDo0RTTStreams;

  bool RealJoinConnection(const nsACString &hostname, int32_t port, bool jk);
  bool TestOriginFrame(const nsACString &name, int32_t port);
  bool mOriginFrameActivated;
  nsDataHashtable<nsCStringHashKey, bool> mOriginFrame;

  nsDataHashtable<nsCStringHashKey, bool> mJoinConnectionCache;

  uint64_t mCurrentForegroundTabOuterContentWindowId;

  class CachePushCheckCallback final : public nsICacheEntryOpenCallback {
   public:
    CachePushCheckCallback(Http2Session *session, uint32_t promisedID,
                           const nsACString &requestString);

    NS_DECL_ISUPPORTS
    NS_DECL_NSICACHEENTRYOPENCALLBACK

   private:
    ~CachePushCheckCallback() {}

    RefPtr<Http2Session> mSession;
    uint32_t mPromisedID;
    nsHttpRequestHead mRequestHead;
  };

  // A h2 session will be created before all socket events are trigered,
  // e.g. NS_NET_STATUS_TLS_HANDSHAKE_ENDED and for TFO many others.
  // We should propagate this events to the first nsHttpTransaction.
  RefPtr<nsHttpTransaction> mFirstHttpTransaction;
  bool mTlsHandshakeFinished;

  bool mCheckNetworkStallsWithTFO;
  PRIntervalTime mLastRequestBytesSentTime;

 private:
  /// connect tunnels
  void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
  void CreateTunnel(nsHttpTransaction *, nsHttpConnectionInfo *,
                    nsIInterfaceRequestor *);
  void RegisterTunnel(Http2Stream *);
  void UnRegisterTunnel(Http2Stream *);
  uint32_t FindTunnelCount(nsHttpConnectionInfo *);
  nsDataHashtable<nsCStringHashKey, uint32_t> mTunnelHash;
};

}  // namespace net
}  // namespace mozilla

#endif  // mozilla_net_Http2Session_h