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