Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
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/. */
6 #ifndef nsHttpTransaction_h__
7 #define nsHttpTransaction_h__
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"
19 #ifdef MOZ_WIDGET_GONK
20 #include "nsINetworkManager.h"
21 #include "nsProxyRelease.h"
22 #endif
24 //-----------------------------------------------------------------------------
26 class nsIHttpActivityObserver;
27 class nsIEventTarget;
28 class nsIInputStream;
29 class nsIOutputStream;
31 namespace mozilla { namespace net {
33 class nsHttpChunkedDecoder;
34 class nsHttpRequestHead;
35 class nsHttpResponseHead;
37 //-----------------------------------------------------------------------------
38 // nsHttpTransaction represents a single HTTP transaction. It is thread-safe,
39 // intended to run on the socket thread.
40 //-----------------------------------------------------------------------------
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
53 nsHttpTransaction();
54 virtual ~nsHttpTransaction();
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);
88 // attributes
89 nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; }
90 nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nullptr; }
91 nsISupports *SecurityInfo() { return mSecurityInfo; }
93 nsIEventTarget *ConsumerTarget() { return mConsumerTarget; }
95 void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks);
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();
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();
105 // Called to find out if the transaction generated a complete response.
106 bool ResponseIsComplete() { return mResponseIsComplete; }
108 bool ProxyConnectFailed() { return mProxyConnectFailed; }
110 // SetPriority() may only be used by the connection manager.
111 void SetPriority(int32_t priority) { mPriority = priority; }
112 int32_t Priority() { return mPriority; }
114 const TimingStruct& Timings() const { return mTimings; }
115 enum Classifier Classification() { return mClassification; }
117 void PrintDiagnostics(nsCString &log);
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; }
124 // overload of nsAHttpTransaction::LoadGroupConnectionInfo()
125 nsILoadGroupConnectionInfo *LoadGroupConnectionInfo() { return mLoadGroupCI.get(); }
126 void SetLoadGroupConnectionInfo(nsILoadGroupConnectionInfo *aLoadGroupCI) { mLoadGroupCI = aLoadGroupCI; }
127 void DispatchedAsBlocking();
128 void RemoveDispatchedAsBlocking();
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();
144 Classifier Classify();
145 void CancelPipeline(uint32_t reason);
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 *);
152 bool TimingEnabled() const { return mCaps & NS_HTTP_TIMING_ENABLED; }
154 bool ResponseTimeoutEnabled() const MOZ_FINAL;
156 private:
157 class UpdateSecurityCallbacks : public nsRunnable
158 {
159 public:
160 UpdateSecurityCallbacks(nsHttpTransaction* aTrans,
161 nsIInterfaceRequestor* aCallbacks)
162 : mTrans(aTrans), mCallbacks(aCallbacks) {}
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 };
175 Mutex mLock;
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;
185 nsCOMPtr<nsISupports> mChannel;
186 nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor;
188 nsCString mReqHeaderBuf; // flattened request headers
189 nsCOMPtr<nsIInputStream> mRequestStream;
190 uint64_t mRequestSize;
192 nsAHttpConnection *mConnection; // hard ref
193 nsHttpConnectionInfo *mConnInfo; // hard ref
194 nsHttpRequestHead *mRequestHead; // weak ref
195 nsHttpResponseHead *mResponseHead; // hard ref
197 nsAHttpSegmentReader *mReader;
198 nsAHttpSegmentWriter *mWriter;
200 nsCString mLineBuf; // may contain a partial line
202 int64_t mContentLength; // equals -1 if unknown
203 int64_t mContentRead; // count of consumed content bytes
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;
212 nsHttpChunkedDecoder *mChunkedDecoder;
214 TimingStruct mTimings;
216 nsresult mStatus;
218 int16_t mPriority;
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;
232 nsHttpVersion mHttpVersion;
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;
254 // mClosed := transaction has been explicitly closed
255 // mTransactionDone := transaction ran to completion or was interrupted
256 // mResponseComplete := transaction ran to completion
258 // For Restart-In-Progress Functionality
259 bool mReportedStart;
260 bool mReportedResponseHeader;
262 // protected by nsHttp::GetLock()
263 nsHttpResponseHead *mForTakeResponseHead;
264 bool mResponseHeadTaken;
266 // The time when the transaction was submitted to the Connection Manager
267 TimeStamp mPendingTime;
269 class RestartVerifier
270 {
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.
280 public:
281 RestartVerifier()
282 : mContentLength(-1)
283 , mAlreadyProcessed(0)
284 , mToReadBeforeRestart(0)
285 , mSetup(false)
286 {}
287 ~RestartVerifier() {}
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 }
306 private:
307 // This is the data from the first complete response header
308 // used to make sure that all subsequent response headers match
310 int64_t mContentLength;
311 nsCString mETag;
312 nsCString mLastModified;
313 nsCString mContentRange;
314 nsCString mContentEncoding;
315 nsCString mTransferEncoding;
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;
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;
327 // true when ::Set has been called with a response header
328 bool mSetup;
329 } mRestartInProgressVerifier;
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();
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
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);
351 private:
352 bool mSubmittedRatePacing;
353 bool mPassedRatePacing;
354 bool mSynchronousRatePaceRequest;
355 nsCOMPtr<nsICancelable> mTokenBucketCancel;
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 };
378 }} // namespace mozilla::net
380 #endif // nsHttpTransaction_h__