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