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