netwerk/protocol/http/Http2Session.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef mozilla_net_Http2Session_h
     7 #define mozilla_net_Http2Session_h
     9 // HTTP/2
    11 #include "ASpdySession.h"
    12 #include "mozilla/Attributes.h"
    13 #include "nsAHttpConnection.h"
    14 #include "nsClassHashtable.h"
    15 #include "nsDataHashtable.h"
    16 #include "nsDeque.h"
    17 #include "nsHashKeys.h"
    19 #include "Http2Compression.h"
    21 class nsISocketTransport;
    23 namespace mozilla {
    24 namespace net {
    26 class Http2PushedStream;
    27 class Http2Stream;
    29 class Http2Session MOZ_FINAL : public ASpdySession
    30   , public nsAHttpConnection
    31   , public nsAHttpSegmentReader
    32   , public nsAHttpSegmentWriter
    33 {
    34 public:
    35   NS_DECL_ISUPPORTS
    36     NS_DECL_NSAHTTPTRANSACTION
    37     NS_DECL_NSAHTTPCONNECTION(mConnection)
    38     NS_DECL_NSAHTTPSEGMENTREADER
    39     NS_DECL_NSAHTTPSEGMENTWRITER
    41    Http2Session(nsAHttpTransaction *, nsISocketTransport *, int32_t);
    42   ~Http2Session();
    44   bool AddStream(nsAHttpTransaction *, int32_t);
    45   bool CanReuse() { return !mShouldGoAway && !mClosed; }
    46   bool RoomForMoreStreams();
    48   // When the connection is active this is called up to once every 1 second
    49   // return the interval (in seconds) that the connection next wants to
    50   // have this invoked. It might happen sooner depending on the needs of
    51   // other connections.
    52   uint32_t  ReadTimeoutTick(PRIntervalTime now);
    54   // Idle time represents time since "goodput".. e.g. a data or header frame
    55   PRIntervalTime IdleTime();
    57   // Registering with a newID of 0 means pick the next available odd ID
    58   uint32_t RegisterStreamID(Http2Stream *, uint32_t aNewID = 0);
    60 /*
    61   HTTP/2 framing
    63   0                   1                   2                   3
    64   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
    65   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    66   |         Length (16)           |   Type (8)    |   Flags (8)   |
    67   +-+-------------+---------------+-------------------------------+
    68   |R|                 Stream Identifier (31)                      |
    69   +-+-------------------------------------------------------------+
    70   |                     Frame Data (0...)                       ...
    71   +---------------------------------------------------------------+
    72 */
    74   enum frameType {
    75     FRAME_TYPE_DATA = 0,
    76     FRAME_TYPE_HEADERS = 1,
    77     FRAME_TYPE_PRIORITY = 2,
    78     FRAME_TYPE_RST_STREAM = 3,
    79     FRAME_TYPE_SETTINGS = 4,
    80     FRAME_TYPE_PUSH_PROMISE = 5,
    81     FRAME_TYPE_PING = 6,
    82     FRAME_TYPE_GOAWAY = 7,
    83     FRAME_TYPE_WINDOW_UPDATE = 8,
    84     FRAME_TYPE_CONTINUATION = 9,
    85     FRAME_TYPE_LAST = 10
    86   };
    88   // NO_ERROR is a macro defined on windows, so we'll name the HTTP2 goaway
    89   // code NO_ERROR to be NO_HTTP_ERROR
    90   enum errorType {
    91     NO_HTTP_ERROR = 0,
    92     PROTOCOL_ERROR = 1,
    93     INTERNAL_ERROR = 2,
    94     FLOW_CONTROL_ERROR = 3,
    95     SETTINGS_TIMEOUT_ERROR = 4,
    96     STREAM_CLOSED_ERROR = 5,
    97     FRAME_SIZE_ERROR = 6,
    98     REFUSED_STREAM_ERROR = 7,
    99     CANCEL_ERROR = 8,
   100     COMPRESSION_ERROR = 9,
   101     CONNECT_ERROR = 10,
   102     ENHANCE_YOUR_CALM = 11,
   103     INADEQUATE_SECURITY = 12
   104   };
   106   // These are frame flags. If they, or other undefined flags, are
   107   // used on frames other than the comments indicate they MUST be ignored.
   108   const static uint8_t kFlag_END_STREAM = 0x01; // data, headers
   109   const static uint8_t kFlag_END_HEADERS = 0x04; // headers, continuation
   110   const static uint8_t kFlag_PRIORITY = 0x08; //headers
   111   const static uint8_t kFlag_END_PUSH_PROMISE = 0x04; // push promise
   112   const static uint8_t kFlag_ACK = 0x01; // ping and settings
   113   const static uint8_t kFlag_END_SEGMENT = 0x02; // data
   114   const static uint8_t kFlag_PAD_LOW = 0x10; // data, headers, continuation
   115   const static uint8_t kFlag_PAD_HIGH = 0x20; // data, headers, continuation
   117   enum {
   118     SETTINGS_TYPE_HEADER_TABLE_SIZE = 1, // compression table size
   119     SETTINGS_TYPE_ENABLE_PUSH = 2,     // can be used to disable push
   120     SETTINGS_TYPE_MAX_CONCURRENT = 3,  // streams recvr allowed to initiate
   121     SETTINGS_TYPE_INITIAL_WINDOW = 4  // bytes for flow control default
   122   };
   124   // This should be big enough to hold all of your control packets,
   125   // but if it needs to grow for huge headers it can do so dynamically.
   126   const static uint32_t kDefaultBufferSize = 2048;
   128   // kDefaultQueueSize must be >= other queue size constants
   129   const static uint32_t kDefaultQueueSize =  32768;
   130   const static uint32_t kQueueMinimumCleanup = 24576;
   131   const static uint32_t kQueueTailRoom    =  4096;
   132   const static uint32_t kQueueReserved    =  1024;
   134   const static uint32_t kDefaultMaxConcurrent = 100;
   135   const static uint32_t kMaxStreamID = 0x7800000;
   137   // This is a sentinel for a deleted stream. It is not a valid
   138   // 31 bit stream ID.
   139   const static uint32_t kDeadStreamID = 0xffffdead;
   141   // below the emergency threshold of local window we ack every received
   142   // byte. Above that we coalesce bytes into the MinimumToAck size.
   143   const static int32_t  kEmergencyWindowThreshold = 256 * 1024;
   144   const static uint32_t kMinimumToAck = 4 * 1024 * 1024;
   146   // The default rwin is 64KB - 1 unless updated by a settings frame
   147   const static uint32_t kDefaultRwin = 65535;
   149   // Frames with HTTP semantics are limited to 2^14 - 1 bytes of length in
   150   // order to preserve responsiveness
   151   const static uint32_t kMaxFrameData = 16383;
   153   static nsresult RecvHeaders(Http2Session *);
   154   static nsresult RecvPriority(Http2Session *);
   155   static nsresult RecvRstStream(Http2Session *);
   156   static nsresult RecvSettings(Http2Session *);
   157   static nsresult RecvPushPromise(Http2Session *);
   158   static nsresult RecvPing(Http2Session *);
   159   static nsresult RecvGoAway(Http2Session *);
   160   static nsresult RecvWindowUpdate(Http2Session *);
   161   static nsresult RecvContinuation(Http2Session *);
   163   template<typename T>
   164   static void EnsureBuffer(nsAutoArrayPtr<T> &,
   165                            uint32_t, uint32_t, uint32_t &);
   166   char       *EnsureOutputBuffer(uint32_t needed);
   168   template<typename charType>
   169   void CreateFrameHeader(charType dest, uint16_t frameLength,
   170                          uint8_t frameType, uint8_t frameFlags,
   171                          uint32_t streamID);
   173   // For writing the data stream to LOG4
   174   static void LogIO(Http2Session *, Http2Stream *, const char *,
   175                     const char *, uint32_t);
   177   // an overload of nsAHttpConnection
   178   void TransactionHasDataToWrite(nsAHttpTransaction *);
   180   // a similar version for Http2Stream
   181   void TransactionHasDataToWrite(Http2Stream *);
   183   // an overload of nsAHttpSegementReader
   184   virtual nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment);
   185   nsresult BufferOutput(const char *, uint32_t, uint32_t *);
   186   void     FlushOutputQueue();
   187   uint32_t AmountOfOutputBuffered() { return mOutputQueueUsed - mOutputQueueSent; }
   189   uint32_t GetServerInitialStreamWindow() { return mServerInitialStreamWindow; }
   191   void ConnectPushedStream(Http2Stream *stream);
   192   void MaybeDecrementConcurrent(Http2Stream *stream);
   194   nsresult ConfirmTLSProfile();
   196   uint64_t Serial() { return mSerial; }
   198   void PrintDiagnostics (nsCString &log);
   200   // Streams need access to these
   201   uint32_t SendingChunkSize() { return mSendingChunkSize; }
   202   uint32_t PushAllowance() { return mPushAllowance; }
   203   Http2Compressor *Compressor() { return &mCompressor; }
   204   nsISocketTransport *SocketTransport() { return mSocketTransport; }
   205   int64_t ServerSessionWindow() { return mServerSessionWindow; }
   206   void DecrementServerSessionWindow (uint32_t bytes) { mServerSessionWindow -= bytes; }
   208 private:
   210   // These internal states do not correspond to the states of the HTTP/2 specification
   211   enum internalStateType {
   212     BUFFERING_OPENING_SETTINGS,
   213     BUFFERING_FRAME_HEADER,
   214     BUFFERING_CONTROL_FRAME,
   215     PROCESSING_DATA_FRAME_PADDING_CONTROL,
   216     PROCESSING_DATA_FRAME,
   217     DISCARDING_DATA_FRAME_PADDING,
   218     DISCARDING_DATA_FRAME,
   219     PROCESSING_COMPLETE_HEADERS,
   220     PROCESSING_CONTROL_RST_STREAM
   221   };
   223   static const uint8_t kMagicHello[24];
   225   nsresult    ResponseHeadersComplete();
   226   uint32_t    GetWriteQueueSize();
   227   void        ChangeDownstreamState(enum internalStateType);
   228   void        ResetDownstreamState();
   229   nsresult    ReadyToProcessDataFrame(enum internalStateType);
   230   nsresult    UncompressAndDiscard();
   231   void        GeneratePing(bool);
   232   void        GenerateSettingsAck();
   233   void        GeneratePriority(uint32_t, uint32_t);
   234   void        GenerateRstStream(uint32_t, uint32_t);
   235   void        GenerateGoAway(uint32_t);
   236   void        CleanupStream(Http2Stream *, nsresult, errorType);
   237   void        CloseStream(Http2Stream *, nsresult);
   238   void        SendHello();
   239   void        RemoveStreamFromQueues(Http2Stream *);
   240   nsresult    ParsePadding(uint8_t &, uint16_t &);
   242   void        SetWriteCallbacks();
   243   void        RealignOutputQueue();
   245   bool        RoomForMoreConcurrent();
   246   void        ActivateStream(Http2Stream *);
   247   void        ProcessPending();
   248   nsresult    SetInputFrameDataStream(uint32_t);
   249   bool        VerifyStream(Http2Stream *, uint32_t);
   250   void        SetNeedsCleanup();
   252   void        UpdateLocalRwin(Http2Stream *stream, uint32_t bytes);
   253   void        UpdateLocalStreamWindow(Http2Stream *stream, uint32_t bytes);
   254   void        UpdateLocalSessionWindow(uint32_t bytes);
   256   // a wrapper for all calls to the nshttpconnection level segment writer. Used
   257   // to track network I/O for timeout purposes
   258   nsresult   NetworkRead(nsAHttpSegmentWriter *, char *, uint32_t, uint32_t *);
   260   static PLDHashOperator ShutdownEnumerator(nsAHttpTransaction *,
   261                                             nsAutoPtr<Http2Stream> &,
   262                                             void *);
   264   static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
   265                                           nsAutoPtr<Http2Stream> &,
   266                                           void *);
   268   static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
   269                                                     nsAutoPtr<Http2Stream> &,
   270                                                     void *);
   272   static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
   273                                                         nsAutoPtr<Http2Stream> &,
   274                                                         void *);
   276   // This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
   277   // from the first transaction on this session. That object contains the
   278   // pointer to the real network-level nsHttpConnection object.
   279   nsRefPtr<nsAHttpConnection> mConnection;
   281   // The underlying socket transport object is needed to propogate some events
   282   nsISocketTransport         *mSocketTransport;
   284   // These are temporary state variables to hold the argument to
   285   // Read/WriteSegments so it can be accessed by On(read/write)segment
   286   // further up the stack.
   287   nsAHttpSegmentReader       *mSegmentReader;
   288   nsAHttpSegmentWriter       *mSegmentWriter;
   290   uint32_t          mSendingChunkSize;        /* the transmission chunk size */
   291   uint32_t          mNextStreamID;            /* 24 bits */
   292   uint32_t          mConcurrentHighWater;     /* max parallelism on session */
   293   uint32_t          mPushAllowance;           /* rwin for unmatched pushes */
   295   internalStateType mDownstreamState; /* in frame, between frames, etc..  */
   297   // Maintain 2 indexes - one by stream ID, one by transaction pointer.
   298   // There are also several lists of streams: ready to write, queued due to
   299   // max parallelism, streams that need to force a read for push, and the full
   300   // set of pushed streams.
   301   // The objects are not ref counted - they get destroyed
   302   // by the nsClassHashtable implementation when they are removed from
   303   // the transaction hash.
   304   nsDataHashtable<nsUint32HashKey, Http2Stream *>     mStreamIDHash;
   305   nsClassHashtable<nsPtrHashKey<nsAHttpTransaction>,
   306     Http2Stream>                                      mStreamTransactionHash;
   308   nsDeque                                             mReadyForWrite;
   309   nsDeque                                             mQueuedStreams;
   310   nsDeque                                             mReadyForRead;
   311   nsTArray<Http2PushedStream *>                       mPushedStreams;
   313   // Compression contexts for header transport.
   314   // HTTP/2 compresses only HTTP headers and does not reset the context in between
   315   // frames. Even data that is not associated with a stream (e.g invalid
   316   // stream ID) is passed through these contexts to keep the compression
   317   // context correct.
   318   Http2Compressor     mCompressor;
   319   Http2Decompressor   mDecompressor;
   320   nsCString           mDecompressBuffer;
   322   // mInputFrameBuffer is used to store received control packets and the 8 bytes
   323   // of header on data packets
   324   uint32_t             mInputFrameBufferSize; // buffer allocation
   325   uint32_t             mInputFrameBufferUsed; // amt of allocation used
   326   nsAutoArrayPtr<char> mInputFrameBuffer;
   328   // mInputFrameDataSize/Read are used for tracking the amount of data consumed
   329   // in a frame after the 8 byte header. Control frames are always fully buffered
   330   // and the fixed 8 byte leading header is at mInputFrameBuffer + 0, the first
   331   // data byte (i.e. the first settings/goaway/etc.. specific byte) is at
   332   // mInputFrameBuffer + 8
   333   // The frame size is mInputFrameDataSize + the constant 8 byte header
   334   uint32_t             mInputFrameDataSize;
   335   uint32_t             mInputFrameDataRead;
   336   bool                 mInputFrameFinal; // This frame was marked FIN
   337   uint8_t              mInputFrameType;
   338   uint8_t              mInputFrameFlags;
   339   uint32_t             mInputFrameID;
   340   uint16_t             mPaddingLength;
   342   // When a frame has been received that is addressed to a particular stream
   343   // (e.g. a data frame after the stream-id has been decoded), this points
   344   // to the stream.
   345   Http2Stream          *mInputFrameDataStream;
   347   // mNeedsCleanup is a state variable to defer cleanup of a closed stream
   348   // If needed, It is set in session::OnWriteSegments() and acted on and
   349   // cleared when the stack returns to session::WriteSegments(). The stream
   350   // cannot be destroyed directly out of OnWriteSegments because
   351   // stream::writeSegments() is on the stack at that time.
   352   Http2Stream          *mNeedsCleanup;
   354   // This reason code in the last processed RESET frame
   355   uint32_t             mDownstreamRstReason;
   357   // When HEADERS/PROMISE are chained together, this is the expected ID of the next
   358   // recvd frame which must be the same type
   359   uint32_t             mExpectedHeaderID;
   360   uint32_t             mExpectedPushPromiseID;
   361   uint32_t             mContinuedPromiseStream;
   363   // for the conversion of downstream http headers into http/2 formatted headers
   364   // The data here does not persist between frames
   365   nsCString            mFlatHTTPResponseHeaders;
   366   uint32_t             mFlatHTTPResponseHeadersOut;
   368   // when set, the session will go away when it reaches 0 streams. This flag
   369   // is set when: the stream IDs are running out (at either the client or the
   370   // server), when DontReuse() is called, a RST that is not specific to a
   371   // particular stream is received, a GOAWAY frame has been received from
   372   // the server.
   373   bool                 mShouldGoAway;
   375   // the session has received a nsAHttpTransaction::Close()  call
   376   bool                 mClosed;
   378   // the session received a GoAway frame with a valid GoAwayID
   379   bool                 mCleanShutdown;
   381   // The TLS comlpiance checks are not done in the ctor beacuse of bad
   382   // exception handling - so we do them at IO time and cache the result
   383   bool                 mTLSProfileConfirmed;
   385   // A specifc reason code for the eventual GoAway frame. If set to NO_HTTP_ERROR
   386   // only NO_HTTP_ERROR, PROTOCOL_ERROR, or INTERNAL_ERROR will be sent.
   387   errorType            mGoAwayReason;
   389   // If a GoAway message was received this is the ID of the last valid
   390   // stream. 0 otherwise. (0 is never a valid stream id.)
   391   uint32_t             mGoAwayID;
   393   // The last stream processed ID we will send in our GoAway frame.
   394   uint32_t             mOutgoingGoAwayID;
   396   // The limit on number of concurrent streams for this session. Normally it
   397   // is basically unlimited, but the SETTINGS control message from the
   398   // server might bring it down.
   399   uint32_t             mMaxConcurrent;
   401   // The actual number of concurrent streams at this moment. Generally below
   402   // mMaxConcurrent, but the max can be lowered in real time to a value
   403   // below the current value
   404   uint32_t             mConcurrent;
   406   // The number of server initiated promises, tracked for telemetry
   407   uint32_t             mServerPushedResources;
   409   // The server rwin for new streams as determined from a SETTINGS frame
   410   uint32_t             mServerInitialStreamWindow;
   412   // The Local Session window is how much data the server is allowed to send
   413   // (across all streams) without getting a window update to stream 0. It is
   414   // signed because asynchronous changes via SETTINGS can drive it negative.
   415   int64_t              mLocalSessionWindow;
   417   // The Remote Session Window is how much data the client is allowed to send
   418   // (across all streams) without receiving a window update to stream 0. It is
   419   // signed because asynchronous changes via SETTINGS can drive it negative.
   420   int64_t              mServerSessionWindow;
   422   // This is a output queue of bytes ready to be written to the SSL stream.
   423   // When that streams returns WOULD_BLOCK on direct write the bytes get
   424   // coalesced together here. This results in larger writes to the SSL layer.
   425   // The buffer is not dynamically grown to accomodate stream writes, but
   426   // does expand to accept infallible session wide frames like GoAway and RST.
   427   uint32_t             mOutputQueueSize;
   428   uint32_t             mOutputQueueUsed;
   429   uint32_t             mOutputQueueSent;
   430   nsAutoArrayPtr<char> mOutputQueueBuffer;
   432   PRIntervalTime       mPingThreshold;
   433   PRIntervalTime       mLastReadEpoch;     // used for ping timeouts
   434   PRIntervalTime       mLastDataReadEpoch; // used for IdleTime()
   435   PRIntervalTime       mPingSentEpoch;
   437   // used as a temporary buffer while enumerating the stream hash during GoAway
   438   nsDeque  mGoAwayStreamsToRestart;
   440   // Each session gets a unique serial number because the push cache is correlated
   441   // by the load group and the serial number can be used as part of the cache key
   442   // to make sure streams aren't shared across sessions.
   443   uint64_t        mSerial;
   444 };
   446 } // namespace mozilla::net
   447 } // namespace mozilla
   449 #endif // mozilla_net_Http2Session_h

mercurial