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