netwerk/protocol/http/SpdySession31.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_SpdySession31_h
     7 #define mozilla_net_SpdySession31_h
     9 // spdy/3.1
    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"
    18 #include "zlib.h"
    20 class nsISocketTransport;
    22 namespace mozilla { namespace net {
    24 class SpdyPushedStream31;
    25 class SpdyStream31;
    27 class SpdySession31 MOZ_FINAL : public ASpdySession
    28   , public nsAHttpConnection
    29   , public nsAHttpSegmentReader
    30   , public nsAHttpSegmentWriter
    31 {
    32 public:
    33   NS_DECL_ISUPPORTS
    34   NS_DECL_NSAHTTPTRANSACTION
    35   NS_DECL_NSAHTTPCONNECTION(mConnection)
    36   NS_DECL_NSAHTTPSEGMENTREADER
    37   NS_DECL_NSAHTTPSEGMENTWRITER
    39   SpdySession31(nsAHttpTransaction *, nsISocketTransport *, int32_t);
    40   ~SpdySession31();
    42   bool AddStream(nsAHttpTransaction *, int32_t);
    43   bool CanReuse() { return !mShouldGoAway && !mClosed; }
    44   bool RoomForMoreStreams();
    46   // When the connection is active this is called up to once every 1 second
    47   // return the interval (in seconds) that the connection next wants to
    48   // have this invoked. It might happen sooner depending on the needs of
    49   // other connections.
    50   uint32_t  ReadTimeoutTick(PRIntervalTime now);
    52   // Idle time represents time since "goodput".. e.g. a data or header frame
    53   PRIntervalTime IdleTime();
    55   // Registering with a newID of 0 means pick the next available odd ID
    56   uint32_t RegisterStreamID(SpdyStream31 *, uint32_t aNewID = 0);
    58   const static uint8_t kVersion        = 3;
    60   const static uint8_t kFlag_Control   = 0x80;
    62   const static uint8_t kFlag_Data_FIN  = 0x01;
    63   const static uint8_t kFlag_Data_UNI  = 0x02;
    65   enum
    66   {
    67     CONTROL_TYPE_FIRST = 0,
    68     CONTROL_TYPE_SYN_STREAM = 1,
    69     CONTROL_TYPE_SYN_REPLY = 2,
    70     CONTROL_TYPE_RST_STREAM = 3,
    71     CONTROL_TYPE_SETTINGS = 4,
    72     CONTROL_TYPE_NOOP = 5,                        /* deprecated */
    73     CONTROL_TYPE_PING = 6,
    74     CONTROL_TYPE_GOAWAY = 7,
    75     CONTROL_TYPE_HEADERS = 8,
    76     CONTROL_TYPE_WINDOW_UPDATE = 9,
    77     CONTROL_TYPE_CREDENTIAL = 10,
    78     CONTROL_TYPE_LAST = 11
    79   };
    81   enum rstReason
    82   {
    83     RST_PROTOCOL_ERROR = 1,
    84     RST_INVALID_STREAM = 2,
    85     RST_REFUSED_STREAM = 3,
    86     RST_UNSUPPORTED_VERSION = 4,
    87     RST_CANCEL = 5,
    88     RST_INTERNAL_ERROR = 6,
    89     RST_FLOW_CONTROL_ERROR = 7,
    90     RST_STREAM_IN_USE = 8,
    91     RST_STREAM_ALREADY_CLOSED = 9,
    92     RST_INVALID_CREDENTIALS = 10,
    93     RST_FRAME_TOO_LARGE = 11
    94   };
    96   enum goawayReason
    97   {
    98     OK = 0,
    99     PROTOCOL_ERROR = 1,
   100     INTERNAL_ERROR = 2,    // sometimes misdocumented as 11
   101     NUM_STATUS_CODES = 3   // reserved by chromium but undocumented
   102   };
   104   enum settingsFlags
   105   {
   106     PERSIST_VALUE = 1,
   107     PERSISTED_VALUE = 2
   108   };
   110   enum
   111   {
   112     SETTINGS_TYPE_UPLOAD_BW = 1, // kb/s
   113     SETTINGS_TYPE_DOWNLOAD_BW = 2, // kb/s
   114     SETTINGS_TYPE_RTT = 3, // ms
   115     SETTINGS_TYPE_MAX_CONCURRENT = 4, // streams
   116     SETTINGS_TYPE_CWND = 5, // packets
   117     SETTINGS_TYPE_DOWNLOAD_RETRANS_RATE = 6, // percentage
   118     SETTINGS_TYPE_INITIAL_WINDOW = 7,  // bytes for flow control
   119     SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8
   120   };
   122   // This should be big enough to hold all of your control packets,
   123   // but if it needs to grow for huge headers it can do so dynamically.
   124   // About 1% of responses from SPDY google services seem to be > 1000
   125   // with all less than 2000 when compression is enabled.
   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 = 1024 * 1024;
   144   const static uint32_t kMinimumToAck = 64 * 1024;
   146   // The default rwin is 64KB unless updated by a settings frame
   147   const static uint32_t kDefaultRwin = 64 * 1024;
   149   static nsresult HandleSynStream(SpdySession31 *);
   150   static nsresult HandleSynReply(SpdySession31 *);
   151   static nsresult HandleRstStream(SpdySession31 *);
   152   static nsresult HandleSettings(SpdySession31 *);
   153   static nsresult HandleNoop(SpdySession31 *);
   154   static nsresult HandlePing(SpdySession31 *);
   155   static nsresult HandleGoAway(SpdySession31 *);
   156   static nsresult HandleHeaders(SpdySession31 *);
   157   static nsresult HandleWindowUpdate(SpdySession31 *);
   158   static nsresult HandleCredential(SpdySession31 *);
   160   template<typename T>
   161     static void EnsureBuffer(nsAutoArrayPtr<T> &,
   162                              uint32_t, uint32_t, uint32_t &);
   164   // For writing the SPDY data stream to LOG4
   165   static void LogIO(SpdySession31 *, SpdyStream31 *, const char *,
   166                     const char *, uint32_t);
   168   // an overload of nsAHttpConnection
   169   void TransactionHasDataToWrite(nsAHttpTransaction *);
   171   // a similar version for SpdyStream31
   172   void TransactionHasDataToWrite(SpdyStream31 *);
   174   // an overload of nsAHttpSegementReader
   175   virtual nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment);
   176   nsresult BufferOutput(const char *, uint32_t, uint32_t *);
   177   void     FlushOutputQueue();
   178   uint32_t AmountOfOutputBuffered() { return mOutputQueueUsed - mOutputQueueSent; }
   180   uint32_t GetServerInitialStreamWindow() { return mServerInitialStreamWindow; }
   182   void ConnectPushedStream(SpdyStream31 *stream);
   183   void DecrementConcurrent(SpdyStream31 *stream);
   185   uint64_t Serial() { return mSerial; }
   187   void     PrintDiagnostics (nsCString &log);
   189   // Streams need access to these
   190   uint32_t SendingChunkSize() { return mSendingChunkSize; }
   191   uint32_t PushAllowance() { return mPushAllowance; }
   192   z_stream *UpstreamZlib() { return &mUpstreamZlib; }
   193   nsISocketTransport *SocketTransport() { return mSocketTransport; }
   194   int64_t RemoteSessionWindow() { return mRemoteSessionWindow; }
   195   void DecrementRemoteSessionWindow (uint32_t bytes) { mRemoteSessionWindow -= bytes; }
   197 private:
   199   enum stateType {
   200     BUFFERING_FRAME_HEADER,
   201     BUFFERING_CONTROL_FRAME,
   202     PROCESSING_DATA_FRAME,
   203     DISCARDING_DATA_FRAME,
   204     PROCESSING_COMPLETE_HEADERS,
   205     PROCESSING_CONTROL_RST_STREAM
   206   };
   208   nsresult    ResponseHeadersComplete();
   209   uint32_t    GetWriteQueueSize();
   210   void        ChangeDownstreamState(enum stateType);
   211   void        ResetDownstreamState();
   212   nsresult    UncompressAndDiscard(uint32_t, uint32_t);
   213   void        zlibInit();
   214   void        GeneratePing(uint32_t);
   215   void        GenerateRstStream(uint32_t, uint32_t);
   216   void        GenerateGoAway(uint32_t);
   217   void        CleanupStream(SpdyStream31 *, nsresult, rstReason);
   218   void        CloseStream(SpdyStream31 *, nsresult);
   219   void        GenerateSettings();
   220   void        RemoveStreamFromQueues(SpdyStream31 *);
   222   void        SetWriteCallbacks();
   223   void        RealignOutputQueue();
   225   bool        RoomForMoreConcurrent();
   226   void        ActivateStream(SpdyStream31 *);
   227   void        ProcessPending();
   228   nsresult    SetInputFrameDataStream(uint32_t);
   229   bool        VerifyStream(SpdyStream31 *, uint32_t);
   230   void        SetNeedsCleanup();
   232   void        UpdateLocalRwin(SpdyStream31 *stream, uint32_t bytes);
   233   void        UpdateLocalStreamWindow(SpdyStream31 *stream, uint32_t bytes);
   234   void        UpdateLocalSessionWindow(uint32_t bytes);
   236   // a wrapper for all calls to the nshttpconnection level segment writer. Used
   237   // to track network I/O for timeout purposes
   238   nsresult   NetworkRead(nsAHttpSegmentWriter *, char *, uint32_t, uint32_t *);
   240   static PLDHashOperator ShutdownEnumerator(nsAHttpTransaction *,
   241                                             nsAutoPtr<SpdyStream31> &,
   242                                             void *);
   244   static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
   245                                           nsAutoPtr<SpdyStream31> &,
   246                                           void *);
   248   static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
   249                                                     nsAutoPtr<SpdyStream31> &,
   250                                                     void *);
   252   static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
   253                                                         nsAutoPtr<SpdyStream31> &,
   254                                                         void *);
   256   // This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
   257   // from the first transaction on this session. That object contains the
   258   // pointer to the real network-level nsHttpConnection object.
   259   nsRefPtr<nsAHttpConnection> mConnection;
   261   // The underlying socket transport object is needed to propogate some events
   262   nsISocketTransport         *mSocketTransport;
   264   // These are temporary state variables to hold the argument to
   265   // Read/WriteSegments so it can be accessed by On(read/write)segment
   266   // further up the stack.
   267   nsAHttpSegmentReader       *mSegmentReader;
   268   nsAHttpSegmentWriter       *mSegmentWriter;
   270   uint32_t          mSendingChunkSize;        /* the transmission chunk size */
   271   uint32_t          mNextStreamID;            /* 24 bits */
   272   uint32_t          mConcurrentHighWater;     /* max parallelism on session */
   273   uint32_t          mPushAllowance;           /* rwin for unmatched pushes */
   275   stateType         mDownstreamState; /* in frame, between frames, etc..  */
   277   // Maintain 2 indexes - one by stream ID, one by transaction pointer.
   278   // There are also several lists of streams: ready to write, queued due to
   279   // max parallelism, streams that need to force a read for push, and the full
   280   // set of pushed streams.
   281   // The objects are not ref counted - they get destroyed
   282   // by the nsClassHashtable implementation when they are removed from
   283   // the transaction hash.
   284   nsDataHashtable<nsUint32HashKey, SpdyStream31 *>     mStreamIDHash;
   285   nsClassHashtable<nsPtrHashKey<nsAHttpTransaction>,
   286     SpdyStream31>                                     mStreamTransactionHash;
   288   nsDeque                                             mReadyForWrite;
   289   nsDeque                                             mQueuedStreams;
   290   nsDeque                                             mReadyForRead;
   291   nsTArray<SpdyPushedStream31 *>                      mPushedStreams;
   293   // Compression contexts for header transport using deflate.
   294   // SPDY compresses only HTTP headers and does not reset zlib in between
   295   // frames. Even data that is not associated with a stream (e.g invalid
   296   // stream ID) is passed through these contexts to keep the compression
   297   // context correct.
   298   z_stream            mDownstreamZlib;
   299   z_stream            mUpstreamZlib;
   301   // mInputFrameBuffer is used to store received control packets and the 8 bytes
   302   // of header on data packets
   303   uint32_t             mInputFrameBufferSize;
   304   uint32_t             mInputFrameBufferUsed;
   305   nsAutoArrayPtr<char> mInputFrameBuffer;
   307   // mInputFrameDataSize/Read are used for tracking the amount of data consumed
   308   // in a data frame. the data itself is not buffered in spdy
   309   // The frame size is mInputFrameDataSize + the constant 8 byte header
   310   uint32_t             mInputFrameDataSize;
   311   uint32_t             mInputFrameDataRead;
   312   bool                 mInputFrameDataLast; // This frame was marked FIN
   314   // When a frame has been received that is addressed to a particular stream
   315   // (e.g. a data frame after the stream-id has been decoded), this points
   316   // to the stream.
   317   SpdyStream31          *mInputFrameDataStream;
   319   // mNeedsCleanup is a state variable to defer cleanup of a closed stream
   320   // If needed, It is set in session::OnWriteSegments() and acted on and
   321   // cleared when the stack returns to session::WriteSegments(). The stream
   322   // cannot be destroyed directly out of OnWriteSegments because
   323   // stream::writeSegments() is on the stack at that time.
   324   SpdyStream31          *mNeedsCleanup;
   326   // The CONTROL_TYPE value for a control frame
   327   uint32_t             mFrameControlType;
   329   // This reason code in the last processed RESET frame
   330   uint32_t             mDownstreamRstReason;
   332   // for the conversion of downstream http headers into spdy formatted headers
   333   // The data here does not persist between frames
   334   nsCString            mFlatHTTPResponseHeaders;
   335   uint32_t             mFlatHTTPResponseHeadersOut;
   337   // when set, the session will go away when it reaches 0 streams. This flag
   338   // is set when: the stream IDs are running out (at either the client or the
   339   // server), when DontReuse() is called, a RST that is not specific to a
   340   // particular stream is received, a GOAWAY frame has been received from
   341   // the server.
   342   bool                 mShouldGoAway;
   344   // the session has received a nsAHttpTransaction::Close()  call
   345   bool                 mClosed;
   347   // the session received a GoAway frame with a valid GoAwayID
   348   bool                 mCleanShutdown;
   350   // indicates PROCESSING_COMPLETE_HEADERS state was pushed onto the stack
   351   // over an active PROCESSING_DATA_FRAME, which should be restored when
   352   // the processed headers are written to the stream
   353   bool                 mDataPending;
   355   // If a GoAway message was received this is the ID of the last valid
   356   // stream. 0 otherwise. (0 is never a valid stream id.)
   357   uint32_t             mGoAwayID;
   359   // The limit on number of concurrent streams for this session. Normally it
   360   // is basically unlimited, but the SETTINGS control message from the
   361   // server might bring it down.
   362   uint32_t             mMaxConcurrent;
   364   // The actual number of concurrent streams at this moment. Generally below
   365   // mMaxConcurrent, but the max can be lowered in real time to a value
   366   // below the current value
   367   uint32_t             mConcurrent;
   369   // The number of server initiated SYN-STREAMS, tracked for telemetry
   370   uint32_t             mServerPushedResources;
   372   // The server rwin for new streams as determined from a SETTINGS frame
   373   uint32_t             mServerInitialStreamWindow;
   375   // The Local Session window is how much data the server is allowed to send
   376   // (across all streams) without getting a window update to stream 0. It is
   377   // signed because asynchronous changes via SETTINGS can drive it negative.
   378   int64_t              mLocalSessionWindow;
   380   // The Remote Session Window is how much data the client is allowed to send
   381   // (across all streams) without receiving a window update to stream 0. It is
   382   // signed because asynchronous changes via SETTINGS can drive it negative.
   383   int64_t              mRemoteSessionWindow;
   385   // This is a output queue of bytes ready to be written to the SSL stream.
   386   // When that streams returns WOULD_BLOCK on direct write the bytes get
   387   // coalesced together here. This results in larger writes to the SSL layer.
   388   // The buffer is not dynamically grown to accomodate stream writes, but
   389   // does expand to accept infallible session wide frames like GoAway and RST.
   390   uint32_t             mOutputQueueSize;
   391   uint32_t             mOutputQueueUsed;
   392   uint32_t             mOutputQueueSent;
   393   nsAutoArrayPtr<char> mOutputQueueBuffer;
   395   PRIntervalTime       mPingThreshold;
   396   PRIntervalTime       mLastReadEpoch;     // used for ping timeouts
   397   PRIntervalTime       mLastDataReadEpoch; // used for IdleTime()
   398   PRIntervalTime       mPingSentEpoch;
   399   uint32_t             mNextPingID;
   401   // used as a temporary buffer while enumerating the stream hash during GoAway
   402   nsDeque  mGoAwayStreamsToRestart;
   404   // Each session gets a unique serial number because the push cache is correlated
   405   // by the load group and the serial number can be used as part of the cache key
   406   // to make sure streams aren't shared across sessions.
   407   uint64_t        mSerial;
   408 };
   410 }} // namespace mozilla::net
   412 #endif // mozilla_net_SpdySession31_h

mercurial