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