|
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 "nsILoadGroup.h" |
|
16 #include "nsIInterfaceRequestor.h" |
|
17 #include "TimingStruct.h" |
|
18 |
|
19 #ifdef MOZ_WIDGET_GONK |
|
20 #include "nsINetworkManager.h" |
|
21 #include "nsProxyRelease.h" |
|
22 #endif |
|
23 |
|
24 //----------------------------------------------------------------------------- |
|
25 |
|
26 class nsIHttpActivityObserver; |
|
27 class nsIEventTarget; |
|
28 class nsIInputStream; |
|
29 class nsIOutputStream; |
|
30 |
|
31 namespace mozilla { namespace net { |
|
32 |
|
33 class nsHttpChunkedDecoder; |
|
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 : public nsAHttpTransaction |
|
43 , public ATokenBucketEvent |
|
44 , public nsIInputStreamCallback |
|
45 , public nsIOutputStreamCallback |
|
46 { |
|
47 public: |
|
48 NS_DECL_THREADSAFE_ISUPPORTS |
|
49 NS_DECL_NSAHTTPTRANSACTION |
|
50 NS_DECL_NSIINPUTSTREAMCALLBACK |
|
51 NS_DECL_NSIOUTPUTSTREAMCALLBACK |
|
52 |
|
53 nsHttpTransaction(); |
|
54 virtual ~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 responseBody |
|
74 // the input stream that will contain the response data. async |
|
75 // wait on this input stream for data. on first notification, |
|
76 // headers should be available (check transaction status). |
|
77 // |
|
78 nsresult Init(uint32_t caps, |
|
79 nsHttpConnectionInfo *connInfo, |
|
80 nsHttpRequestHead *reqHeaders, |
|
81 nsIInputStream *reqBody, |
|
82 bool reqBodyIncludesHeaders, |
|
83 nsIEventTarget *consumerTarget, |
|
84 nsIInterfaceRequestor *callbacks, |
|
85 nsITransportEventSink *eventsink, |
|
86 nsIAsyncInputStream **responseBody); |
|
87 |
|
88 // attributes |
|
89 nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; } |
|
90 nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nullptr; } |
|
91 nsISupports *SecurityInfo() { return mSecurityInfo; } |
|
92 |
|
93 nsIEventTarget *ConsumerTarget() { return mConsumerTarget; } |
|
94 |
|
95 void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks); |
|
96 |
|
97 // Called to take ownership of the response headers; the transaction |
|
98 // will drop any reference to the response headers after this call. |
|
99 nsHttpResponseHead *TakeResponseHead(); |
|
100 |
|
101 // Provides a thread safe reference of the connection |
|
102 // nsHttpTransaction::Connection should only be used on the socket thread |
|
103 already_AddRefed<nsAHttpConnection> GetConnectionReference(); |
|
104 |
|
105 // Called to find out if the transaction generated a complete response. |
|
106 bool ResponseIsComplete() { return mResponseIsComplete; } |
|
107 |
|
108 bool ProxyConnectFailed() { return mProxyConnectFailed; } |
|
109 |
|
110 // SetPriority() may only be used by the connection manager. |
|
111 void SetPriority(int32_t priority) { mPriority = priority; } |
|
112 int32_t Priority() { return mPriority; } |
|
113 |
|
114 const TimingStruct& Timings() const { return mTimings; } |
|
115 enum Classifier Classification() { return mClassification; } |
|
116 |
|
117 void PrintDiagnostics(nsCString &log); |
|
118 |
|
119 // Sets mPendingTime to the current time stamp or to a null time stamp (if now is false) |
|
120 void SetPendingTime(bool now = true) { mPendingTime = now ? TimeStamp::Now() : TimeStamp(); } |
|
121 const TimeStamp GetPendingTime() { return mPendingTime; } |
|
122 bool UsesPipelining() const { return mCaps & NS_HTTP_ALLOW_PIPELINING; } |
|
123 |
|
124 // overload of nsAHttpTransaction::LoadGroupConnectionInfo() |
|
125 nsILoadGroupConnectionInfo *LoadGroupConnectionInfo() { return mLoadGroupCI.get(); } |
|
126 void SetLoadGroupConnectionInfo(nsILoadGroupConnectionInfo *aLoadGroupCI) { mLoadGroupCI = aLoadGroupCI; } |
|
127 void DispatchedAsBlocking(); |
|
128 void RemoveDispatchedAsBlocking(); |
|
129 |
|
130 private: |
|
131 nsresult Restart(); |
|
132 nsresult RestartInProgress(); |
|
133 char *LocateHttpStart(char *buf, uint32_t len, |
|
134 bool aAllowPartialMatch); |
|
135 nsresult ParseLine(char *line); |
|
136 nsresult ParseLineSegment(char *seg, uint32_t len); |
|
137 nsresult ParseHead(char *, uint32_t count, uint32_t *countRead); |
|
138 nsresult HandleContentStart(); |
|
139 nsresult HandleContent(char *, uint32_t count, uint32_t *contentRead, uint32_t *contentRemaining); |
|
140 nsresult ProcessData(char *, uint32_t, uint32_t *); |
|
141 void DeleteSelfOnConsumerThread(); |
|
142 void ReleaseBlockingTransaction(); |
|
143 |
|
144 Classifier Classify(); |
|
145 void CancelPipeline(uint32_t reason); |
|
146 |
|
147 static NS_METHOD ReadRequestSegment(nsIInputStream *, void *, const char *, |
|
148 uint32_t, uint32_t, uint32_t *); |
|
149 static NS_METHOD WritePipeSegment(nsIOutputStream *, void *, char *, |
|
150 uint32_t, uint32_t, uint32_t *); |
|
151 |
|
152 bool TimingEnabled() const { return mCaps & NS_HTTP_TIMING_ENABLED; } |
|
153 |
|
154 bool ResponseTimeoutEnabled() const MOZ_FINAL; |
|
155 |
|
156 private: |
|
157 class UpdateSecurityCallbacks : public nsRunnable |
|
158 { |
|
159 public: |
|
160 UpdateSecurityCallbacks(nsHttpTransaction* aTrans, |
|
161 nsIInterfaceRequestor* aCallbacks) |
|
162 : mTrans(aTrans), mCallbacks(aCallbacks) {} |
|
163 |
|
164 NS_IMETHOD Run() |
|
165 { |
|
166 if (mTrans->mConnection) |
|
167 mTrans->mConnection->SetSecurityCallbacks(mCallbacks); |
|
168 return NS_OK; |
|
169 } |
|
170 private: |
|
171 nsRefPtr<nsHttpTransaction> mTrans; |
|
172 nsCOMPtr<nsIInterfaceRequestor> mCallbacks; |
|
173 }; |
|
174 |
|
175 Mutex mLock; |
|
176 |
|
177 nsCOMPtr<nsIInterfaceRequestor> mCallbacks; |
|
178 nsCOMPtr<nsITransportEventSink> mTransportSink; |
|
179 nsCOMPtr<nsIEventTarget> mConsumerTarget; |
|
180 nsCOMPtr<nsISupports> mSecurityInfo; |
|
181 nsCOMPtr<nsIAsyncInputStream> mPipeIn; |
|
182 nsCOMPtr<nsIAsyncOutputStream> mPipeOut; |
|
183 nsCOMPtr<nsILoadGroupConnectionInfo> mLoadGroupCI; |
|
184 |
|
185 nsCOMPtr<nsISupports> mChannel; |
|
186 nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor; |
|
187 |
|
188 nsCString mReqHeaderBuf; // flattened request headers |
|
189 nsCOMPtr<nsIInputStream> mRequestStream; |
|
190 uint64_t mRequestSize; |
|
191 |
|
192 nsAHttpConnection *mConnection; // hard ref |
|
193 nsHttpConnectionInfo *mConnInfo; // hard ref |
|
194 nsHttpRequestHead *mRequestHead; // weak ref |
|
195 nsHttpResponseHead *mResponseHead; // hard ref |
|
196 |
|
197 nsAHttpSegmentReader *mReader; |
|
198 nsAHttpSegmentWriter *mWriter; |
|
199 |
|
200 nsCString mLineBuf; // may contain a partial line |
|
201 |
|
202 int64_t mContentLength; // equals -1 if unknown |
|
203 int64_t mContentRead; // count of consumed content bytes |
|
204 |
|
205 // After a 304/204 or other "no-content" style response we will skip over |
|
206 // up to MAX_INVALID_RESPONSE_BODY_SZ bytes when looking for the next |
|
207 // response header to deal with servers that actually sent a response |
|
208 // body where they should not have. This member tracks how many bytes have |
|
209 // so far been skipped. |
|
210 uint32_t mInvalidResponseBytesRead; |
|
211 |
|
212 nsHttpChunkedDecoder *mChunkedDecoder; |
|
213 |
|
214 TimingStruct mTimings; |
|
215 |
|
216 nsresult mStatus; |
|
217 |
|
218 int16_t mPriority; |
|
219 |
|
220 uint16_t mRestartCount; // the number of times this transaction has been restarted |
|
221 uint32_t mCaps; |
|
222 // mCapsToClear holds flags that should be cleared in mCaps, e.g. unset |
|
223 // NS_HTTP_REFRESH_DNS when DNS refresh request has completed to avoid |
|
224 // redundant requests on the network. To deal with raciness, only unsetting |
|
225 // bitfields should be allowed: 'lost races' will thus err on the |
|
226 // conservative side, e.g. by going ahead with a 2nd DNS refresh. |
|
227 uint32_t mCapsToClear; |
|
228 enum Classifier mClassification; |
|
229 int32_t mPipelinePosition; |
|
230 int64_t mMaxPipelineObjectSize; |
|
231 |
|
232 nsHttpVersion mHttpVersion; |
|
233 |
|
234 // state flags, all logically boolean, but not packed together into a |
|
235 // bitfield so as to avoid bitfield-induced races. See bug 560579. |
|
236 bool mClosed; |
|
237 bool mConnected; |
|
238 bool mHaveStatusLine; |
|
239 bool mHaveAllHeaders; |
|
240 bool mTransactionDone; |
|
241 bool mResponseIsComplete; |
|
242 bool mDidContentStart; |
|
243 bool mNoContent; // expecting an empty entity body |
|
244 bool mSentData; |
|
245 bool mReceivedData; |
|
246 bool mStatusEventPending; |
|
247 bool mHasRequestBody; |
|
248 bool mProxyConnectFailed; |
|
249 bool mHttpResponseMatched; |
|
250 bool mPreserveStream; |
|
251 bool mDispatchedAsBlocking; |
|
252 bool mResponseTimeoutEnabled; |
|
253 |
|
254 // mClosed := transaction has been explicitly closed |
|
255 // mTransactionDone := transaction ran to completion or was interrupted |
|
256 // mResponseComplete := transaction ran to completion |
|
257 |
|
258 // For Restart-In-Progress Functionality |
|
259 bool mReportedStart; |
|
260 bool mReportedResponseHeader; |
|
261 |
|
262 // protected by nsHttp::GetLock() |
|
263 nsHttpResponseHead *mForTakeResponseHead; |
|
264 bool mResponseHeadTaken; |
|
265 |
|
266 // The time when the transaction was submitted to the Connection Manager |
|
267 TimeStamp mPendingTime; |
|
268 |
|
269 class RestartVerifier |
|
270 { |
|
271 |
|
272 // When a idemptotent transaction has received part of its response body |
|
273 // and incurs an error it can be restarted. To do this we mark the place |
|
274 // where we stopped feeding the body to the consumer and start the |
|
275 // network call over again. If everything we track (headers, length, etc..) |
|
276 // matches up to the place where we left off then the consumer starts being |
|
277 // fed data again with the new information. This can be done N times up |
|
278 // to the normal restart (i.e. with no response info) limit. |
|
279 |
|
280 public: |
|
281 RestartVerifier() |
|
282 : mContentLength(-1) |
|
283 , mAlreadyProcessed(0) |
|
284 , mToReadBeforeRestart(0) |
|
285 , mSetup(false) |
|
286 {} |
|
287 ~RestartVerifier() {} |
|
288 |
|
289 void Set(int64_t contentLength, nsHttpResponseHead *head); |
|
290 bool Verify(int64_t contentLength, nsHttpResponseHead *head); |
|
291 bool IsDiscardingContent() { return mToReadBeforeRestart != 0; } |
|
292 bool IsSetup() { return mSetup; } |
|
293 int64_t AlreadyProcessed() { return mAlreadyProcessed; } |
|
294 void SetAlreadyProcessed(int64_t val) { |
|
295 mAlreadyProcessed = val; |
|
296 mToReadBeforeRestart = val; |
|
297 } |
|
298 int64_t ToReadBeforeRestart() { return mToReadBeforeRestart; } |
|
299 void HaveReadBeforeRestart(uint32_t amt) |
|
300 { |
|
301 MOZ_ASSERT(amt <= mToReadBeforeRestart, |
|
302 "too large of a HaveReadBeforeRestart deduction"); |
|
303 mToReadBeforeRestart -= amt; |
|
304 } |
|
305 |
|
306 private: |
|
307 // This is the data from the first complete response header |
|
308 // used to make sure that all subsequent response headers match |
|
309 |
|
310 int64_t mContentLength; |
|
311 nsCString mETag; |
|
312 nsCString mLastModified; |
|
313 nsCString mContentRange; |
|
314 nsCString mContentEncoding; |
|
315 nsCString mTransferEncoding; |
|
316 |
|
317 // This is the amount of data that has been passed to the channel |
|
318 // from previous iterations of the transaction and must therefore |
|
319 // be skipped in the new one. |
|
320 int64_t mAlreadyProcessed; |
|
321 |
|
322 // The amount of data that must be discarded in the current iteration |
|
323 // (where iteration > 0) to reach the mAlreadyProcessed high water |
|
324 // mark. |
|
325 int64_t mToReadBeforeRestart; |
|
326 |
|
327 // true when ::Set has been called with a response header |
|
328 bool mSetup; |
|
329 } mRestartInProgressVerifier; |
|
330 |
|
331 // For Rate Pacing via an EventTokenBucket |
|
332 public: |
|
333 // called by the connection manager to run this transaction through the |
|
334 // token bucket. If the token bucket admits the transaction immediately it |
|
335 // returns true. The function is called repeatedly until it returns true. |
|
336 bool TryToRunPacedRequest(); |
|
337 |
|
338 // ATokenBucketEvent pure virtual implementation. Called by the token bucket |
|
339 // when the transaction is ready to run. If this happens asynchrounously to |
|
340 // token bucket submission the transaction just posts an event that causes |
|
341 // the pending transaction queue to be rerun (and TryToRunPacedRequest() to |
|
342 // be run again. |
|
343 void OnTokenBucketAdmitted(); // ATokenBucketEvent |
|
344 |
|
345 // CancelPacing() can be used to tell the token bucket to remove this |
|
346 // transaction from the list of pending transactions. This is used when a |
|
347 // transaction is believed to be HTTP/1 (and thus subject to rate pacing) |
|
348 // but later can be dispatched via spdy (not subject to rate pacing). |
|
349 void CancelPacing(nsresult reason); |
|
350 |
|
351 private: |
|
352 bool mSubmittedRatePacing; |
|
353 bool mPassedRatePacing; |
|
354 bool mSynchronousRatePaceRequest; |
|
355 nsCOMPtr<nsICancelable> mTokenBucketCancel; |
|
356 |
|
357 // These members are used for network per-app metering (bug 746073) |
|
358 // Currently, they are only available on gonk. |
|
359 uint64_t mCountRecv; |
|
360 uint64_t mCountSent; |
|
361 uint32_t mAppId; |
|
362 #ifdef MOZ_WIDGET_GONK |
|
363 nsMainThreadPtrHandle<nsINetworkInterface> mActiveNetwork; |
|
364 #endif |
|
365 nsresult SaveNetworkStats(bool); |
|
366 void CountRecvBytes(uint64_t recvBytes) |
|
367 { |
|
368 mCountRecv += recvBytes; |
|
369 SaveNetworkStats(false); |
|
370 } |
|
371 void CountSentBytes(uint64_t sentBytes) |
|
372 { |
|
373 mCountSent += sentBytes; |
|
374 SaveNetworkStats(false); |
|
375 } |
|
376 }; |
|
377 |
|
378 }} // namespace mozilla::net |
|
379 |
|
380 #endif // nsHttpTransaction_h__ |