1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/http/nsHttpTransaction.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,380 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef nsHttpTransaction_h__ 1.10 +#define nsHttpTransaction_h__ 1.11 + 1.12 +#include "nsHttp.h" 1.13 +#include "nsAHttpTransaction.h" 1.14 +#include "nsAHttpConnection.h" 1.15 +#include "EventTokenBucket.h" 1.16 +#include "nsCOMPtr.h" 1.17 +#include "nsThreadUtils.h" 1.18 +#include "nsILoadGroup.h" 1.19 +#include "nsIInterfaceRequestor.h" 1.20 +#include "TimingStruct.h" 1.21 + 1.22 +#ifdef MOZ_WIDGET_GONK 1.23 +#include "nsINetworkManager.h" 1.24 +#include "nsProxyRelease.h" 1.25 +#endif 1.26 + 1.27 +//----------------------------------------------------------------------------- 1.28 + 1.29 +class nsIHttpActivityObserver; 1.30 +class nsIEventTarget; 1.31 +class nsIInputStream; 1.32 +class nsIOutputStream; 1.33 + 1.34 +namespace mozilla { namespace net { 1.35 + 1.36 +class nsHttpChunkedDecoder; 1.37 +class nsHttpRequestHead; 1.38 +class nsHttpResponseHead; 1.39 + 1.40 +//----------------------------------------------------------------------------- 1.41 +// nsHttpTransaction represents a single HTTP transaction. It is thread-safe, 1.42 +// intended to run on the socket thread. 1.43 +//----------------------------------------------------------------------------- 1.44 + 1.45 +class nsHttpTransaction : public nsAHttpTransaction 1.46 + , public ATokenBucketEvent 1.47 + , public nsIInputStreamCallback 1.48 + , public nsIOutputStreamCallback 1.49 +{ 1.50 +public: 1.51 + NS_DECL_THREADSAFE_ISUPPORTS 1.52 + NS_DECL_NSAHTTPTRANSACTION 1.53 + NS_DECL_NSIINPUTSTREAMCALLBACK 1.54 + NS_DECL_NSIOUTPUTSTREAMCALLBACK 1.55 + 1.56 + nsHttpTransaction(); 1.57 + virtual ~nsHttpTransaction(); 1.58 + 1.59 + // 1.60 + // called to initialize the transaction 1.61 + // 1.62 + // @param caps 1.63 + // the transaction capabilities (see nsHttp.h) 1.64 + // @param connInfo 1.65 + // the connection type for this transaction. 1.66 + // @param reqHeaders 1.67 + // the request header struct 1.68 + // @param reqBody 1.69 + // the request body (POST or PUT data stream) 1.70 + // @param reqBodyIncludesHeaders 1.71 + // fun stuff to support NPAPI plugins. 1.72 + // @param target 1.73 + // the dispatch target were notifications should be sent. 1.74 + // @param callbacks 1.75 + // the notification callbacks to be given to PSM. 1.76 + // @param responseBody 1.77 + // the input stream that will contain the response data. async 1.78 + // wait on this input stream for data. on first notification, 1.79 + // headers should be available (check transaction status). 1.80 + // 1.81 + nsresult Init(uint32_t caps, 1.82 + nsHttpConnectionInfo *connInfo, 1.83 + nsHttpRequestHead *reqHeaders, 1.84 + nsIInputStream *reqBody, 1.85 + bool reqBodyIncludesHeaders, 1.86 + nsIEventTarget *consumerTarget, 1.87 + nsIInterfaceRequestor *callbacks, 1.88 + nsITransportEventSink *eventsink, 1.89 + nsIAsyncInputStream **responseBody); 1.90 + 1.91 + // attributes 1.92 + nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; } 1.93 + nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nullptr; } 1.94 + nsISupports *SecurityInfo() { return mSecurityInfo; } 1.95 + 1.96 + nsIEventTarget *ConsumerTarget() { return mConsumerTarget; } 1.97 + 1.98 + void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks); 1.99 + 1.100 + // Called to take ownership of the response headers; the transaction 1.101 + // will drop any reference to the response headers after this call. 1.102 + nsHttpResponseHead *TakeResponseHead(); 1.103 + 1.104 + // Provides a thread safe reference of the connection 1.105 + // nsHttpTransaction::Connection should only be used on the socket thread 1.106 + already_AddRefed<nsAHttpConnection> GetConnectionReference(); 1.107 + 1.108 + // Called to find out if the transaction generated a complete response. 1.109 + bool ResponseIsComplete() { return mResponseIsComplete; } 1.110 + 1.111 + bool ProxyConnectFailed() { return mProxyConnectFailed; } 1.112 + 1.113 + // SetPriority() may only be used by the connection manager. 1.114 + void SetPriority(int32_t priority) { mPriority = priority; } 1.115 + int32_t Priority() { return mPriority; } 1.116 + 1.117 + const TimingStruct& Timings() const { return mTimings; } 1.118 + enum Classifier Classification() { return mClassification; } 1.119 + 1.120 + void PrintDiagnostics(nsCString &log); 1.121 + 1.122 + // Sets mPendingTime to the current time stamp or to a null time stamp (if now is false) 1.123 + void SetPendingTime(bool now = true) { mPendingTime = now ? TimeStamp::Now() : TimeStamp(); } 1.124 + const TimeStamp GetPendingTime() { return mPendingTime; } 1.125 + bool UsesPipelining() const { return mCaps & NS_HTTP_ALLOW_PIPELINING; } 1.126 + 1.127 + // overload of nsAHttpTransaction::LoadGroupConnectionInfo() 1.128 + nsILoadGroupConnectionInfo *LoadGroupConnectionInfo() { return mLoadGroupCI.get(); } 1.129 + void SetLoadGroupConnectionInfo(nsILoadGroupConnectionInfo *aLoadGroupCI) { mLoadGroupCI = aLoadGroupCI; } 1.130 + void DispatchedAsBlocking(); 1.131 + void RemoveDispatchedAsBlocking(); 1.132 + 1.133 +private: 1.134 + nsresult Restart(); 1.135 + nsresult RestartInProgress(); 1.136 + char *LocateHttpStart(char *buf, uint32_t len, 1.137 + bool aAllowPartialMatch); 1.138 + nsresult ParseLine(char *line); 1.139 + nsresult ParseLineSegment(char *seg, uint32_t len); 1.140 + nsresult ParseHead(char *, uint32_t count, uint32_t *countRead); 1.141 + nsresult HandleContentStart(); 1.142 + nsresult HandleContent(char *, uint32_t count, uint32_t *contentRead, uint32_t *contentRemaining); 1.143 + nsresult ProcessData(char *, uint32_t, uint32_t *); 1.144 + void DeleteSelfOnConsumerThread(); 1.145 + void ReleaseBlockingTransaction(); 1.146 + 1.147 + Classifier Classify(); 1.148 + void CancelPipeline(uint32_t reason); 1.149 + 1.150 + static NS_METHOD ReadRequestSegment(nsIInputStream *, void *, const char *, 1.151 + uint32_t, uint32_t, uint32_t *); 1.152 + static NS_METHOD WritePipeSegment(nsIOutputStream *, void *, char *, 1.153 + uint32_t, uint32_t, uint32_t *); 1.154 + 1.155 + bool TimingEnabled() const { return mCaps & NS_HTTP_TIMING_ENABLED; } 1.156 + 1.157 + bool ResponseTimeoutEnabled() const MOZ_FINAL; 1.158 + 1.159 +private: 1.160 + class UpdateSecurityCallbacks : public nsRunnable 1.161 + { 1.162 + public: 1.163 + UpdateSecurityCallbacks(nsHttpTransaction* aTrans, 1.164 + nsIInterfaceRequestor* aCallbacks) 1.165 + : mTrans(aTrans), mCallbacks(aCallbacks) {} 1.166 + 1.167 + NS_IMETHOD Run() 1.168 + { 1.169 + if (mTrans->mConnection) 1.170 + mTrans->mConnection->SetSecurityCallbacks(mCallbacks); 1.171 + return NS_OK; 1.172 + } 1.173 + private: 1.174 + nsRefPtr<nsHttpTransaction> mTrans; 1.175 + nsCOMPtr<nsIInterfaceRequestor> mCallbacks; 1.176 + }; 1.177 + 1.178 + Mutex mLock; 1.179 + 1.180 + nsCOMPtr<nsIInterfaceRequestor> mCallbacks; 1.181 + nsCOMPtr<nsITransportEventSink> mTransportSink; 1.182 + nsCOMPtr<nsIEventTarget> mConsumerTarget; 1.183 + nsCOMPtr<nsISupports> mSecurityInfo; 1.184 + nsCOMPtr<nsIAsyncInputStream> mPipeIn; 1.185 + nsCOMPtr<nsIAsyncOutputStream> mPipeOut; 1.186 + nsCOMPtr<nsILoadGroupConnectionInfo> mLoadGroupCI; 1.187 + 1.188 + nsCOMPtr<nsISupports> mChannel; 1.189 + nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor; 1.190 + 1.191 + nsCString mReqHeaderBuf; // flattened request headers 1.192 + nsCOMPtr<nsIInputStream> mRequestStream; 1.193 + uint64_t mRequestSize; 1.194 + 1.195 + nsAHttpConnection *mConnection; // hard ref 1.196 + nsHttpConnectionInfo *mConnInfo; // hard ref 1.197 + nsHttpRequestHead *mRequestHead; // weak ref 1.198 + nsHttpResponseHead *mResponseHead; // hard ref 1.199 + 1.200 + nsAHttpSegmentReader *mReader; 1.201 + nsAHttpSegmentWriter *mWriter; 1.202 + 1.203 + nsCString mLineBuf; // may contain a partial line 1.204 + 1.205 + int64_t mContentLength; // equals -1 if unknown 1.206 + int64_t mContentRead; // count of consumed content bytes 1.207 + 1.208 + // After a 304/204 or other "no-content" style response we will skip over 1.209 + // up to MAX_INVALID_RESPONSE_BODY_SZ bytes when looking for the next 1.210 + // response header to deal with servers that actually sent a response 1.211 + // body where they should not have. This member tracks how many bytes have 1.212 + // so far been skipped. 1.213 + uint32_t mInvalidResponseBytesRead; 1.214 + 1.215 + nsHttpChunkedDecoder *mChunkedDecoder; 1.216 + 1.217 + TimingStruct mTimings; 1.218 + 1.219 + nsresult mStatus; 1.220 + 1.221 + int16_t mPriority; 1.222 + 1.223 + uint16_t mRestartCount; // the number of times this transaction has been restarted 1.224 + uint32_t mCaps; 1.225 + // mCapsToClear holds flags that should be cleared in mCaps, e.g. unset 1.226 + // NS_HTTP_REFRESH_DNS when DNS refresh request has completed to avoid 1.227 + // redundant requests on the network. To deal with raciness, only unsetting 1.228 + // bitfields should be allowed: 'lost races' will thus err on the 1.229 + // conservative side, e.g. by going ahead with a 2nd DNS refresh. 1.230 + uint32_t mCapsToClear; 1.231 + enum Classifier mClassification; 1.232 + int32_t mPipelinePosition; 1.233 + int64_t mMaxPipelineObjectSize; 1.234 + 1.235 + nsHttpVersion mHttpVersion; 1.236 + 1.237 + // state flags, all logically boolean, but not packed together into a 1.238 + // bitfield so as to avoid bitfield-induced races. See bug 560579. 1.239 + bool mClosed; 1.240 + bool mConnected; 1.241 + bool mHaveStatusLine; 1.242 + bool mHaveAllHeaders; 1.243 + bool mTransactionDone; 1.244 + bool mResponseIsComplete; 1.245 + bool mDidContentStart; 1.246 + bool mNoContent; // expecting an empty entity body 1.247 + bool mSentData; 1.248 + bool mReceivedData; 1.249 + bool mStatusEventPending; 1.250 + bool mHasRequestBody; 1.251 + bool mProxyConnectFailed; 1.252 + bool mHttpResponseMatched; 1.253 + bool mPreserveStream; 1.254 + bool mDispatchedAsBlocking; 1.255 + bool mResponseTimeoutEnabled; 1.256 + 1.257 + // mClosed := transaction has been explicitly closed 1.258 + // mTransactionDone := transaction ran to completion or was interrupted 1.259 + // mResponseComplete := transaction ran to completion 1.260 + 1.261 + // For Restart-In-Progress Functionality 1.262 + bool mReportedStart; 1.263 + bool mReportedResponseHeader; 1.264 + 1.265 + // protected by nsHttp::GetLock() 1.266 + nsHttpResponseHead *mForTakeResponseHead; 1.267 + bool mResponseHeadTaken; 1.268 + 1.269 + // The time when the transaction was submitted to the Connection Manager 1.270 + TimeStamp mPendingTime; 1.271 + 1.272 + class RestartVerifier 1.273 + { 1.274 + 1.275 + // When a idemptotent transaction has received part of its response body 1.276 + // and incurs an error it can be restarted. To do this we mark the place 1.277 + // where we stopped feeding the body to the consumer and start the 1.278 + // network call over again. If everything we track (headers, length, etc..) 1.279 + // matches up to the place where we left off then the consumer starts being 1.280 + // fed data again with the new information. This can be done N times up 1.281 + // to the normal restart (i.e. with no response info) limit. 1.282 + 1.283 + public: 1.284 + RestartVerifier() 1.285 + : mContentLength(-1) 1.286 + , mAlreadyProcessed(0) 1.287 + , mToReadBeforeRestart(0) 1.288 + , mSetup(false) 1.289 + {} 1.290 + ~RestartVerifier() {} 1.291 + 1.292 + void Set(int64_t contentLength, nsHttpResponseHead *head); 1.293 + bool Verify(int64_t contentLength, nsHttpResponseHead *head); 1.294 + bool IsDiscardingContent() { return mToReadBeforeRestart != 0; } 1.295 + bool IsSetup() { return mSetup; } 1.296 + int64_t AlreadyProcessed() { return mAlreadyProcessed; } 1.297 + void SetAlreadyProcessed(int64_t val) { 1.298 + mAlreadyProcessed = val; 1.299 + mToReadBeforeRestart = val; 1.300 + } 1.301 + int64_t ToReadBeforeRestart() { return mToReadBeforeRestart; } 1.302 + void HaveReadBeforeRestart(uint32_t amt) 1.303 + { 1.304 + MOZ_ASSERT(amt <= mToReadBeforeRestart, 1.305 + "too large of a HaveReadBeforeRestart deduction"); 1.306 + mToReadBeforeRestart -= amt; 1.307 + } 1.308 + 1.309 + private: 1.310 + // This is the data from the first complete response header 1.311 + // used to make sure that all subsequent response headers match 1.312 + 1.313 + int64_t mContentLength; 1.314 + nsCString mETag; 1.315 + nsCString mLastModified; 1.316 + nsCString mContentRange; 1.317 + nsCString mContentEncoding; 1.318 + nsCString mTransferEncoding; 1.319 + 1.320 + // This is the amount of data that has been passed to the channel 1.321 + // from previous iterations of the transaction and must therefore 1.322 + // be skipped in the new one. 1.323 + int64_t mAlreadyProcessed; 1.324 + 1.325 + // The amount of data that must be discarded in the current iteration 1.326 + // (where iteration > 0) to reach the mAlreadyProcessed high water 1.327 + // mark. 1.328 + int64_t mToReadBeforeRestart; 1.329 + 1.330 + // true when ::Set has been called with a response header 1.331 + bool mSetup; 1.332 + } mRestartInProgressVerifier; 1.333 + 1.334 +// For Rate Pacing via an EventTokenBucket 1.335 +public: 1.336 + // called by the connection manager to run this transaction through the 1.337 + // token bucket. If the token bucket admits the transaction immediately it 1.338 + // returns true. The function is called repeatedly until it returns true. 1.339 + bool TryToRunPacedRequest(); 1.340 + 1.341 + // ATokenBucketEvent pure virtual implementation. Called by the token bucket 1.342 + // when the transaction is ready to run. If this happens asynchrounously to 1.343 + // token bucket submission the transaction just posts an event that causes 1.344 + // the pending transaction queue to be rerun (and TryToRunPacedRequest() to 1.345 + // be run again. 1.346 + void OnTokenBucketAdmitted(); // ATokenBucketEvent 1.347 + 1.348 + // CancelPacing() can be used to tell the token bucket to remove this 1.349 + // transaction from the list of pending transactions. This is used when a 1.350 + // transaction is believed to be HTTP/1 (and thus subject to rate pacing) 1.351 + // but later can be dispatched via spdy (not subject to rate pacing). 1.352 + void CancelPacing(nsresult reason); 1.353 + 1.354 +private: 1.355 + bool mSubmittedRatePacing; 1.356 + bool mPassedRatePacing; 1.357 + bool mSynchronousRatePaceRequest; 1.358 + nsCOMPtr<nsICancelable> mTokenBucketCancel; 1.359 + 1.360 +// These members are used for network per-app metering (bug 746073) 1.361 +// Currently, they are only available on gonk. 1.362 + uint64_t mCountRecv; 1.363 + uint64_t mCountSent; 1.364 + uint32_t mAppId; 1.365 +#ifdef MOZ_WIDGET_GONK 1.366 + nsMainThreadPtrHandle<nsINetworkInterface> mActiveNetwork; 1.367 +#endif 1.368 + nsresult SaveNetworkStats(bool); 1.369 + void CountRecvBytes(uint64_t recvBytes) 1.370 + { 1.371 + mCountRecv += recvBytes; 1.372 + SaveNetworkStats(false); 1.373 + } 1.374 + void CountSentBytes(uint64_t sentBytes) 1.375 + { 1.376 + mCountSent += sentBytes; 1.377 + SaveNetworkStats(false); 1.378 + } 1.379 +}; 1.380 + 1.381 +}} // namespace mozilla::net 1.382 + 1.383 +#endif // nsHttpTransaction_h__