netwerk/protocol/http/nsHttpTransaction.h

changeset 0
6474c204b198
     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__

mercurial