1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef mozilla_net_Http2Stream_h 7 #define mozilla_net_Http2Stream_h 8 9 // HTTP/2 - RFC7540 10 // https://www.rfc-editor.org/rfc/rfc7540.txt 11 12 #include "mozilla/Attributes.h" 13 #include "mozilla/UniquePtr.h" 14 #include "nsAHttpTransaction.h" 15 #include "nsISupportsPriority.h" 16 #include "SimpleBuffer.h" 17 18 class nsIInputStream; 19 class nsIOutputStream; 20 21 namespace mozilla { 22 class OriginAttributes; 23 } 24 25 namespace mozilla { 26 namespace net { 27 28 class nsStandardURL; 29 class Http2Session; 30 class Http2Decompressor; 31 32 class Http2Stream : public nsAHttpSegmentReader, 33 public nsAHttpSegmentWriter, 34 public SupportsWeakPtr<Http2Stream> { 35 public: 36 MOZ_DECLARE_WEAKREFERENCE_TYPENAME(Http2Stream) 37 NS_DECL_NSAHTTPSEGMENTREADER 38 NS_DECL_NSAHTTPSEGMENTWRITER 39 40 enum stateType { 41 IDLE, 42 RESERVED_BY_REMOTE, 43 OPEN, 44 CLOSED_BY_LOCAL, 45 CLOSED_BY_REMOTE, 46 CLOSED 47 }; 48 49 const static int32_t kNormalPriority = 0x1000; 50 const static int32_t kWorstPriority = 51 kNormalPriority + nsISupportsPriority::PRIORITY_LOWEST; 52 const static int32_t kBestPriority = 53 kNormalPriority + nsISupportsPriority::PRIORITY_HIGHEST; 54 55 Http2Stream(nsAHttpTransaction *, Http2Session *, int32_t, uint64_t); 56 StreamID()57 uint32_t StreamID() { return mStreamID; } PushSource()58 Http2PushedStream *PushSource() { return mPushSource; } 59 void ClearPushSource(); 60 HTTPState()61 stateType HTTPState() { return mState; } SetHTTPState(stateType val)62 void SetHTTPState(stateType val) { mState = val; } 63 64 virtual MOZ_MUST_USE nsresult ReadSegments(nsAHttpSegmentReader *, uint32_t, 65 uint32_t *); 66 virtual MOZ_MUST_USE nsresult WriteSegments(nsAHttpSegmentWriter *, uint32_t, 67 uint32_t *); 68 virtual bool DeferCleanup(nsresult status); 69 70 // The consumer stream is the synthetic pull stream hooked up to this stream 71 // http2PushedStream overrides it GetConsumerStream()72 virtual Http2Stream *GetConsumerStream() { return nullptr; }; 73 Origin()74 const nsCString &Origin() const { return mOrigin; } Host()75 const nsCString &Host() const { return mHeaderHost; } Path()76 const nsCString &Path() const { return mHeaderPath; } 77 RequestBlockedOnRead()78 bool RequestBlockedOnRead() { 79 return static_cast<bool>(mRequestBlockedOnRead); 80 } 81 HasRegisteredID()82 bool HasRegisteredID() { return mStreamID != 0; } 83 Transaction()84 nsAHttpTransaction *Transaction() { return mTransaction; } RequestContext()85 virtual nsIRequestContext *RequestContext() { 86 return mTransaction ? mTransaction->RequestContext() : nullptr; 87 } 88 89 void Close(nsresult reason); 90 void SetResponseIsComplete(); 91 92 void SetRecvdFin(bool aStatus); RecvdFin()93 bool RecvdFin() { return mRecvdFin; } 94 SetRecvdData(bool aStatus)95 void SetRecvdData(bool aStatus) { mReceivedData = aStatus ? 1 : 0; } RecvdData()96 bool RecvdData() { return mReceivedData; } 97 98 void SetSentFin(bool aStatus); SentFin()99 bool SentFin() { return mSentFin; } 100 101 void SetRecvdReset(bool aStatus); RecvdReset()102 bool RecvdReset() { return mRecvdReset; } 103 104 void SetSentReset(bool aStatus); SentReset()105 bool SentReset() { return mSentReset; } 106 SetQueued(bool aStatus)107 void SetQueued(bool aStatus) { mQueued = aStatus ? 1 : 0; } Queued()108 bool Queued() { return mQueued; } 109 SetCountAsActive(bool aStatus)110 void SetCountAsActive(bool aStatus) { mCountAsActive = aStatus ? 1 : 0; } CountAsActive()111 bool CountAsActive() { return mCountAsActive; } 112 113 void SetAllHeadersReceived(); UnsetAllHeadersReceived()114 void UnsetAllHeadersReceived() { mAllHeadersReceived = 0; } AllHeadersReceived()115 bool AllHeadersReceived() { return mAllHeadersReceived; } 116 117 void UpdateTransportSendEvents(uint32_t count); 118 void UpdateTransportReadEvents(uint32_t count); 119 120 // NS_ERROR_ABORT terminates stream, other failure terminates session 121 MOZ_MUST_USE nsresult ConvertResponseHeaders(Http2Decompressor *, 122 nsACString &, nsACString &, 123 int32_t &); 124 MOZ_MUST_USE nsresult ConvertPushHeaders(Http2Decompressor *, nsACString &, 125 nsACString &); 126 MOZ_MUST_USE nsresult ConvertResponseTrailers(Http2Decompressor *, 127 nsACString &); 128 129 bool AllowFlowControlledWrite(); 130 void UpdateServerReceiveWindow(int32_t delta); ServerReceiveWindow()131 int64_t ServerReceiveWindow() { return mServerReceiveWindow; } 132 DecrementClientReceiveWindow(uint32_t delta)133 void DecrementClientReceiveWindow(uint32_t delta) { 134 mClientReceiveWindow -= delta; 135 mLocalUnacked += delta; 136 } 137 IncrementClientReceiveWindow(uint32_t delta)138 void IncrementClientReceiveWindow(uint32_t delta) { 139 mClientReceiveWindow += delta; 140 mLocalUnacked -= delta; 141 } 142 143 uint64_t LocalUnAcked(); ClientReceiveWindow()144 int64_t ClientReceiveWindow() { return mClientReceiveWindow; } 145 BlockedOnRwin()146 bool BlockedOnRwin() { return mBlockedOnRwin; } 147 Priority()148 uint32_t Priority() { return mPriority; } 149 void SetPriority(uint32_t); 150 void SetPriorityDependency(uint32_t, uint8_t, bool); 151 void UpdatePriorityDependency(); 152 153 // A pull stream has an implicit sink, a pushed stream has a sink 154 // once it is matched to a pull stream. HasSink()155 virtual bool HasSink() { return true; } 156 157 // This is a no-op on pull streams. Pushed streams override this. SetPushComplete()158 virtual void SetPushComplete(){}; 159 160 virtual ~Http2Stream(); 161 Session()162 Http2Session *Session() { return mSession; } 163 164 static MOZ_MUST_USE nsresult MakeOriginURL(const nsACString &origin, 165 nsCOMPtr<nsIURI> &url); 166 167 static MOZ_MUST_USE nsresult MakeOriginURL(const nsACString &scheme, 168 const nsACString &origin, 169 nsCOMPtr<nsIURI> &url); 170 171 // Mirrors nsAHttpTransaction 172 bool Do0RTT(); 173 nsresult Finish0RTT(bool aRestart, bool aAlpnIgnored); 174 175 nsresult GetOriginAttributes(mozilla::OriginAttributes *oa); 176 177 void TopLevelOuterContentWindowIdChanged(uint64_t windowId); 178 179 protected: 180 static void CreatePushHashKey( 181 const nsCString &scheme, const nsCString &hostHeader, 182 const mozilla::OriginAttributes &originAttributes, uint64_t serial, 183 const nsACString &pathInfo, nsCString &outOrigin, nsCString &outKey); 184 185 // These internal states track request generation 186 enum upstreamStateType { 187 GENERATING_HEADERS, 188 GENERATING_BODY, 189 SENDING_BODY, 190 SENDING_FIN_STREAM, 191 UPSTREAM_COMPLETE 192 }; 193 194 uint32_t mStreamID; 195 196 // The session that this stream is a subset of 197 Http2Session *mSession; 198 199 // These are temporary state variables to hold the argument to 200 // Read/WriteSegments so it can be accessed by On(read/write)segment 201 // further up the stack. 202 nsAHttpSegmentReader *mSegmentReader; 203 nsAHttpSegmentWriter *mSegmentWriter; 204 205 nsCString mOrigin; 206 nsCString mHeaderHost; 207 nsCString mHeaderScheme; 208 nsCString mHeaderPath; 209 210 // Each stream goes from generating_headers to upstream_complete, perhaps 211 // looping on multiple instances of generating_body and 212 // sending_body for each frame in the upload. 213 enum upstreamStateType mUpstreamState; 214 215 // The HTTP/2 state for the stream from section 5.1 216 enum stateType mState; 217 218 // Flag is set when all http request headers have been read ID is not stable 219 uint32_t mRequestHeadersDone : 1; 220 221 // Flag is set when ID is stable and concurrency limits are met 222 uint32_t mOpenGenerated : 1; 223 224 // Flag is set when all http response headers have been read 225 uint32_t mAllHeadersReceived : 1; 226 227 // Flag is set when stream is queued inside the session due to 228 // concurrency limits being exceeded 229 uint32_t mQueued : 1; 230 231 void ChangeState(enum upstreamStateType); 232 233 virtual void AdjustInitialWindow(); 234 MOZ_MUST_USE nsresult TransmitFrame(const char *, uint32_t *, 235 bool forceCommitment); 236 237 // The underlying socket transport object is needed to propogate some events 238 nsISocketTransport *mSocketTransport; 239 240 private: 241 friend class nsAutoPtr<Http2Stream>; 242 243 MOZ_MUST_USE nsresult ParseHttpRequestHeaders(const char *, uint32_t, 244 uint32_t *); 245 MOZ_MUST_USE nsresult GenerateOpen(); 246 247 void AdjustPushedPriority(); 248 void GenerateDataFrameHeader(uint32_t, bool); 249 250 MOZ_MUST_USE nsresult BufferInput(uint32_t, uint32_t *); 251 252 // The underlying HTTP transaction. This pointer is used as the key 253 // in the Http2Session mStreamTransactionHash so it is important to 254 // keep a reference to it as long as this stream is a member of that hash. 255 // (i.e. don't change it or release it after it is set in the ctor). 256 RefPtr<nsAHttpTransaction> mTransaction; 257 258 // The quanta upstream data frames are chopped into 259 uint32_t mChunkSize; 260 261 // Flag is set when the HTTP processor has more data to send 262 // but has blocked in doing so. 263 uint32_t mRequestBlockedOnRead : 1; 264 265 // Flag is set after the response frame bearing the fin bit has 266 // been processed. (i.e. after the server has closed). 267 uint32_t mRecvdFin : 1; 268 269 // Flag is set after 1st DATA frame has been passed to stream 270 uint32_t mReceivedData : 1; 271 272 // Flag is set after RST_STREAM has been received for this stream 273 uint32_t mRecvdReset : 1; 274 275 // Flag is set after RST_STREAM has been generated for this stream 276 uint32_t mSentReset : 1; 277 278 // Flag is set when stream is counted towards MAX_CONCURRENT streams in 279 // session 280 uint32_t mCountAsActive : 1; 281 282 // Flag is set when a FIN has been placed on a data or header frame 283 // (i.e after the client has closed) 284 uint32_t mSentFin : 1; 285 286 // Flag is set after the WAITING_FOR Transport event has been generated 287 uint32_t mSentWaitingFor : 1; 288 289 // Flag is set after TCP send autotuning has been disabled 290 uint32_t mSetTCPSocketBuffer : 1; 291 292 // Flag is set when OnWriteSegment is being called directly from stream 293 // instead of transaction 294 uint32_t mBypassInputBuffer : 1; 295 296 // The InlineFrame and associated data is used for composing control 297 // frames and data frame headers. 298 UniquePtr<uint8_t[]> mTxInlineFrame; 299 uint32_t mTxInlineFrameSize; 300 uint32_t mTxInlineFrameUsed; 301 302 // mTxStreamFrameSize tracks the progress of 303 // transmitting a request body data frame. The data frame itself 304 // is never copied into the spdy layer. 305 uint32_t mTxStreamFrameSize; 306 307 // Buffer for request header compression. 308 nsCString mFlatHttpRequestHeaders; 309 310 // Track the content-length of a request body so that we can 311 // place the fin flag on the last data packet instead of waiting 312 // for a stream closed indication. Relying on stream close results 313 // in an extra 0-length runt packet and seems to have some interop 314 // problems with the google servers. Connect does rely on stream 315 // close by setting this to the max value. 316 int64_t mRequestBodyLenRemaining; 317 318 uint32_t mPriority; // geckoish weight 319 uint32_t mPriorityDependency; // h2 stream id 3 - 0xb 320 uint8_t mPriorityWeight; // h2 weight 321 322 // mClientReceiveWindow, mServerReceiveWindow, and mLocalUnacked are for flow 323 // control. *window are signed because the race conditions in asynchronous 324 // SETTINGS messages can force them temporarily negative. 325 326 // mClientReceiveWindow is how much data the server will send without getting 327 // a 328 // window update 329 int64_t mClientReceiveWindow; 330 331 // mServerReceiveWindow is how much data the client is allowed to send without 332 // getting a window update 333 int64_t mServerReceiveWindow; 334 335 // LocalUnacked is the number of bytes received by the client but not 336 // yet reflected in a window update. Sending that update will increment 337 // ClientReceiveWindow 338 uint64_t mLocalUnacked; 339 340 // True when sending is suspended becuase the server receive window is 341 // <= 0 342 bool mBlockedOnRwin; 343 344 // For Progress Events 345 uint64_t mTotalSent; 346 uint64_t mTotalRead; 347 348 // For Http2Push 349 Http2PushedStream *mPushSource; 350 351 // Used to store stream data when the transaction channel cannot keep up 352 // and flow control has not yet kicked in. 353 SimpleBuffer mSimpleBuffer; 354 355 bool mAttempting0RTT; 356 357 uint64_t mCurrentForegroundTabOuterContentWindowId; 358 359 uint64_t mTransactionTabId; 360 361 /// connect tunnels 362 public: IsTunnel()363 bool IsTunnel() { return mIsTunnel; } 364 365 private: 366 void ClearTransactionsBlockedOnTunnel(); 367 void MapStreamToPlainText(); 368 void MapStreamToHttpConnection(); 369 370 bool mIsTunnel; 371 bool mPlainTextTunnel; 372 }; 373 374 } // namespace net 375 } // namespace mozilla 376 377 #endif // mozilla_net_Http2Stream_h 378