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/. */
6 #ifndef mozilla_net_Http2StreamBase_h
7 #define mozilla_net_Http2StreamBase_h
10 // https://www.rfc-editor.org/rfc/rfc7540.txt
12 #include "mozilla/Attributes.h"
13 #include "mozilla/UniquePtr.h"
14 #include "mozilla/WeakPtr.h"
15 #include "nsAHttpTransaction.h"
16 #include "nsISupportsPriority.h"
17 #include "SimpleBuffer.h"
18 #include "nsISupportsImpl.h"
21 class nsISocketTransport
;
23 class nsIOutputStream
;
26 class OriginAttributes
;
29 namespace mozilla::net
{
34 class Http2PushedStream
;
35 class Http2Decompressor
;
37 class Http2StreamBase
: public nsAHttpSegmentReader
,
38 public nsAHttpSegmentWriter
,
39 public SupportsWeakPtr
{
41 NS_DECL_NSAHTTPSEGMENTREADER
52 const static int32_t kNormalPriority
= 0x1000;
53 const static int32_t kWorstPriority
=
54 kNormalPriority
+ nsISupportsPriority::PRIORITY_LOWEST
;
55 const static int32_t kBestPriority
=
56 kNormalPriority
+ nsISupportsPriority::PRIORITY_HIGHEST
;
58 Http2StreamBase(uint64_t, Http2Session
*, int32_t, uint64_t);
60 uint32_t StreamID() { return mStreamID
; }
62 stateType
HTTPState() { return mState
; }
63 void SetHTTPState(stateType val
) { mState
= val
; }
65 [[nodiscard
]] virtual nsresult
ReadSegments(nsAHttpSegmentReader
*, uint32_t,
67 [[nodiscard
]] virtual nsresult
WriteSegments(nsAHttpSegmentWriter
*, uint32_t,
69 virtual bool DeferCleanup(nsresult status
);
71 const nsCString
& Origin() const { return mOrigin
; }
72 const nsCString
& Host() const { return mHeaderHost
; }
73 const nsCString
& Path() const { return mHeaderPath
; }
75 bool RequestBlockedOnRead() {
76 return static_cast<bool>(mRequestBlockedOnRead
);
79 bool HasRegisteredID() { return mStreamID
!= 0; }
81 virtual nsAHttpTransaction
* Transaction() { return nullptr; }
82 nsHttpTransaction
* HttpTransaction();
83 virtual nsIRequestContext
* RequestContext() { return nullptr; }
85 virtual void CloseStream(nsresult reason
) = 0;
86 void SetResponseIsComplete();
88 void SetRecvdFin(bool aStatus
);
89 bool RecvdFin() { return mRecvdFin
; }
91 void SetRecvdData(bool aStatus
) { mReceivedData
= aStatus
? 1 : 0; }
92 bool RecvdData() { return mReceivedData
; }
94 void SetSentFin(bool aStatus
);
95 bool SentFin() { return mSentFin
; }
97 void SetRecvdReset(bool aStatus
);
98 bool RecvdReset() { return mRecvdReset
; }
100 void SetSentReset(bool aStatus
);
101 bool SentReset() { return mSentReset
; }
103 void SetQueued(bool aStatus
) { mQueued
= aStatus
? 1 : 0; }
104 bool Queued() { return mQueued
; }
106 void SetCountAsActive(bool aStatus
) { mCountAsActive
= aStatus
? 1 : 0; }
107 bool CountAsActive() { return mCountAsActive
; }
109 void SetAllHeadersReceived();
110 void UnsetAllHeadersReceived() { mAllHeadersReceived
= 0; }
111 bool AllHeadersReceived() { return mAllHeadersReceived
; }
113 void UpdateTransportSendEvents(uint32_t count
);
114 void UpdateTransportReadEvents(uint32_t count
);
116 // NS_ERROR_ABORT terminates stream, other failure terminates session
117 [[nodiscard
]] nsresult
ConvertResponseHeaders(Http2Decompressor
*, nsACString
&,
118 nsACString
&, int32_t&);
119 [[nodiscard
]] nsresult
ConvertResponseTrailers(Http2Decompressor
*,
122 bool AllowFlowControlledWrite();
123 void UpdateServerReceiveWindow(int32_t delta
);
124 int64_t ServerReceiveWindow() { return mServerReceiveWindow
; }
126 void DecrementClientReceiveWindow(uint32_t delta
) {
127 mClientReceiveWindow
-= delta
;
128 mLocalUnacked
+= delta
;
131 void IncrementClientReceiveWindow(uint32_t delta
) {
132 mClientReceiveWindow
+= delta
;
133 mLocalUnacked
-= delta
;
136 uint64_t LocalUnAcked();
137 int64_t ClientReceiveWindow() { return mClientReceiveWindow
; }
139 bool BlockedOnRwin() { return mBlockedOnRwin
; }
141 uint32_t RFC7540Priority() { return mRFC7540Priority
; }
142 uint32_t PriorityDependency() { return mPriorityDependency
; }
143 uint8_t PriorityWeight() { return mPriorityWeight
; }
144 void SetPriority(uint32_t);
145 void SetPriorityDependency(uint32_t, uint32_t);
146 void UpdatePriorityDependency();
148 uint64_t TransactionBrowserId() { return mTransactionBrowserId
; }
150 // A pull stream has an implicit sink, a pushed stream has a sink
151 // once it is matched to a pull stream.
152 virtual bool HasSink() { return true; }
154 already_AddRefed
<Http2Session
> Session();
156 // Mirrors nsAHttpTransaction
158 nsresult
Finish0RTT(bool aRestart
, bool aAlpnChanged
);
160 nsresult
GetOriginAttributes(mozilla::OriginAttributes
* oa
);
162 virtual void CurrentBrowserIdChanged(uint64_t id
);
163 // For use by pushed streams only
164 void CurrentBrowserIdChangedInternal(uint64_t id
);
166 virtual void UpdatePriorityRFC7540(Http2Session
* session
);
167 virtual void UpdatePriority(Http2Session
* session
);
169 virtual bool IsTunnel() { return false; }
171 virtual uint32_t GetWireStreamId() { return mStreamID
; }
172 virtual Http2Stream
* GetHttp2Stream() { return nullptr; }
173 virtual Http2PushedStream
* GetHttp2PushedStream() { return nullptr; }
175 [[nodiscard
]] virtual nsresult
OnWriteSegment(char*, uint32_t,
178 virtual nsHttpConnectionInfo
* ConnectionInfo();
180 bool DataBuffered() { return mSimpleBuffer
.Available(); }
182 virtual nsresult
Condition() { return NS_OK
; }
184 virtual void DisableSpdy() {
186 Transaction()->DisableSpdy();
189 virtual void ReuseConnectionOnRestartOK(bool aReuse
) {
191 Transaction()->ReuseConnectionOnRestartOK(aReuse
);
194 virtual void MakeNonSticky() {
196 Transaction()->MakeNonSticky();
201 virtual ~Http2StreamBase();
203 virtual void HandleResponseHeaders(nsACString
& aHeadersOut
,
204 int32_t httpResponseCode
) {}
205 virtual nsresult
CallToWriteData(uint32_t count
, uint32_t* countRead
) = 0;
206 virtual nsresult
CallToReadData(uint32_t count
, uint32_t* countWritten
) = 0;
207 virtual bool CloseSendStreamWhenDone() { return true; }
209 // These internal states track request generation
210 enum upstreamStateType
{
218 uint32_t mStreamID
{0};
220 // The session that this stream is a subset of
223 // These are temporary state variables to hold the argument to
224 // Read/WriteSegments so it can be accessed by On(read/write)segment
225 // further up the stack.
226 RefPtr
<nsAHttpSegmentReader
> mSegmentReader
;
227 nsAHttpSegmentWriter
* mSegmentWriter
{nullptr};
230 nsCString mHeaderHost
;
231 nsCString mHeaderScheme
;
232 nsCString mHeaderPath
;
234 // Each stream goes from generating_headers to upstream_complete, perhaps
235 // looping on multiple instances of generating_body and
236 // sending_body for each frame in the upload.
237 enum upstreamStateType mUpstreamState
{ GENERATING_HEADERS
};
239 // The HTTP/2 state for the stream from section 5.1
240 enum stateType mState
{ IDLE
};
242 // Flag is set when all http request headers have been read ID is not stable
243 uint32_t mRequestHeadersDone
: 1;
245 // Flag is set when ID is stable and concurrency limits are met
246 uint32_t mOpenGenerated
: 1;
248 // Flag is set when all http response headers have been read
249 uint32_t mAllHeadersReceived
: 1;
251 // Flag is set when stream is queued inside the session due to
252 // concurrency limits being exceeded
253 uint32_t mQueued
: 1;
255 void ChangeState(enum upstreamStateType
);
257 virtual void AdjustInitialWindow();
258 [[nodiscard
]] nsresult
TransmitFrame(const char*, uint32_t*,
259 bool forceCommitment
);
261 // The underlying socket transport object is needed to propogate some events
262 nsCOMPtr
<nsISocketTransport
> mSocketTransport
;
264 uint8_t mPriorityWeight
= 0; // h2 weight
265 uint32_t mPriorityDependency
= 0; // h2 stream id this one depends on
266 uint64_t mCurrentBrowserId
;
267 uint64_t mTransactionBrowserId
{0};
269 // The InlineFrame and associated data is used for composing control
270 // frames and data frame headers.
271 UniquePtr
<uint8_t[]> mTxInlineFrame
;
272 uint32_t mTxInlineFrameSize
{0};
273 uint32_t mTxInlineFrameUsed
{0};
275 uint32_t mRFC7540Priority
= 0; // geckoish weight
277 // Buffer for request header compression.
278 nsCString mFlatHttpRequestHeaders
;
280 // Track the content-length of a request body so that we can
281 // place the fin flag on the last data packet instead of waiting
282 // for a stream closed indication. Relying on stream close results
283 // in an extra 0-length runt packet and seems to have some interop
284 // problems with the google servers. Connect does rely on stream
285 // close by setting this to the max value.
286 int64_t mRequestBodyLenRemaining
{0};
289 friend class mozilla::DefaultDelete
<Http2StreamBase
>;
291 [[nodiscard
]] nsresult
ParseHttpRequestHeaders(const char*, uint32_t,
293 [[nodiscard
]] nsresult
GenerateOpen();
295 virtual nsresult
GenerateHeaders(nsCString
& aCompressedData
,
296 uint8_t& firstFrameFlags
) = 0;
298 void GenerateDataFrameHeader(uint32_t, bool);
300 [[nodiscard
]] nsresult
BufferInput(uint32_t, uint32_t*);
302 // The quanta upstream data frames are chopped into
305 // Flag is set when the HTTP processor has more data to send
306 // but has blocked in doing so.
307 uint32_t mRequestBlockedOnRead
: 1;
309 // Flag is set after the response frame bearing the fin bit has
310 // been processed. (i.e. after the server has closed).
311 uint32_t mRecvdFin
: 1;
313 // Flag is set after 1st DATA frame has been passed to stream
314 uint32_t mReceivedData
: 1;
316 // Flag is set after RST_STREAM has been received for this stream
317 uint32_t mRecvdReset
: 1;
319 // Flag is set after RST_STREAM has been generated for this stream
320 uint32_t mSentReset
: 1;
322 // Flag is set when stream is counted towards MAX_CONCURRENT streams in
324 uint32_t mCountAsActive
: 1;
326 // Flag is set when a FIN has been placed on a data or header frame
327 // (i.e after the client has closed)
328 uint32_t mSentFin
: 1;
330 // Flag is set after the WAITING_FOR Transport event has been generated
331 uint32_t mSentWaitingFor
: 1;
333 // Flag is set after TCP send autotuning has been disabled
334 uint32_t mSetTCPSocketBuffer
: 1;
336 // Flag is set when OnWriteSegment is being called directly from stream
337 // instead of transaction
338 uint32_t mBypassInputBuffer
: 1;
340 // mTxStreamFrameSize tracks the progress of
341 // transmitting a request body data frame. The data frame itself
342 // is never copied into the spdy layer.
343 uint32_t mTxStreamFrameSize
{0};
345 // mClientReceiveWindow, mServerReceiveWindow, and mLocalUnacked are for flow
346 // control. *window are signed because the race conditions in asynchronous
347 // SETTINGS messages can force them temporarily negative.
349 // mClientReceiveWindow is how much data the server will send without getting
352 int64_t mClientReceiveWindow
;
354 // mServerReceiveWindow is how much data the client is allowed to send without
355 // getting a window update
356 int64_t mServerReceiveWindow
;
358 // LocalUnacked is the number of bytes received by the client but not
359 // yet reflected in a window update. Sending that update will increment
360 // ClientReceiveWindow
361 uint64_t mLocalUnacked
{0};
363 // True when sending is suspended becuase the server receive window is
365 bool mBlockedOnRwin
{false};
367 // For Progress Events
368 uint64_t mTotalSent
{0};
369 uint64_t mTotalRead
{0};
371 // Used to store stream data when the transaction channel cannot keep up
372 // and flow control has not yet kicked in.
373 SimpleBuffer mSimpleBuffer
;
375 bool mAttempting0RTT
{false};
378 } // namespace mozilla::net
380 #endif // mozilla_net_Http2StreamBase_h