netwerk/protocol/http/SpdySession31.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/protocol/http/SpdySession31.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,412 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef mozilla_net_SpdySession31_h
    1.10 +#define mozilla_net_SpdySession31_h
    1.11 +
    1.12 +// spdy/3.1
    1.13 +
    1.14 +#include "ASpdySession.h"
    1.15 +#include "mozilla/Attributes.h"
    1.16 +#include "nsAHttpConnection.h"
    1.17 +#include "nsClassHashtable.h"
    1.18 +#include "nsDataHashtable.h"
    1.19 +#include "nsDeque.h"
    1.20 +#include "nsHashKeys.h"
    1.21 +#include "zlib.h"
    1.22 +
    1.23 +class nsISocketTransport;
    1.24 +
    1.25 +namespace mozilla { namespace net {
    1.26 +
    1.27 +class SpdyPushedStream31;
    1.28 +class SpdyStream31;
    1.29 +
    1.30 +class SpdySession31 MOZ_FINAL : public ASpdySession
    1.31 +  , public nsAHttpConnection
    1.32 +  , public nsAHttpSegmentReader
    1.33 +  , public nsAHttpSegmentWriter
    1.34 +{
    1.35 +public:
    1.36 +  NS_DECL_ISUPPORTS
    1.37 +  NS_DECL_NSAHTTPTRANSACTION
    1.38 +  NS_DECL_NSAHTTPCONNECTION(mConnection)
    1.39 +  NS_DECL_NSAHTTPSEGMENTREADER
    1.40 +  NS_DECL_NSAHTTPSEGMENTWRITER
    1.41 +
    1.42 +  SpdySession31(nsAHttpTransaction *, nsISocketTransport *, int32_t);
    1.43 +  ~SpdySession31();
    1.44 +
    1.45 +  bool AddStream(nsAHttpTransaction *, int32_t);
    1.46 +  bool CanReuse() { return !mShouldGoAway && !mClosed; }
    1.47 +  bool RoomForMoreStreams();
    1.48 +
    1.49 +  // When the connection is active this is called up to once every 1 second
    1.50 +  // return the interval (in seconds) that the connection next wants to
    1.51 +  // have this invoked. It might happen sooner depending on the needs of
    1.52 +  // other connections.
    1.53 +  uint32_t  ReadTimeoutTick(PRIntervalTime now);
    1.54 +
    1.55 +  // Idle time represents time since "goodput".. e.g. a data or header frame
    1.56 +  PRIntervalTime IdleTime();
    1.57 +
    1.58 +  // Registering with a newID of 0 means pick the next available odd ID
    1.59 +  uint32_t RegisterStreamID(SpdyStream31 *, uint32_t aNewID = 0);
    1.60 +
    1.61 +  const static uint8_t kVersion        = 3;
    1.62 +
    1.63 +  const static uint8_t kFlag_Control   = 0x80;
    1.64 +
    1.65 +  const static uint8_t kFlag_Data_FIN  = 0x01;
    1.66 +  const static uint8_t kFlag_Data_UNI  = 0x02;
    1.67 +
    1.68 +  enum
    1.69 +  {
    1.70 +    CONTROL_TYPE_FIRST = 0,
    1.71 +    CONTROL_TYPE_SYN_STREAM = 1,
    1.72 +    CONTROL_TYPE_SYN_REPLY = 2,
    1.73 +    CONTROL_TYPE_RST_STREAM = 3,
    1.74 +    CONTROL_TYPE_SETTINGS = 4,
    1.75 +    CONTROL_TYPE_NOOP = 5,                        /* deprecated */
    1.76 +    CONTROL_TYPE_PING = 6,
    1.77 +    CONTROL_TYPE_GOAWAY = 7,
    1.78 +    CONTROL_TYPE_HEADERS = 8,
    1.79 +    CONTROL_TYPE_WINDOW_UPDATE = 9,
    1.80 +    CONTROL_TYPE_CREDENTIAL = 10,
    1.81 +    CONTROL_TYPE_LAST = 11
    1.82 +  };
    1.83 +
    1.84 +  enum rstReason
    1.85 +  {
    1.86 +    RST_PROTOCOL_ERROR = 1,
    1.87 +    RST_INVALID_STREAM = 2,
    1.88 +    RST_REFUSED_STREAM = 3,
    1.89 +    RST_UNSUPPORTED_VERSION = 4,
    1.90 +    RST_CANCEL = 5,
    1.91 +    RST_INTERNAL_ERROR = 6,
    1.92 +    RST_FLOW_CONTROL_ERROR = 7,
    1.93 +    RST_STREAM_IN_USE = 8,
    1.94 +    RST_STREAM_ALREADY_CLOSED = 9,
    1.95 +    RST_INVALID_CREDENTIALS = 10,
    1.96 +    RST_FRAME_TOO_LARGE = 11
    1.97 +  };
    1.98 +
    1.99 +  enum goawayReason
   1.100 +  {
   1.101 +    OK = 0,
   1.102 +    PROTOCOL_ERROR = 1,
   1.103 +    INTERNAL_ERROR = 2,    // sometimes misdocumented as 11
   1.104 +    NUM_STATUS_CODES = 3   // reserved by chromium but undocumented
   1.105 +  };
   1.106 +
   1.107 +  enum settingsFlags
   1.108 +  {
   1.109 +    PERSIST_VALUE = 1,
   1.110 +    PERSISTED_VALUE = 2
   1.111 +  };
   1.112 +
   1.113 +  enum
   1.114 +  {
   1.115 +    SETTINGS_TYPE_UPLOAD_BW = 1, // kb/s
   1.116 +    SETTINGS_TYPE_DOWNLOAD_BW = 2, // kb/s
   1.117 +    SETTINGS_TYPE_RTT = 3, // ms
   1.118 +    SETTINGS_TYPE_MAX_CONCURRENT = 4, // streams
   1.119 +    SETTINGS_TYPE_CWND = 5, // packets
   1.120 +    SETTINGS_TYPE_DOWNLOAD_RETRANS_RATE = 6, // percentage
   1.121 +    SETTINGS_TYPE_INITIAL_WINDOW = 7,  // bytes for flow control
   1.122 +    SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8
   1.123 +  };
   1.124 +
   1.125 +  // This should be big enough to hold all of your control packets,
   1.126 +  // but if it needs to grow for huge headers it can do so dynamically.
   1.127 +  // About 1% of responses from SPDY google services seem to be > 1000
   1.128 +  // with all less than 2000 when compression is enabled.
   1.129 +  const static uint32_t kDefaultBufferSize = 2048;
   1.130 +
   1.131 +  // kDefaultQueueSize must be >= other queue size constants
   1.132 +  const static uint32_t kDefaultQueueSize =  32768;
   1.133 +  const static uint32_t kQueueMinimumCleanup = 24576;
   1.134 +  const static uint32_t kQueueTailRoom    =  4096;
   1.135 +  const static uint32_t kQueueReserved    =  1024;
   1.136 +
   1.137 +  const static uint32_t kDefaultMaxConcurrent = 100;
   1.138 +  const static uint32_t kMaxStreamID = 0x7800000;
   1.139 +
   1.140 +  // This is a sentinel for a deleted stream. It is not a valid
   1.141 +  // 31 bit stream ID.
   1.142 +  const static uint32_t kDeadStreamID = 0xffffdead;
   1.143 +
   1.144 +  // below the emergency threshold of local window we ack every received
   1.145 +  // byte. Above that we coalesce bytes into the MinimumToAck size.
   1.146 +  const static int32_t  kEmergencyWindowThreshold = 1024 * 1024;
   1.147 +  const static uint32_t kMinimumToAck = 64 * 1024;
   1.148 +
   1.149 +  // The default rwin is 64KB unless updated by a settings frame
   1.150 +  const static uint32_t kDefaultRwin = 64 * 1024;
   1.151 +
   1.152 +  static nsresult HandleSynStream(SpdySession31 *);
   1.153 +  static nsresult HandleSynReply(SpdySession31 *);
   1.154 +  static nsresult HandleRstStream(SpdySession31 *);
   1.155 +  static nsresult HandleSettings(SpdySession31 *);
   1.156 +  static nsresult HandleNoop(SpdySession31 *);
   1.157 +  static nsresult HandlePing(SpdySession31 *);
   1.158 +  static nsresult HandleGoAway(SpdySession31 *);
   1.159 +  static nsresult HandleHeaders(SpdySession31 *);
   1.160 +  static nsresult HandleWindowUpdate(SpdySession31 *);
   1.161 +  static nsresult HandleCredential(SpdySession31 *);
   1.162 +
   1.163 +  template<typename T>
   1.164 +    static void EnsureBuffer(nsAutoArrayPtr<T> &,
   1.165 +                             uint32_t, uint32_t, uint32_t &);
   1.166 +
   1.167 +  // For writing the SPDY data stream to LOG4
   1.168 +  static void LogIO(SpdySession31 *, SpdyStream31 *, const char *,
   1.169 +                    const char *, uint32_t);
   1.170 +
   1.171 +  // an overload of nsAHttpConnection
   1.172 +  void TransactionHasDataToWrite(nsAHttpTransaction *);
   1.173 +
   1.174 +  // a similar version for SpdyStream31
   1.175 +  void TransactionHasDataToWrite(SpdyStream31 *);
   1.176 +
   1.177 +  // an overload of nsAHttpSegementReader
   1.178 +  virtual nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment);
   1.179 +  nsresult BufferOutput(const char *, uint32_t, uint32_t *);
   1.180 +  void     FlushOutputQueue();
   1.181 +  uint32_t AmountOfOutputBuffered() { return mOutputQueueUsed - mOutputQueueSent; }
   1.182 +
   1.183 +  uint32_t GetServerInitialStreamWindow() { return mServerInitialStreamWindow; }
   1.184 +
   1.185 +  void ConnectPushedStream(SpdyStream31 *stream);
   1.186 +  void DecrementConcurrent(SpdyStream31 *stream);
   1.187 +
   1.188 +  uint64_t Serial() { return mSerial; }
   1.189 +
   1.190 +  void     PrintDiagnostics (nsCString &log);
   1.191 +
   1.192 +  // Streams need access to these
   1.193 +  uint32_t SendingChunkSize() { return mSendingChunkSize; }
   1.194 +  uint32_t PushAllowance() { return mPushAllowance; }
   1.195 +  z_stream *UpstreamZlib() { return &mUpstreamZlib; }
   1.196 +  nsISocketTransport *SocketTransport() { return mSocketTransport; }
   1.197 +  int64_t RemoteSessionWindow() { return mRemoteSessionWindow; }
   1.198 +  void DecrementRemoteSessionWindow (uint32_t bytes) { mRemoteSessionWindow -= bytes; }
   1.199 +
   1.200 +private:
   1.201 +
   1.202 +  enum stateType {
   1.203 +    BUFFERING_FRAME_HEADER,
   1.204 +    BUFFERING_CONTROL_FRAME,
   1.205 +    PROCESSING_DATA_FRAME,
   1.206 +    DISCARDING_DATA_FRAME,
   1.207 +    PROCESSING_COMPLETE_HEADERS,
   1.208 +    PROCESSING_CONTROL_RST_STREAM
   1.209 +  };
   1.210 +
   1.211 +  nsresult    ResponseHeadersComplete();
   1.212 +  uint32_t    GetWriteQueueSize();
   1.213 +  void        ChangeDownstreamState(enum stateType);
   1.214 +  void        ResetDownstreamState();
   1.215 +  nsresult    UncompressAndDiscard(uint32_t, uint32_t);
   1.216 +  void        zlibInit();
   1.217 +  void        GeneratePing(uint32_t);
   1.218 +  void        GenerateRstStream(uint32_t, uint32_t);
   1.219 +  void        GenerateGoAway(uint32_t);
   1.220 +  void        CleanupStream(SpdyStream31 *, nsresult, rstReason);
   1.221 +  void        CloseStream(SpdyStream31 *, nsresult);
   1.222 +  void        GenerateSettings();
   1.223 +  void        RemoveStreamFromQueues(SpdyStream31 *);
   1.224 +
   1.225 +  void        SetWriteCallbacks();
   1.226 +  void        RealignOutputQueue();
   1.227 +
   1.228 +  bool        RoomForMoreConcurrent();
   1.229 +  void        ActivateStream(SpdyStream31 *);
   1.230 +  void        ProcessPending();
   1.231 +  nsresult    SetInputFrameDataStream(uint32_t);
   1.232 +  bool        VerifyStream(SpdyStream31 *, uint32_t);
   1.233 +  void        SetNeedsCleanup();
   1.234 +
   1.235 +  void        UpdateLocalRwin(SpdyStream31 *stream, uint32_t bytes);
   1.236 +  void        UpdateLocalStreamWindow(SpdyStream31 *stream, uint32_t bytes);
   1.237 +  void        UpdateLocalSessionWindow(uint32_t bytes);
   1.238 +
   1.239 +  // a wrapper for all calls to the nshttpconnection level segment writer. Used
   1.240 +  // to track network I/O for timeout purposes
   1.241 +  nsresult   NetworkRead(nsAHttpSegmentWriter *, char *, uint32_t, uint32_t *);
   1.242 +
   1.243 +  static PLDHashOperator ShutdownEnumerator(nsAHttpTransaction *,
   1.244 +                                            nsAutoPtr<SpdyStream31> &,
   1.245 +                                            void *);
   1.246 +
   1.247 +  static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
   1.248 +                                          nsAutoPtr<SpdyStream31> &,
   1.249 +                                          void *);
   1.250 +
   1.251 +  static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
   1.252 +                                                    nsAutoPtr<SpdyStream31> &,
   1.253 +                                                    void *);
   1.254 +
   1.255 +  static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
   1.256 +                                                        nsAutoPtr<SpdyStream31> &,
   1.257 +                                                        void *);
   1.258 +
   1.259 +  // This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
   1.260 +  // from the first transaction on this session. That object contains the
   1.261 +  // pointer to the real network-level nsHttpConnection object.
   1.262 +  nsRefPtr<nsAHttpConnection> mConnection;
   1.263 +
   1.264 +  // The underlying socket transport object is needed to propogate some events
   1.265 +  nsISocketTransport         *mSocketTransport;
   1.266 +
   1.267 +  // These are temporary state variables to hold the argument to
   1.268 +  // Read/WriteSegments so it can be accessed by On(read/write)segment
   1.269 +  // further up the stack.
   1.270 +  nsAHttpSegmentReader       *mSegmentReader;
   1.271 +  nsAHttpSegmentWriter       *mSegmentWriter;
   1.272 +
   1.273 +  uint32_t          mSendingChunkSize;        /* the transmission chunk size */
   1.274 +  uint32_t          mNextStreamID;            /* 24 bits */
   1.275 +  uint32_t          mConcurrentHighWater;     /* max parallelism on session */
   1.276 +  uint32_t          mPushAllowance;           /* rwin for unmatched pushes */
   1.277 +
   1.278 +  stateType         mDownstreamState; /* in frame, between frames, etc..  */
   1.279 +
   1.280 +  // Maintain 2 indexes - one by stream ID, one by transaction pointer.
   1.281 +  // There are also several lists of streams: ready to write, queued due to
   1.282 +  // max parallelism, streams that need to force a read for push, and the full
   1.283 +  // set of pushed streams.
   1.284 +  // The objects are not ref counted - they get destroyed
   1.285 +  // by the nsClassHashtable implementation when they are removed from
   1.286 +  // the transaction hash.
   1.287 +  nsDataHashtable<nsUint32HashKey, SpdyStream31 *>     mStreamIDHash;
   1.288 +  nsClassHashtable<nsPtrHashKey<nsAHttpTransaction>,
   1.289 +    SpdyStream31>                                     mStreamTransactionHash;
   1.290 +
   1.291 +  nsDeque                                             mReadyForWrite;
   1.292 +  nsDeque                                             mQueuedStreams;
   1.293 +  nsDeque                                             mReadyForRead;
   1.294 +  nsTArray<SpdyPushedStream31 *>                      mPushedStreams;
   1.295 +
   1.296 +  // Compression contexts for header transport using deflate.
   1.297 +  // SPDY compresses only HTTP headers and does not reset zlib in between
   1.298 +  // frames. Even data that is not associated with a stream (e.g invalid
   1.299 +  // stream ID) is passed through these contexts to keep the compression
   1.300 +  // context correct.
   1.301 +  z_stream            mDownstreamZlib;
   1.302 +  z_stream            mUpstreamZlib;
   1.303 +
   1.304 +  // mInputFrameBuffer is used to store received control packets and the 8 bytes
   1.305 +  // of header on data packets
   1.306 +  uint32_t             mInputFrameBufferSize;
   1.307 +  uint32_t             mInputFrameBufferUsed;
   1.308 +  nsAutoArrayPtr<char> mInputFrameBuffer;
   1.309 +
   1.310 +  // mInputFrameDataSize/Read are used for tracking the amount of data consumed
   1.311 +  // in a data frame. the data itself is not buffered in spdy
   1.312 +  // The frame size is mInputFrameDataSize + the constant 8 byte header
   1.313 +  uint32_t             mInputFrameDataSize;
   1.314 +  uint32_t             mInputFrameDataRead;
   1.315 +  bool                 mInputFrameDataLast; // This frame was marked FIN
   1.316 +
   1.317 +  // When a frame has been received that is addressed to a particular stream
   1.318 +  // (e.g. a data frame after the stream-id has been decoded), this points
   1.319 +  // to the stream.
   1.320 +  SpdyStream31          *mInputFrameDataStream;
   1.321 +
   1.322 +  // mNeedsCleanup is a state variable to defer cleanup of a closed stream
   1.323 +  // If needed, It is set in session::OnWriteSegments() and acted on and
   1.324 +  // cleared when the stack returns to session::WriteSegments(). The stream
   1.325 +  // cannot be destroyed directly out of OnWriteSegments because
   1.326 +  // stream::writeSegments() is on the stack at that time.
   1.327 +  SpdyStream31          *mNeedsCleanup;
   1.328 +
   1.329 +  // The CONTROL_TYPE value for a control frame
   1.330 +  uint32_t             mFrameControlType;
   1.331 +
   1.332 +  // This reason code in the last processed RESET frame
   1.333 +  uint32_t             mDownstreamRstReason;
   1.334 +
   1.335 +  // for the conversion of downstream http headers into spdy formatted headers
   1.336 +  // The data here does not persist between frames
   1.337 +  nsCString            mFlatHTTPResponseHeaders;
   1.338 +  uint32_t             mFlatHTTPResponseHeadersOut;
   1.339 +
   1.340 +  // when set, the session will go away when it reaches 0 streams. This flag
   1.341 +  // is set when: the stream IDs are running out (at either the client or the
   1.342 +  // server), when DontReuse() is called, a RST that is not specific to a
   1.343 +  // particular stream is received, a GOAWAY frame has been received from
   1.344 +  // the server.
   1.345 +  bool                 mShouldGoAway;
   1.346 +
   1.347 +  // the session has received a nsAHttpTransaction::Close()  call
   1.348 +  bool                 mClosed;
   1.349 +
   1.350 +  // the session received a GoAway frame with a valid GoAwayID
   1.351 +  bool                 mCleanShutdown;
   1.352 +
   1.353 +  // indicates PROCESSING_COMPLETE_HEADERS state was pushed onto the stack
   1.354 +  // over an active PROCESSING_DATA_FRAME, which should be restored when
   1.355 +  // the processed headers are written to the stream
   1.356 +  bool                 mDataPending;
   1.357 +
   1.358 +  // If a GoAway message was received this is the ID of the last valid
   1.359 +  // stream. 0 otherwise. (0 is never a valid stream id.)
   1.360 +  uint32_t             mGoAwayID;
   1.361 +
   1.362 +  // The limit on number of concurrent streams for this session. Normally it
   1.363 +  // is basically unlimited, but the SETTINGS control message from the
   1.364 +  // server might bring it down.
   1.365 +  uint32_t             mMaxConcurrent;
   1.366 +
   1.367 +  // The actual number of concurrent streams at this moment. Generally below
   1.368 +  // mMaxConcurrent, but the max can be lowered in real time to a value
   1.369 +  // below the current value
   1.370 +  uint32_t             mConcurrent;
   1.371 +
   1.372 +  // The number of server initiated SYN-STREAMS, tracked for telemetry
   1.373 +  uint32_t             mServerPushedResources;
   1.374 +
   1.375 +  // The server rwin for new streams as determined from a SETTINGS frame
   1.376 +  uint32_t             mServerInitialStreamWindow;
   1.377 +
   1.378 +  // The Local Session window is how much data the server is allowed to send
   1.379 +  // (across all streams) without getting a window update to stream 0. It is
   1.380 +  // signed because asynchronous changes via SETTINGS can drive it negative.
   1.381 +  int64_t              mLocalSessionWindow;
   1.382 +
   1.383 +  // The Remote Session Window is how much data the client is allowed to send
   1.384 +  // (across all streams) without receiving a window update to stream 0. It is
   1.385 +  // signed because asynchronous changes via SETTINGS can drive it negative.
   1.386 +  int64_t              mRemoteSessionWindow;
   1.387 +
   1.388 +  // This is a output queue of bytes ready to be written to the SSL stream.
   1.389 +  // When that streams returns WOULD_BLOCK on direct write the bytes get
   1.390 +  // coalesced together here. This results in larger writes to the SSL layer.
   1.391 +  // The buffer is not dynamically grown to accomodate stream writes, but
   1.392 +  // does expand to accept infallible session wide frames like GoAway and RST.
   1.393 +  uint32_t             mOutputQueueSize;
   1.394 +  uint32_t             mOutputQueueUsed;
   1.395 +  uint32_t             mOutputQueueSent;
   1.396 +  nsAutoArrayPtr<char> mOutputQueueBuffer;
   1.397 +
   1.398 +  PRIntervalTime       mPingThreshold;
   1.399 +  PRIntervalTime       mLastReadEpoch;     // used for ping timeouts
   1.400 +  PRIntervalTime       mLastDataReadEpoch; // used for IdleTime()
   1.401 +  PRIntervalTime       mPingSentEpoch;
   1.402 +  uint32_t             mNextPingID;
   1.403 +
   1.404 +  // used as a temporary buffer while enumerating the stream hash during GoAway
   1.405 +  nsDeque  mGoAwayStreamsToRestart;
   1.406 +
   1.407 +  // Each session gets a unique serial number because the push cache is correlated
   1.408 +  // by the load group and the serial number can be used as part of the cache key
   1.409 +  // to make sure streams aren't shared across sessions.
   1.410 +  uint64_t        mSerial;
   1.411 +};
   1.412 +
   1.413 +}} // namespace mozilla::net
   1.414 +
   1.415 +#endif // mozilla_net_SpdySession31_h

mercurial