/src/mozilla-central/netwerk/protocol/http/nsHttpTransaction.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
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 nsHttpTransaction_h__ |
7 | | #define nsHttpTransaction_h__ |
8 | | |
9 | | #include "nsHttp.h" |
10 | | #include "nsAHttpTransaction.h" |
11 | | #include "nsAHttpConnection.h" |
12 | | #include "EventTokenBucket.h" |
13 | | #include "nsCOMPtr.h" |
14 | | #include "nsThreadUtils.h" |
15 | | #include "nsIInterfaceRequestor.h" |
16 | | #include "TimingStruct.h" |
17 | | #include "Http2Push.h" |
18 | | #include "mozilla/net/DNS.h" |
19 | | #include "ARefBase.h" |
20 | | #include "AlternateServices.h" |
21 | | |
22 | | //----------------------------------------------------------------------------- |
23 | | |
24 | | class nsIHttpActivityObserver; |
25 | | class nsIEventTarget; |
26 | | class nsIInputStream; |
27 | | class nsIOutputStream; |
28 | | class nsIRequestContext; |
29 | | |
30 | | namespace mozilla { namespace net { |
31 | | |
32 | | class nsHttpChunkedDecoder; |
33 | | class nsHttpHeaderArray; |
34 | | class nsHttpRequestHead; |
35 | | class nsHttpResponseHead; |
36 | | |
37 | | //----------------------------------------------------------------------------- |
38 | | // nsHttpTransaction represents a single HTTP transaction. It is thread-safe, |
39 | | // intended to run on the socket thread. |
40 | | //----------------------------------------------------------------------------- |
41 | | |
42 | | class nsHttpTransaction final : public nsAHttpTransaction |
43 | | , public ATokenBucketEvent |
44 | | , public nsIInputStreamCallback |
45 | | , public nsIOutputStreamCallback |
46 | | , public ARefBase |
47 | | { |
48 | | public: |
49 | | NS_DECL_THREADSAFE_ISUPPORTS |
50 | | NS_DECL_NSAHTTPTRANSACTION |
51 | | NS_DECL_NSIINPUTSTREAMCALLBACK |
52 | | NS_DECL_NSIOUTPUTSTREAMCALLBACK |
53 | | |
54 | | nsHttpTransaction(); |
55 | | |
56 | | // |
57 | | // called to initialize the transaction |
58 | | // |
59 | | // @param caps |
60 | | // the transaction capabilities (see nsHttp.h) |
61 | | // @param connInfo |
62 | | // the connection type for this transaction. |
63 | | // @param reqHeaders |
64 | | // the request header struct |
65 | | // @param reqBody |
66 | | // the request body (POST or PUT data stream) |
67 | | // @param reqBodyIncludesHeaders |
68 | | // fun stuff to support NPAPI plugins. |
69 | | // @param target |
70 | | // the dispatch target were notifications should be sent. |
71 | | // @param callbacks |
72 | | // the notification callbacks to be given to PSM. |
73 | | // @param topLevelOuterContentWindowId |
74 | | // indicate the top level outer content window in which |
75 | | // this transaction is being loaded. |
76 | | // @param responseBody |
77 | | // the input stream that will contain the response data. async |
78 | | // wait on this input stream for data. on first notification, |
79 | | // headers should be available (check transaction status). |
80 | | // |
81 | | MOZ_MUST_USE nsresult Init(uint32_t caps, |
82 | | nsHttpConnectionInfo *connInfo, |
83 | | nsHttpRequestHead *reqHeaders, |
84 | | nsIInputStream *reqBody, |
85 | | uint64_t reqContentLength, |
86 | | bool reqBodyIncludesHeaders, |
87 | | nsIEventTarget *consumerTarget, |
88 | | nsIInterfaceRequestor *callbacks, |
89 | | nsITransportEventSink *eventsink, |
90 | | uint64_t topLevelOuterContentWindowId, |
91 | | nsIAsyncInputStream **responseBody); |
92 | | |
93 | | void OnActivated() override; |
94 | | |
95 | | // attributes |
96 | 0 | nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nullptr; } |
97 | 0 | nsISupports *SecurityInfo() { return mSecurityInfo; } |
98 | | |
99 | 0 | nsIEventTarget *ConsumerTarget() { return mConsumerTarget; } |
100 | 0 | nsISupports *HttpChannel() { return mChannel; } |
101 | | |
102 | | void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks); |
103 | | |
104 | | // Called to take ownership of the response headers; the transaction |
105 | | // will drop any reference to the response headers after this call. |
106 | | nsHttpResponseHead *TakeResponseHead(); |
107 | | |
108 | | // Called to take ownership of the trailer headers. |
109 | | // Returning null if there is no trailer. |
110 | | nsHttpHeaderArray *TakeResponseTrailers(); |
111 | | |
112 | | // Provides a thread safe reference of the connection |
113 | | // nsHttpTransaction::Connection should only be used on the socket thread |
114 | | already_AddRefed<nsAHttpConnection> GetConnectionReference(); |
115 | | |
116 | | // Called to set/find out if the transaction generated a complete response. |
117 | 0 | bool ResponseIsComplete() { return mResponseIsComplete; } |
118 | 0 | void SetResponseIsComplete() { mResponseIsComplete = true; } |
119 | | |
120 | 0 | bool ProxyConnectFailed() { return mProxyConnectFailed; } |
121 | | |
122 | 0 | void EnableKeepAlive() { mCaps |= NS_HTTP_ALLOW_KEEPALIVE; } |
123 | 0 | void MakeSticky() { mCaps |= NS_HTTP_STICKY_CONNECTION; } |
124 | | |
125 | | // SetPriority() may only be used by the connection manager. |
126 | 0 | void SetPriority(int32_t priority) { mPriority = priority; } |
127 | 0 | int32_t Priority() { return mPriority; } |
128 | | |
129 | | void PrintDiagnostics(nsCString &log); |
130 | | |
131 | | // Sets mPendingTime to the current time stamp or to a null time stamp (if now is false) |
132 | 0 | void SetPendingTime(bool now = true) { mPendingTime = now ? TimeStamp::Now() : TimeStamp(); } |
133 | 0 | const TimeStamp GetPendingTime() { return mPendingTime; } |
134 | | |
135 | | // overload of nsAHttpTransaction::RequestContext() |
136 | 0 | nsIRequestContext *RequestContext() override { return mRequestContext.get(); } |
137 | | void SetRequestContext(nsIRequestContext *aRequestContext); |
138 | | void DispatchedAsBlocking(); |
139 | | void RemoveDispatchedAsBlocking(); |
140 | | |
141 | 0 | nsHttpTransaction *QueryHttpTransaction() override { return this; } |
142 | | |
143 | 0 | Http2PushedStream *GetPushedStream() { return mPushedStream; } |
144 | | Http2PushedStream *TakePushedStream() |
145 | 0 | { |
146 | 0 | Http2PushedStream *r = mPushedStream; |
147 | 0 | mPushedStream = nullptr; |
148 | 0 | return r; |
149 | 0 | } |
150 | 0 | void SetPushedStream(Http2PushedStream *push) { mPushedStream = push; } |
151 | 0 | uint32_t InitialRwin() const { return mInitialRwin; }; |
152 | 0 | bool ChannelPipeFull() { return mWaitingOnPipeOut; } |
153 | | |
154 | | // Locked methods to get and set timing info |
155 | | const TimingStruct Timings(); |
156 | | void BootstrapTimings(TimingStruct times); |
157 | | void SetDomainLookupStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); |
158 | | void SetDomainLookupEnd(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); |
159 | | void SetConnectStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); |
160 | | void SetConnectEnd(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); |
161 | | void SetRequestStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); |
162 | | void SetResponseStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); |
163 | | void SetResponseEnd(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); |
164 | | |
165 | | mozilla::TimeStamp GetDomainLookupStart(); |
166 | | mozilla::TimeStamp GetDomainLookupEnd(); |
167 | | mozilla::TimeStamp GetConnectStart(); |
168 | | mozilla::TimeStamp GetTcpConnectEnd(); |
169 | | mozilla::TimeStamp GetSecureConnectionStart(); |
170 | | |
171 | | mozilla::TimeStamp GetConnectEnd(); |
172 | | mozilla::TimeStamp GetRequestStart(); |
173 | | mozilla::TimeStamp GetResponseStart(); |
174 | | mozilla::TimeStamp GetResponseEnd(); |
175 | | |
176 | 0 | int64_t GetTransferSize() { return mTransferSize; } |
177 | | |
178 | | MOZ_MUST_USE bool Do0RTT() override; |
179 | | MOZ_MUST_USE nsresult Finish0RTT(bool aRestart, bool aAlpnChanged /* ignored */) override; |
180 | | |
181 | | // After Finish0RTT early data may have failed but the caller did not request |
182 | | // restart - this indicates that state for dev tools |
183 | | void Refused0RTT(); |
184 | | |
185 | | MOZ_MUST_USE bool CanDo0RTT() override; |
186 | | MOZ_MUST_USE nsresult RestartOnFastOpenError() override; |
187 | | |
188 | | uint64_t TopLevelOuterContentWindowId() override |
189 | 0 | { |
190 | 0 | return mTopLevelOuterContentWindowId; |
191 | 0 | } |
192 | | |
193 | | void SetFastOpenStatus(uint8_t aStatus) override; |
194 | | |
195 | | void SetHttpTrailers(nsCString &aTrailers); |
196 | | private: |
197 | | friend class DeleteHttpTransaction; |
198 | | virtual ~nsHttpTransaction(); |
199 | | |
200 | | MOZ_MUST_USE nsresult Restart(); |
201 | | char *LocateHttpStart(char *buf, uint32_t len, |
202 | | bool aAllowPartialMatch); |
203 | | MOZ_MUST_USE nsresult ParseLine(nsACString &line); |
204 | | MOZ_MUST_USE nsresult ParseLineSegment(char *seg, uint32_t len); |
205 | | MOZ_MUST_USE nsresult ParseHead(char *, uint32_t count, |
206 | | uint32_t *countRead); |
207 | | MOZ_MUST_USE nsresult HandleContentStart(); |
208 | | MOZ_MUST_USE nsresult HandleContent(char *, uint32_t count, |
209 | | uint32_t *contentRead, |
210 | | uint32_t *contentRemaining); |
211 | | MOZ_MUST_USE nsresult ProcessData(char *, uint32_t, uint32_t *); |
212 | | void DeleteSelfOnConsumerThread(); |
213 | | void ReleaseBlockingTransaction(); |
214 | | |
215 | | static MOZ_MUST_USE nsresult ReadRequestSegment(nsIInputStream *, void *, |
216 | | const char *, uint32_t, |
217 | | uint32_t, uint32_t *); |
218 | | static MOZ_MUST_USE nsresult WritePipeSegment(nsIOutputStream *, void *, |
219 | | char *, uint32_t, uint32_t, |
220 | | uint32_t *); |
221 | | |
222 | 0 | bool TimingEnabled() const { return mCaps & NS_HTTP_TIMING_ENABLED; } |
223 | | |
224 | | bool ResponseTimeoutEnabled() const final; |
225 | | |
226 | | void DisableSpdy() override; |
227 | 0 | void ReuseConnectionOnRestartOK(bool reuseOk) override { mReuseOnRestart = reuseOk; } |
228 | | |
229 | | // Called right after we parsed the response head. Checks for connection based |
230 | | // authentication schemes in reponse headers for WWW and Proxy authentication. |
231 | | // If such is found in any of them, NS_HTTP_STICKY_CONNECTION is set in mCaps. |
232 | | // We need the sticky flag be set early to keep the connection from very start |
233 | | // of the authentication process. |
234 | | void CheckForStickyAuthScheme(); |
235 | | void CheckForStickyAuthSchemeAt(nsHttpAtom const& header); |
236 | | |
237 | | // Called from WriteSegments. Checks for conditions whether to throttle reading |
238 | | // the content. When this returns true, WriteSegments returns WOULD_BLOCK. |
239 | | bool ShouldThrottle(); |
240 | | |
241 | | private: |
242 | | class UpdateSecurityCallbacks : public Runnable |
243 | | { |
244 | | public: |
245 | | UpdateSecurityCallbacks(nsHttpTransaction* aTrans, |
246 | | nsIInterfaceRequestor* aCallbacks) |
247 | | : Runnable("net::nsHttpTransaction::UpdateSecurityCallbacks") |
248 | | , mTrans(aTrans) |
249 | | , mCallbacks(aCallbacks) |
250 | 0 | { |
251 | 0 | } |
252 | | |
253 | | NS_IMETHOD Run() override |
254 | 0 | { |
255 | 0 | if (mTrans->mConnection) |
256 | 0 | mTrans->mConnection->SetSecurityCallbacks(mCallbacks); |
257 | 0 | return NS_OK; |
258 | 0 | } |
259 | | private: |
260 | | RefPtr<nsHttpTransaction> mTrans; |
261 | | nsCOMPtr<nsIInterfaceRequestor> mCallbacks; |
262 | | }; |
263 | | |
264 | | Mutex mLock; |
265 | | |
266 | | nsCOMPtr<nsIInterfaceRequestor> mCallbacks; |
267 | | nsCOMPtr<nsITransportEventSink> mTransportSink; |
268 | | nsCOMPtr<nsIEventTarget> mConsumerTarget; |
269 | | nsCOMPtr<nsISupports> mSecurityInfo; |
270 | | nsCOMPtr<nsIAsyncInputStream> mPipeIn; |
271 | | nsCOMPtr<nsIAsyncOutputStream> mPipeOut; |
272 | | nsCOMPtr<nsIRequestContext> mRequestContext; |
273 | | |
274 | | nsCOMPtr<nsISupports> mChannel; |
275 | | nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor; |
276 | | |
277 | | nsCString mReqHeaderBuf; // flattened request headers |
278 | | nsCOMPtr<nsIInputStream> mRequestStream; |
279 | | int64_t mRequestSize; |
280 | | |
281 | | RefPtr<nsAHttpConnection> mConnection; |
282 | | RefPtr<nsHttpConnectionInfo> mConnInfo; |
283 | | nsHttpRequestHead *mRequestHead; // weak ref |
284 | | nsHttpResponseHead *mResponseHead; // owning pointer |
285 | | |
286 | | nsAHttpSegmentReader *mReader; |
287 | | nsAHttpSegmentWriter *mWriter; |
288 | | |
289 | | nsCString mLineBuf; // may contain a partial line |
290 | | |
291 | | int64_t mContentLength; // equals -1 if unknown |
292 | | int64_t mContentRead; // count of consumed content bytes |
293 | | Atomic<int64_t, ReleaseAcquire> mTransferSize; // count of received bytes |
294 | | |
295 | | // After a 304/204 or other "no-content" style response we will skip over |
296 | | // up to MAX_INVALID_RESPONSE_BODY_SZ bytes when looking for the next |
297 | | // response header to deal with servers that actually sent a response |
298 | | // body where they should not have. This member tracks how many bytes have |
299 | | // so far been skipped. |
300 | | uint32_t mInvalidResponseBytesRead; |
301 | | |
302 | | Http2PushedStream *mPushedStream; |
303 | | uint32_t mInitialRwin; |
304 | | |
305 | | nsHttpChunkedDecoder *mChunkedDecoder; |
306 | | |
307 | | TimingStruct mTimings; |
308 | | |
309 | | nsresult mStatus; |
310 | | |
311 | | int16_t mPriority; |
312 | | |
313 | | uint16_t mRestartCount; // the number of times this transaction has been restarted |
314 | | uint32_t mCaps; |
315 | | |
316 | | HttpVersion mHttpVersion; |
317 | | uint16_t mHttpResponseCode; |
318 | | |
319 | | uint32_t mCurrentHttpResponseHeaderSize; |
320 | | |
321 | | int32_t const THROTTLE_NO_LIMIT = -1; |
322 | | // This can have 3 possible values: |
323 | | // * THROTTLE_NO_LIMIT - this means the transaction is not in any way limited |
324 | | // to read the response, this is the default |
325 | | // * a positive number - a limit is set because the transaction is obligated |
326 | | // to throttle the response read, this is decresed with |
327 | | // every piece of data the transaction receives |
328 | | // * zero - when the transaction depletes the limit for reading, this makes it |
329 | | // stop reading and return WOULD_BLOCK from WriteSegments; transaction |
330 | | // then waits for a call of ResumeReading that resets this member back |
331 | | // to THROTTLE_NO_LIMIT |
332 | | int32_t mThrottlingReadAllowance; |
333 | | |
334 | | // mCapsToClear holds flags that should be cleared in mCaps, e.g. unset |
335 | | // NS_HTTP_REFRESH_DNS when DNS refresh request has completed to avoid |
336 | | // redundant requests on the network. The member itself is atomic, but |
337 | | // access to it from the networking thread may happen either before or |
338 | | // after the main thread modifies it. To deal with raciness, only unsetting |
339 | | // bitfields should be allowed: 'lost races' will thus err on the |
340 | | // conservative side, e.g. by going ahead with a 2nd DNS refresh. |
341 | | Atomic<uint32_t> mCapsToClear; |
342 | | Atomic<bool, ReleaseAcquire> mResponseIsComplete; |
343 | | |
344 | | // True iff WriteSegments was called while this transaction should be throttled (stop reading) |
345 | | // Used to resume read on unblock of reading. Conn manager is responsible for calling back |
346 | | // to resume reading. |
347 | | bool mReadingStopped; |
348 | | |
349 | | // state flags, all logically boolean, but not packed together into a |
350 | | // bitfield so as to avoid bitfield-induced races. See bug 560579. |
351 | | bool mClosed; |
352 | | bool mConnected; |
353 | | bool mActivated; |
354 | | bool mHaveStatusLine; |
355 | | bool mHaveAllHeaders; |
356 | | bool mTransactionDone; |
357 | | bool mDidContentStart; |
358 | | bool mNoContent; // expecting an empty entity body |
359 | | bool mSentData; |
360 | | bool mReceivedData; |
361 | | bool mStatusEventPending; |
362 | | bool mHasRequestBody; |
363 | | bool mProxyConnectFailed; |
364 | | bool mHttpResponseMatched; |
365 | | bool mPreserveStream; |
366 | | bool mDispatchedAsBlocking; |
367 | | bool mResponseTimeoutEnabled; |
368 | | bool mForceRestart; |
369 | | bool mReuseOnRestart; |
370 | | bool mContentDecoding; |
371 | | bool mContentDecodingCheck; |
372 | | bool mDeferredSendProgress; |
373 | | bool mWaitingOnPipeOut; |
374 | | |
375 | | // mClosed := transaction has been explicitly closed |
376 | | // mTransactionDone := transaction ran to completion or was interrupted |
377 | | // mResponseComplete := transaction ran to completion |
378 | | |
379 | | // For Restart-In-Progress Functionality |
380 | | bool mReportedStart; |
381 | | bool mReportedResponseHeader; |
382 | | |
383 | | // protected by nsHttp::GetLock() |
384 | | bool mResponseHeadTaken; |
385 | | nsAutoPtr<nsHttpHeaderArray> mForTakeResponseTrailers; |
386 | | bool mResponseTrailersTaken; |
387 | | |
388 | | // The time when the transaction was submitted to the Connection Manager |
389 | | TimeStamp mPendingTime; |
390 | | |
391 | | uint64_t mTopLevelOuterContentWindowId; |
392 | | |
393 | | // For Rate Pacing via an EventTokenBucket |
394 | | public: |
395 | | // called by the connection manager to run this transaction through the |
396 | | // token bucket. If the token bucket admits the transaction immediately it |
397 | | // returns true. The function is called repeatedly until it returns true. |
398 | | bool TryToRunPacedRequest(); |
399 | | |
400 | | // ATokenBucketEvent pure virtual implementation. Called by the token bucket |
401 | | // when the transaction is ready to run. If this happens asynchrounously to |
402 | | // token bucket submission the transaction just posts an event that causes |
403 | | // the pending transaction queue to be rerun (and TryToRunPacedRequest() to |
404 | | // be run again. |
405 | | void OnTokenBucketAdmitted() override; // ATokenBucketEvent |
406 | | |
407 | | // CancelPacing() can be used to tell the token bucket to remove this |
408 | | // transaction from the list of pending transactions. This is used when a |
409 | | // transaction is believed to be HTTP/1 (and thus subject to rate pacing) |
410 | | // but later can be dispatched via spdy (not subject to rate pacing). |
411 | | void CancelPacing(nsresult reason); |
412 | | |
413 | | // Called by the connetion manager on the socket thread when reading for this |
414 | | // previously throttled transaction has to be resumed. |
415 | | void ResumeReading(); |
416 | | |
417 | | // This examins classification of this transaction whether the Throttleable class |
418 | | // has been set while Leader, Unblocked, DontThrottle has not. |
419 | | bool EligibleForThrottling() const; |
420 | | |
421 | | private: |
422 | | bool mSubmittedRatePacing; |
423 | | bool mPassedRatePacing; |
424 | | bool mSynchronousRatePaceRequest; |
425 | | nsCOMPtr<nsICancelable> mTokenBucketCancel; |
426 | | public: |
427 | | void SetClassOfService(uint32_t cos); |
428 | 0 | uint32_t ClassOfService() { return mClassOfService; } |
429 | | private: |
430 | | uint32_t mClassOfService; |
431 | | |
432 | | public: |
433 | | // setting TunnelProvider to non-null means the transaction should only |
434 | | // be dispatched on a specific ConnectionInfo Hash Key (as opposed to a |
435 | | // generic wild card one). That means in the specific case of carrying this |
436 | | // transaction on an HTTP/2 tunnel it will only be dispatched onto an |
437 | | // existing tunnel instead of triggering creation of a new one. |
438 | | // The tunnel provider is used for ASpdySession::MaybeReTunnel() checks. |
439 | | |
440 | 0 | void SetTunnelProvider(ASpdySession *provider) { mTunnelProvider = provider; } |
441 | 0 | ASpdySession *TunnelProvider() { return mTunnelProvider; } |
442 | 0 | nsIInterfaceRequestor *SecurityCallbacks() { return mCallbacks; } |
443 | | |
444 | | private: |
445 | | RefPtr<ASpdySession> mTunnelProvider; |
446 | | |
447 | | public: |
448 | 0 | void SetTransactionObserver(TransactionObserver *arg) { mTransactionObserver = arg; } |
449 | | private: |
450 | | RefPtr<TransactionObserver> mTransactionObserver; |
451 | | public: |
452 | | void GetNetworkAddresses(NetAddr &self, NetAddr &peer); |
453 | | |
454 | | private: |
455 | | NetAddr mSelfAddr; |
456 | | NetAddr mPeerAddr; |
457 | | |
458 | | bool m0RTTInProgress; |
459 | | bool mDoNotTryEarlyData; |
460 | | enum |
461 | | { |
462 | | EARLY_NONE, |
463 | | EARLY_SENT, |
464 | | EARLY_ACCEPTED, |
465 | | EARLY_425 |
466 | | } mEarlyDataDisposition; |
467 | | |
468 | | uint8_t mFastOpenStatus; |
469 | | }; |
470 | | |
471 | | } // namespace net |
472 | | } // namespace mozilla |
473 | | |
474 | | #endif // nsHttpTransaction_h__ |