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