netwerk/protocol/http/nsHttpTransaction.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial