Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/http/nsHttpTransaction.h
Line
Count
Source (jump to first uncovered line)
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 "nsIInterfaceRequestor.h"
16
#include "TimingStruct.h"
17
#include "Http2Push.h"
18
#include "mozilla/net/DNS.h"
19
#include "ARefBase.h"
20
#include "AlternateServices.h"
21
22
//-----------------------------------------------------------------------------
23
24
class nsIHttpActivityObserver;
25
class nsIEventTarget;
26
class nsIInputStream;
27
class nsIOutputStream;
28
class nsIRequestContext;
29
30
namespace mozilla { namespace net {
31
32
class nsHttpChunkedDecoder;
33
class nsHttpHeaderArray;
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 final : public nsAHttpTransaction
43
                              , public ATokenBucketEvent
44
                              , public nsIInputStreamCallback
45
                              , public nsIOutputStreamCallback
46
                              , public ARefBase
47
{
48
public:
49
    NS_DECL_THREADSAFE_ISUPPORTS
50
    NS_DECL_NSAHTTPTRANSACTION
51
    NS_DECL_NSIINPUTSTREAMCALLBACK
52
    NS_DECL_NSIOUTPUTSTREAMCALLBACK
53
54
    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 topLevelOuterContentWindowId
74
    //        indicate the top level outer content window in which
75
    //        this transaction is being loaded.
76
    // @param responseBody
77
    //        the input stream that will contain the response data.  async
78
    //        wait on this input stream for data.  on first notification,
79
    //        headers should be available (check transaction status).
80
    //
81
    MOZ_MUST_USE nsresult Init(uint32_t               caps,
82
                               nsHttpConnectionInfo  *connInfo,
83
                               nsHttpRequestHead     *reqHeaders,
84
                               nsIInputStream        *reqBody,
85
                               uint64_t               reqContentLength,
86
                               bool                   reqBodyIncludesHeaders,
87
                               nsIEventTarget        *consumerTarget,
88
                               nsIInterfaceRequestor *callbacks,
89
                               nsITransportEventSink *eventsink,
90
                               uint64_t               topLevelOuterContentWindowId,
91
                               nsIAsyncInputStream  **responseBody);
92
93
    void OnActivated() override;
94
95
    // attributes
96
0
    nsHttpResponseHead    *ResponseHead()   { return mHaveAllHeaders ? mResponseHead : nullptr; }
97
0
    nsISupports           *SecurityInfo()   { return mSecurityInfo; }
98
99
0
    nsIEventTarget        *ConsumerTarget() { return mConsumerTarget; }
100
0
    nsISupports           *HttpChannel()    { return mChannel; }
101
102
    void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks);
103
104
    // Called to take ownership of the response headers; the transaction
105
    // will drop any reference to the response headers after this call.
106
    nsHttpResponseHead *TakeResponseHead();
107
108
    // Called to take ownership of the trailer headers.
109
    // Returning null if there is no trailer.
110
    nsHttpHeaderArray *TakeResponseTrailers();
111
112
    // Provides a thread safe reference of the connection
113
    // nsHttpTransaction::Connection should only be used on the socket thread
114
    already_AddRefed<nsAHttpConnection> GetConnectionReference();
115
116
    // Called to set/find out if the transaction generated a complete response.
117
0
    bool ResponseIsComplete() { return mResponseIsComplete; }
118
0
    void SetResponseIsComplete() { mResponseIsComplete = true; }
119
120
0
    bool      ProxyConnectFailed() { return mProxyConnectFailed; }
121
122
0
    void EnableKeepAlive() { mCaps |= NS_HTTP_ALLOW_KEEPALIVE; }
123
0
    void MakeSticky() { mCaps |= NS_HTTP_STICKY_CONNECTION; }
124
125
    // SetPriority() may only be used by the connection manager.
126
0
    void    SetPriority(int32_t priority) { mPriority = priority; }
127
0
    int32_t    Priority()                 { return mPriority; }
128
129
    void PrintDiagnostics(nsCString &log);
130
131
    // Sets mPendingTime to the current time stamp or to a null time stamp (if now is false)
132
0
    void SetPendingTime(bool now = true) { mPendingTime = now ? TimeStamp::Now() : TimeStamp(); }
133
0
    const TimeStamp GetPendingTime() { return mPendingTime; }
134
135
    // overload of nsAHttpTransaction::RequestContext()
136
0
    nsIRequestContext *RequestContext() override { return mRequestContext.get(); }
137
    void SetRequestContext(nsIRequestContext *aRequestContext);
138
    void DispatchedAsBlocking();
139
    void RemoveDispatchedAsBlocking();
140
141
0
    nsHttpTransaction *QueryHttpTransaction() override { return this; }
142
143
0
    Http2PushedStream *GetPushedStream() { return mPushedStream; }
144
    Http2PushedStream *TakePushedStream()
145
0
    {
146
0
        Http2PushedStream *r = mPushedStream;
147
0
        mPushedStream = nullptr;
148
0
        return r;
149
0
    }
150
0
    void SetPushedStream(Http2PushedStream *push) { mPushedStream = push; }
151
0
    uint32_t InitialRwin() const { return mInitialRwin; };
152
0
    bool ChannelPipeFull() { return mWaitingOnPipeOut; }
153
154
    // Locked methods to get and set timing info
155
    const TimingStruct Timings();
156
    void BootstrapTimings(TimingStruct times);
157
    void SetDomainLookupStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false);
158
    void SetDomainLookupEnd(mozilla::TimeStamp timeStamp, bool onlyIfNull = false);
159
    void SetConnectStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false);
160
    void SetConnectEnd(mozilla::TimeStamp timeStamp, bool onlyIfNull = false);
161
    void SetRequestStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false);
162
    void SetResponseStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false);
163
    void SetResponseEnd(mozilla::TimeStamp timeStamp, bool onlyIfNull = false);
164
165
    mozilla::TimeStamp GetDomainLookupStart();
166
    mozilla::TimeStamp GetDomainLookupEnd();
167
    mozilla::TimeStamp GetConnectStart();
168
    mozilla::TimeStamp GetTcpConnectEnd();
169
    mozilla::TimeStamp GetSecureConnectionStart();
170
171
    mozilla::TimeStamp GetConnectEnd();
172
    mozilla::TimeStamp GetRequestStart();
173
    mozilla::TimeStamp GetResponseStart();
174
    mozilla::TimeStamp GetResponseEnd();
175
176
0
    int64_t GetTransferSize() { return mTransferSize; }
177
178
    MOZ_MUST_USE bool Do0RTT() override;
179
    MOZ_MUST_USE nsresult Finish0RTT(bool aRestart, bool aAlpnChanged /* ignored */) override;
180
181
    // After Finish0RTT early data may have failed but the caller did not request
182
    // restart - this indicates that state for dev tools
183
    void Refused0RTT();
184
185
    MOZ_MUST_USE bool CanDo0RTT() override;
186
    MOZ_MUST_USE nsresult RestartOnFastOpenError() override;
187
188
    uint64_t TopLevelOuterContentWindowId() override
189
0
    {
190
0
        return mTopLevelOuterContentWindowId;
191
0
    }
192
193
    void SetFastOpenStatus(uint8_t aStatus) override;
194
195
    void SetHttpTrailers(nsCString &aTrailers);
196
private:
197
    friend class DeleteHttpTransaction;
198
    virtual ~nsHttpTransaction();
199
200
    MOZ_MUST_USE nsresult Restart();
201
    char    *LocateHttpStart(char *buf, uint32_t len,
202
                             bool aAllowPartialMatch);
203
    MOZ_MUST_USE nsresult ParseLine(nsACString &line);
204
    MOZ_MUST_USE nsresult ParseLineSegment(char *seg, uint32_t len);
205
    MOZ_MUST_USE nsresult ParseHead(char *, uint32_t count,
206
                                    uint32_t *countRead);
207
    MOZ_MUST_USE nsresult HandleContentStart();
208
    MOZ_MUST_USE nsresult HandleContent(char *, uint32_t count,
209
                                        uint32_t *contentRead,
210
                                        uint32_t *contentRemaining);
211
    MOZ_MUST_USE nsresult ProcessData(char *, uint32_t, uint32_t *);
212
    void     DeleteSelfOnConsumerThread();
213
    void     ReleaseBlockingTransaction();
214
215
    static MOZ_MUST_USE nsresult ReadRequestSegment(nsIInputStream *, void *,
216
                                                    const char *, uint32_t,
217
                                                    uint32_t, uint32_t *);
218
    static MOZ_MUST_USE nsresult WritePipeSegment(nsIOutputStream *, void *,
219
                                                  char *, uint32_t, uint32_t,
220
                                                  uint32_t *);
221
222
0
    bool TimingEnabled() const { return mCaps & NS_HTTP_TIMING_ENABLED; }
223
224
    bool ResponseTimeoutEnabled() const final;
225
226
    void DisableSpdy() override;
227
0
    void ReuseConnectionOnRestartOK(bool reuseOk) override { mReuseOnRestart = reuseOk; }
228
229
    // Called right after we parsed the response head.  Checks for connection based
230
    // authentication schemes in reponse headers for WWW and Proxy authentication.
231
    // If such is found in any of them, NS_HTTP_STICKY_CONNECTION is set in mCaps.
232
    // We need the sticky flag be set early to keep the connection from very start
233
    // of the authentication process.
234
    void CheckForStickyAuthScheme();
235
    void CheckForStickyAuthSchemeAt(nsHttpAtom const& header);
236
237
    // Called from WriteSegments.  Checks for conditions whether to throttle reading
238
    // the content.  When this returns true, WriteSegments returns WOULD_BLOCK.
239
    bool ShouldThrottle();
240
241
private:
242
    class UpdateSecurityCallbacks : public Runnable
243
    {
244
      public:
245
        UpdateSecurityCallbacks(nsHttpTransaction* aTrans,
246
                                nsIInterfaceRequestor* aCallbacks)
247
          : Runnable("net::nsHttpTransaction::UpdateSecurityCallbacks")
248
          , mTrans(aTrans)
249
          , mCallbacks(aCallbacks)
250
0
        {
251
0
        }
252
253
        NS_IMETHOD Run() override
254
0
        {
255
0
            if (mTrans->mConnection)
256
0
                mTrans->mConnection->SetSecurityCallbacks(mCallbacks);
257
0
            return NS_OK;
258
0
        }
259
      private:
260
        RefPtr<nsHttpTransaction> mTrans;
261
        nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
262
    };
263
264
    Mutex mLock;
265
266
    nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
267
    nsCOMPtr<nsITransportEventSink> mTransportSink;
268
    nsCOMPtr<nsIEventTarget>        mConsumerTarget;
269
    nsCOMPtr<nsISupports>           mSecurityInfo;
270
    nsCOMPtr<nsIAsyncInputStream>   mPipeIn;
271
    nsCOMPtr<nsIAsyncOutputStream>  mPipeOut;
272
    nsCOMPtr<nsIRequestContext>     mRequestContext;
273
274
    nsCOMPtr<nsISupports>             mChannel;
275
    nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor;
276
277
    nsCString                       mReqHeaderBuf;    // flattened request headers
278
    nsCOMPtr<nsIInputStream>        mRequestStream;
279
    int64_t                         mRequestSize;
280
281
    RefPtr<nsAHttpConnection>     mConnection;
282
    RefPtr<nsHttpConnectionInfo>  mConnInfo;
283
    nsHttpRequestHead              *mRequestHead;     // weak ref
284
    nsHttpResponseHead             *mResponseHead;    // owning pointer
285
286
    nsAHttpSegmentReader           *mReader;
287
    nsAHttpSegmentWriter           *mWriter;
288
289
    nsCString                       mLineBuf;         // may contain a partial line
290
291
    int64_t                         mContentLength;   // equals -1 if unknown
292
    int64_t                         mContentRead;     // count of consumed content bytes
293
    Atomic<int64_t, ReleaseAcquire> mTransferSize; // count of received bytes
294
295
    // After a 304/204 or other "no-content" style response we will skip over
296
    // up to MAX_INVALID_RESPONSE_BODY_SZ bytes when looking for the next
297
    // response header to deal with servers that actually sent a response
298
    // body where they should not have. This member tracks how many bytes have
299
    // so far been skipped.
300
    uint32_t                        mInvalidResponseBytesRead;
301
302
    Http2PushedStream               *mPushedStream;
303
    uint32_t                        mInitialRwin;
304
305
    nsHttpChunkedDecoder            *mChunkedDecoder;
306
307
    TimingStruct                    mTimings;
308
309
    nsresult                        mStatus;
310
311
    int16_t                         mPriority;
312
313
    uint16_t                        mRestartCount;        // the number of times this transaction has been restarted
314
    uint32_t                        mCaps;
315
316
    HttpVersion                     mHttpVersion;
317
    uint16_t                        mHttpResponseCode;
318
319
    uint32_t                        mCurrentHttpResponseHeaderSize;
320
321
    int32_t const THROTTLE_NO_LIMIT = -1;
322
    // This can have 3 possible values:
323
    // * THROTTLE_NO_LIMIT - this means the transaction is not in any way limited
324
    //                       to read the response, this is the default
325
    // * a positive number - a limit is set because the transaction is obligated
326
    //                       to throttle the response read, this is decresed with
327
    //                       every piece of data the transaction receives
328
    // * zero - when the transaction depletes the limit for reading, this makes it
329
    //          stop reading and return WOULD_BLOCK from WriteSegments; transaction
330
    //          then waits for a call of ResumeReading that resets this member back
331
    //          to THROTTLE_NO_LIMIT
332
    int32_t                         mThrottlingReadAllowance;
333
334
    // mCapsToClear holds flags that should be cleared in mCaps, e.g. unset
335
    // NS_HTTP_REFRESH_DNS when DNS refresh request has completed to avoid
336
    // redundant requests on the network. The member itself is atomic, but
337
    // access to it from the networking thread may happen either before or
338
    // after the main thread modifies it. To deal with raciness, only unsetting
339
    // bitfields should be allowed: 'lost races' will thus err on the
340
    // conservative side, e.g. by going ahead with a 2nd DNS refresh.
341
    Atomic<uint32_t>                mCapsToClear;
342
    Atomic<bool, ReleaseAcquire>    mResponseIsComplete;
343
344
    // True iff WriteSegments was called while this transaction should be throttled (stop reading)
345
    // Used to resume read on unblock of reading.  Conn manager is responsible for calling back
346
    // to resume reading.
347
    bool                            mReadingStopped;
348
349
    // state flags, all logically boolean, but not packed together into a
350
    // bitfield so as to avoid bitfield-induced races.  See bug 560579.
351
    bool                            mClosed;
352
    bool                            mConnected;
353
    bool                            mActivated;
354
    bool                            mHaveStatusLine;
355
    bool                            mHaveAllHeaders;
356
    bool                            mTransactionDone;
357
    bool                            mDidContentStart;
358
    bool                            mNoContent; // expecting an empty entity body
359
    bool                            mSentData;
360
    bool                            mReceivedData;
361
    bool                            mStatusEventPending;
362
    bool                            mHasRequestBody;
363
    bool                            mProxyConnectFailed;
364
    bool                            mHttpResponseMatched;
365
    bool                            mPreserveStream;
366
    bool                            mDispatchedAsBlocking;
367
    bool                            mResponseTimeoutEnabled;
368
    bool                            mForceRestart;
369
    bool                            mReuseOnRestart;
370
    bool                            mContentDecoding;
371
    bool                            mContentDecodingCheck;
372
    bool                            mDeferredSendProgress;
373
    bool                            mWaitingOnPipeOut;
374
375
    // mClosed           := transaction has been explicitly closed
376
    // mTransactionDone  := transaction ran to completion or was interrupted
377
    // mResponseComplete := transaction ran to completion
378
379
    // For Restart-In-Progress Functionality
380
    bool                            mReportedStart;
381
    bool                            mReportedResponseHeader;
382
383
    // protected by nsHttp::GetLock()
384
    bool                            mResponseHeadTaken;
385
    nsAutoPtr<nsHttpHeaderArray>    mForTakeResponseTrailers;
386
    bool                            mResponseTrailersTaken;
387
388
    // The time when the transaction was submitted to the Connection Manager
389
    TimeStamp                       mPendingTime;
390
391
    uint64_t                        mTopLevelOuterContentWindowId;
392
393
// For Rate Pacing via an EventTokenBucket
394
public:
395
    // called by the connection manager to run this transaction through the
396
    // token bucket. If the token bucket admits the transaction immediately it
397
    // returns true. The function is called repeatedly until it returns true.
398
    bool TryToRunPacedRequest();
399
400
    // ATokenBucketEvent pure virtual implementation. Called by the token bucket
401
    // when the transaction is ready to run. If this happens asynchrounously to
402
    // token bucket submission the transaction just posts an event that causes
403
    // the pending transaction queue to be rerun (and TryToRunPacedRequest() to
404
    // be run again.
405
    void OnTokenBucketAdmitted() override; // ATokenBucketEvent
406
407
    // CancelPacing() can be used to tell the token bucket to remove this
408
    // transaction from the list of pending transactions. This is used when a
409
    // transaction is believed to be HTTP/1 (and thus subject to rate pacing)
410
    // but later can be dispatched via spdy (not subject to rate pacing).
411
    void CancelPacing(nsresult reason);
412
413
    // Called by the connetion manager on the socket thread when reading for this
414
    // previously throttled transaction has to be resumed.
415
    void ResumeReading();
416
417
    // This examins classification of this transaction whether the Throttleable class
418
    // has been set while Leader, Unblocked, DontThrottle has not.
419
    bool EligibleForThrottling() const;
420
421
private:
422
    bool mSubmittedRatePacing;
423
    bool mPassedRatePacing;
424
    bool mSynchronousRatePaceRequest;
425
    nsCOMPtr<nsICancelable> mTokenBucketCancel;
426
public:
427
    void     SetClassOfService(uint32_t cos);
428
0
    uint32_t ClassOfService() { return mClassOfService; }
429
private:
430
    uint32_t mClassOfService;
431
432
public:
433
    // setting TunnelProvider to non-null means the transaction should only
434
    // be dispatched on a specific ConnectionInfo Hash Key (as opposed to a
435
    // generic wild card one). That means in the specific case of carrying this
436
    // transaction on an HTTP/2 tunnel it will only be dispatched onto an
437
    // existing tunnel instead of triggering creation of a new one.
438
    // The tunnel provider is used for ASpdySession::MaybeReTunnel() checks.
439
440
0
    void SetTunnelProvider(ASpdySession *provider) { mTunnelProvider = provider; }
441
0
    ASpdySession *TunnelProvider() { return mTunnelProvider; }
442
0
    nsIInterfaceRequestor *SecurityCallbacks() { return mCallbacks; }
443
444
private:
445
    RefPtr<ASpdySession> mTunnelProvider;
446
447
public:
448
0
    void SetTransactionObserver(TransactionObserver *arg) { mTransactionObserver = arg; }
449
private:
450
    RefPtr<TransactionObserver> mTransactionObserver;
451
public:
452
    void GetNetworkAddresses(NetAddr &self, NetAddr &peer);
453
454
private:
455
    NetAddr                         mSelfAddr;
456
    NetAddr                         mPeerAddr;
457
458
    bool                            m0RTTInProgress;
459
    bool                            mDoNotTryEarlyData;
460
    enum
461
    {
462
        EARLY_NONE,
463
        EARLY_SENT,
464
        EARLY_ACCEPTED,
465
        EARLY_425
466
    } mEarlyDataDisposition;
467
468
    uint8_t mFastOpenStatus;
469
};
470
471
} // namespace net
472
} // namespace mozilla
473
474
#endif // nsHttpTransaction_h__