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.

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

mercurial