netwerk/protocol/http/SpdySession3.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.

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

mercurial