netwerk/protocol/http/SpdySession3.h

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

mercurial