LCOV - code coverage report
Current view: directory - netwerk/protocol/http - SpdySession.h (source / functions) Found Hit Coverage
Test: app.info Lines: 1 0 0.0 %
Date: 2012-06-02 Functions: 1 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : 
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Mozilla Foundation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Patrick McManus <mcmanus@ducksong.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #ifndef mozilla_net_SpdySession_h
      41                 : #define mozilla_net_SpdySession_h
      42                 : 
      43                 : // SPDY as defined by
      44                 : // http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft2
      45                 : 
      46                 : #include "nsAHttpTransaction.h"
      47                 : #include "nsAHttpConnection.h"
      48                 : #include "nsClassHashtable.h"
      49                 : #include "nsDataHashtable.h"
      50                 : #include "nsDeque.h"
      51                 : #include "nsHashKeys.h"
      52                 : #include "zlib.h"
      53                 : 
      54                 : class nsHttpConnection;
      55                 : class nsISocketTransport;
      56                 : 
      57                 : namespace mozilla { namespace net {
      58                 : 
      59                 : class SpdyStream;
      60                 : 
      61                 : class SpdySession : public nsAHttpTransaction
      62                 :                   , public nsAHttpConnection
      63                 :                   , public nsAHttpSegmentReader
      64                 :                   , public nsAHttpSegmentWriter
      65                 : {
      66                 : public:
      67                 :   NS_DECL_ISUPPORTS
      68                 :   NS_DECL_NSAHTTPTRANSACTION
      69                 :   NS_DECL_NSAHTTPCONNECTION
      70                 :   NS_DECL_NSAHTTPSEGMENTREADER
      71                 :   NS_DECL_NSAHTTPSEGMENTWRITER
      72                 : 
      73                 :   SpdySession(nsAHttpTransaction *, nsISocketTransport *, PRInt32);
      74                 :   ~SpdySession();
      75                 : 
      76                 :   bool AddStream(nsAHttpTransaction *, PRInt32);
      77               0 :   bool CanReuse() { return !mShouldGoAway && !mClosed; }
      78                 :   void DontReuse();
      79                 :   bool RoomForMoreStreams();
      80                 : 
      81                 :   // When the connection is active this is called every 15 seconds
      82                 :   void ReadTimeoutTick(PRIntervalTime now);
      83                 :   
      84                 :   // Idle time represents time since "goodput".. e.g. a data or header frame
      85                 :   PRIntervalTime IdleTime();
      86                 : 
      87                 :   PRUint32 RegisterStreamID(SpdyStream *);
      88                 : 
      89                 :   const static PRUint8 kFlag_Control   = 0x80;
      90                 : 
      91                 :   const static PRUint8 kFlag_Data_FIN  = 0x01;
      92                 :   const static PRUint8 kFlag_Data_UNI  = 0x02;
      93                 :   const static PRUint8 kFlag_Data_ZLIB = 0x02;
      94                 :   
      95                 :   // The protocol document for v2 specifies that the
      96                 :   // highest value (3) is the highest priority, but in
      97                 :   // reality 0 is the highest priority. 
      98                 :   //
      99                 :   // Draft 3 notes here https://sites.google.com/a/chromium.org/dev/spdy/spdy-protocol/
     100                 :   // are the best guide to the mistake. Also see
     101                 :   // GetLowestPriority() and GetHighestPriority() in spdy_framer.h of
     102                 :   // chromium source.
     103                 : 
     104                 :   const static PRUint8 kPri00   = 0 << 6; // highest
     105                 :   const static PRUint8 kPri01   = 1 << 6;
     106                 :   const static PRUint8 kPri02   = 2 << 6;
     107                 :   const static PRUint8 kPri03   = 3 << 6; // lowest
     108                 : 
     109                 :   enum
     110                 :   {
     111                 :     CONTROL_TYPE_FIRST = 0,
     112                 :     CONTROL_TYPE_SYN_STREAM = 1,
     113                 :     CONTROL_TYPE_SYN_REPLY = 2,
     114                 :     CONTROL_TYPE_RST_STREAM = 3,
     115                 :     CONTROL_TYPE_SETTINGS = 4,
     116                 :     CONTROL_TYPE_NOOP = 5,
     117                 :     CONTROL_TYPE_PING = 6,
     118                 :     CONTROL_TYPE_GOAWAY = 7,
     119                 :     CONTROL_TYPE_HEADERS = 8,
     120                 :     CONTROL_TYPE_WINDOW_UPDATE = 9,               /* no longer in v2 */
     121                 :     CONTROL_TYPE_LAST = 10
     122                 :   };
     123                 : 
     124                 :   enum rstReason
     125                 :   {
     126                 :     RST_PROTOCOL_ERROR = 1,
     127                 :     RST_INVALID_STREAM = 2,
     128                 :     RST_REFUSED_STREAM = 3,
     129                 :     RST_UNSUPPORTED_VERSION = 4,
     130                 :     RST_CANCEL = 5,
     131                 :     RST_INTERNAL_ERROR = 6,
     132                 :     RST_FLOW_CONTROL_ERROR = 7,
     133                 :     RST_BAD_ASSOC_STREAM = 8
     134                 :   };
     135                 : 
     136                 :   enum
     137                 :   {
     138                 :     SETTINGS_TYPE_UPLOAD_BW = 1, // kb/s
     139                 :     SETTINGS_TYPE_DOWNLOAD_BW = 2, // kb/s
     140                 :     SETTINGS_TYPE_RTT = 3, // ms
     141                 :     SETTINGS_TYPE_MAX_CONCURRENT = 4, // streams
     142                 :     SETTINGS_TYPE_CWND = 5, // packets
     143                 :     SETTINGS_TYPE_DOWNLOAD_RETRANS_RATE = 6, // percentage
     144                 :     SETTINGS_TYPE_INITIAL_WINDOW = 7  // bytes. Not used in v2.
     145                 :   };
     146                 : 
     147                 :   // This should be big enough to hold all of your control packets,
     148                 :   // but if it needs to grow for huge headers it can do so dynamically.
     149                 :   // About 1% of requests to SPDY google services seem to be > 1000
     150                 :   // with all less than 2000.
     151                 :   const static PRUint32 kDefaultBufferSize = 2048;
     152                 : 
     153                 :   // kDefaultQueueSize must be >= other queue size constants
     154                 :   const static PRUint32 kDefaultQueueSize =  16384;
     155                 :   const static PRUint32 kQueueMinimumCleanup = 8192;
     156                 :   const static PRUint32 kQueueTailRoom    =  4096;
     157                 :   const static PRUint32 kQueueReserved    =  1024;
     158                 : 
     159                 :   const static PRUint32 kSendingChunkSize = 4096;
     160                 :   const static PRUint32 kDefaultMaxConcurrent = 100;
     161                 :   const static PRUint32 kMaxStreamID = 0x7800000;
     162                 :   
     163                 :   static nsresult HandleSynStream(SpdySession *);
     164                 :   static nsresult HandleSynReply(SpdySession *);
     165                 :   static nsresult HandleRstStream(SpdySession *);
     166                 :   static nsresult HandleSettings(SpdySession *);
     167                 :   static nsresult HandleNoop(SpdySession *);
     168                 :   static nsresult HandlePing(SpdySession *);
     169                 :   static nsresult HandleGoAway(SpdySession *);
     170                 :   static nsresult HandleHeaders(SpdySession *);
     171                 :   static nsresult HandleWindowUpdate(SpdySession *);
     172                 : 
     173                 :   static void EnsureBuffer(nsAutoArrayPtr<char> &,
     174                 :                            PRUint32, PRUint32, PRUint32 &);
     175                 : 
     176                 :   // For writing the SPDY data stream to LOG4
     177                 :   static void LogIO(SpdySession *, SpdyStream *, const char *,
     178                 :                     const char *, PRUint32);
     179                 : 
     180                 :   // an overload of nsAHttpConnection
     181                 :   void TransactionHasDataToWrite(nsAHttpTransaction *);
     182                 : 
     183                 :   // a similar version for SpdyStream
     184                 :   void TransactionHasDataToWrite(SpdyStream *);
     185                 : 
     186                 :   // an overload of nsAHttpSegementReader
     187                 :   virtual nsresult CommitToSegmentSize(PRUint32 size);
     188                 :   
     189                 : private:
     190                 : 
     191                 :   enum stateType {
     192                 :     BUFFERING_FRAME_HEADER,
     193                 :     BUFFERING_CONTROL_FRAME,
     194                 :     PROCESSING_DATA_FRAME,
     195                 :     DISCARDING_DATA_FRAME,
     196                 :     PROCESSING_CONTROL_SYN_REPLY,
     197                 :     PROCESSING_CONTROL_RST_STREAM
     198                 :   };
     199                 : 
     200                 :   void        DeterminePingThreshold();
     201                 :   nsresult    HandleSynReplyForValidStream();
     202                 :   PRUint32    GetWriteQueueSize();
     203                 :   void        ChangeDownstreamState(enum stateType);
     204                 :   void        ResetDownstreamState();
     205                 :   nsresult    DownstreamUncompress(char *, PRUint32);
     206                 :   void        zlibInit();
     207                 :   nsresult    FindHeader(nsCString, nsDependentCSubstring &);
     208                 :   nsresult    ConvertHeaders(nsDependentCSubstring &,
     209                 :                              nsDependentCSubstring &);
     210                 :   void        GeneratePing(PRUint32);
     211                 :   void        ClearPing(bool);
     212                 :   void        GenerateRstStream(PRUint32, PRUint32);
     213                 :   void        GenerateGoAway();
     214                 :   void        CleanupStream(SpdyStream *, nsresult, rstReason);
     215                 : 
     216                 :   void        SetWriteCallbacks();
     217                 :   void        FlushOutputQueue();
     218                 : 
     219                 :   bool        RoomForMoreConcurrent();
     220                 :   void        ActivateStream(SpdyStream *);
     221                 :   void        ProcessPending();
     222                 : 
     223                 :   // a wrapper for all calls to the nshttpconnection level segment writer. Used
     224                 :   // to track network I/O for timeout purposes
     225                 :   nsresult   NetworkRead(nsAHttpSegmentWriter *, char *, PRUint32, PRUint32 *);
     226                 :   
     227                 :   static PLDHashOperator ShutdownEnumerator(nsAHttpTransaction *,
     228                 :                                             nsAutoPtr<SpdyStream> &,
     229                 :                                             void *);
     230                 : 
     231                 :   // This is intended to be nsHttpConnectionMgr:nsHttpConnectionHandle taken
     232                 :   // from the first transaction on this session. That object contains the
     233                 :   // pointer to the real network-level nsHttpConnection object.
     234                 :   nsRefPtr<nsAHttpConnection> mConnection;
     235                 : 
     236                 :   // The underlying socket transport object is needed to propogate some events
     237                 :   nsISocketTransport         *mSocketTransport;
     238                 : 
     239                 :   // These are temporary state variables to hold the argument to
     240                 :   // Read/WriteSegments so it can be accessed by On(read/write)segment
     241                 :   // further up the stack.
     242                 :   nsAHttpSegmentReader       *mSegmentReader;
     243                 :   nsAHttpSegmentWriter       *mSegmentWriter;
     244                 : 
     245                 :   PRUint32          mSendingChunkSize;        /* the transmission chunk size */
     246                 :   PRUint32          mNextStreamID;            /* 24 bits */
     247                 :   PRUint32          mConcurrentHighWater;     /* max parallelism on session */
     248                 : 
     249                 :   stateType         mDownstreamState; /* in frame, between frames, etc..  */
     250                 : 
     251                 :   // Maintain 5 indexes - one by stream ID, one by transaction ptr,
     252                 :   // one list of streams ready to write, one list of streams that are queued
     253                 :   // due to max parallelism settings, and one list of streams
     254                 :   // that must be given priority to write for window updates. The objects
     255                 :   // are not ref counted - they get destroyed
     256                 :   // by the nsClassHashtable implementation when they are removed from
     257                 :   // there.
     258                 :   nsDataHashtable<nsUint32HashKey, SpdyStream *>      mStreamIDHash;
     259                 :   nsClassHashtable<nsPtrHashKey<nsAHttpTransaction>,
     260                 :                    SpdyStream>                        mStreamTransactionHash;
     261                 :   nsDeque                                             mReadyForWrite;
     262                 :   nsDeque                                             mQueuedStreams;
     263                 : 
     264                 :   // UrgentForWrite is meant to carry window updates. They were defined in
     265                 :   // the v2 spec but apparently never implemented so are now scheduled to
     266                 :   // be removed. But they will be reintroduced for v3, so we will leave
     267                 :   // this queue in place to ease that transition.
     268                 :   nsDeque           mUrgentForWrite;
     269                 : 
     270                 :   // Compression contexts for header transport using deflate.
     271                 :   // SPDY compresses only HTTP headers and does not reset zlib in between
     272                 :   // frames.
     273                 :   z_stream            mDownstreamZlib;
     274                 :   z_stream            mUpstreamZlib;
     275                 : 
     276                 :   // mInputFrameBuffer is used to store received control packets and the 8 bytes
     277                 :   // of header on data packets
     278                 :   PRUint32             mInputFrameBufferSize;
     279                 :   PRUint32             mInputFrameBufferUsed;
     280                 :   nsAutoArrayPtr<char> mInputFrameBuffer;
     281                 :   
     282                 :   // mInputFrameDataSize/Read are used for tracking the amount of data consumed
     283                 :   // in a data frame. the data itself is not buffered in spdy
     284                 :   // The frame size is mInputFrameDataSize + the constant 8 byte header
     285                 :   PRUint32             mInputFrameDataSize;
     286                 :   PRUint32             mInputFrameDataRead;
     287                 :   bool                 mInputFrameDataLast; // This frame was marked FIN
     288                 : 
     289                 :   // When a frame has been received that is addressed to a particular stream
     290                 :   // (e.g. a data frame after the stream-id has been decoded), this points
     291                 :   // to the stream.
     292                 :   SpdyStream          *mInputFrameDataStream;
     293                 :   
     294                 :   // mNeedsCleanup is a state variable to defer cleanup of a closed stream
     295                 :   // If needed, It is set in session::OnWriteSegments() and acted on and
     296                 :   // cleared when the stack returns to session::WriteSegments(). The stream
     297                 :   // cannot be destroyed directly out of OnWriteSegments because
     298                 :   // stream::writeSegments() is on the stack at that time.
     299                 :   SpdyStream          *mNeedsCleanup;
     300                 : 
     301                 :   // The CONTROL_TYPE value for a control frame
     302                 :   PRUint32             mFrameControlType;
     303                 : 
     304                 :   // This reason code in the last processed RESET frame
     305                 :   PRUint32             mDownstreamRstReason;
     306                 : 
     307                 :   // These are used for decompressing downstream spdy response headers
     308                 :   // This is done at the session level because sometimes the stream
     309                 :   // has already been canceled but the decompression still must happen
     310                 :   // to keep the zlib state correct for the next state of headers.
     311                 :   PRUint32             mDecompressBufferSize;
     312                 :   PRUint32             mDecompressBufferUsed;
     313                 :   nsAutoArrayPtr<char> mDecompressBuffer;
     314                 : 
     315                 :   // for the conversion of downstream http headers into spdy formatted headers
     316                 :   nsCString            mFlatHTTPResponseHeaders;
     317                 :   PRUint32             mFlatHTTPResponseHeadersOut;
     318                 : 
     319                 :   // when set, the session will go away when it reaches 0 streams. This flag
     320                 :   // is set when: the stream IDs are running out (at either the client or the
     321                 :   // server), when DontReuse() is called, a RST that is not specific to a
     322                 :   // particular stream is received, a GOAWAY frame has been received from
     323                 :   // the server.
     324                 :   bool                 mShouldGoAway;
     325                 : 
     326                 :   // the session has received a nsAHttpTransaction::Close()  call
     327                 :   bool                 mClosed;
     328                 : 
     329                 :   // the session received a GoAway frame with a valid GoAwayID
     330                 :   bool                 mCleanShutdown;
     331                 : 
     332                 :   // If a GoAway message was received this is the ID of the last valid
     333                 :   // stream. 0 otherwise. (0 is never a valid stream id.)
     334                 :   PRUint32             mGoAwayID;
     335                 : 
     336                 :   // The limit on number of concurrent streams for this session. Normally it
     337                 :   // is basically unlimited, but the SETTINGS control message from the
     338                 :   // server might bring it down.
     339                 :   PRUint32             mMaxConcurrent;
     340                 : 
     341                 :   // The actual number of concurrent streams at this moment. Generally below
     342                 :   // mMaxConcurrent, but the max can be lowered in real time to a value
     343                 :   // below the current value
     344                 :   PRUint32             mConcurrent;
     345                 : 
     346                 :   // The number of server initiated SYN-STREAMS, tracked for telemetry
     347                 :   PRUint32             mServerPushedResources;
     348                 : 
     349                 :   // This is a output queue of bytes ready to be written to the SSL stream.
     350                 :   // When that streams returns WOULD_BLOCK on direct write the bytes get
     351                 :   // coalesced together here. This results in larger writes to the SSL layer.
     352                 :   // The buffer is not dynamically grown to accomodate stream writes, but
     353                 :   // does expand to accept infallible session wide frames like GoAway and RST.
     354                 :   PRUint32             mOutputQueueSize;
     355                 :   PRUint32             mOutputQueueUsed;
     356                 :   PRUint32             mOutputQueueSent;
     357                 :   nsAutoArrayPtr<char> mOutputQueueBuffer;
     358                 : 
     359                 :   PRIntervalTime       mPingThreshold;
     360                 :   PRIntervalTime       mLastReadEpoch;     // used for ping timeouts
     361                 :   PRIntervalTime       mLastDataReadEpoch; // used for IdleTime()
     362                 :   PRIntervalTime       mPingSentEpoch;
     363                 :   PRUint32             mNextPingID;
     364                 :   bool                 mPingThresholdExperiment;
     365                 : };
     366                 : 
     367                 : }} // namespace mozilla::net
     368                 : 
     369                 : #endif // mozilla_net_SpdySession_h

Generated by: LCOV version 1.7