gecko/netwerk/protocol/http/nsHttpTransaction.h
Patrick McManus f5c0c33db7 bug 603512 - large objects block pipelines r=honzab
the type and state patch tries hard not to form pipelines behind resources that
could become head of line blockers. But of course that requires the ability to
predict the future, and won't be perfect.

This patch reacts to a transaction that has a large response body (defined by
either a large content-length header or actually reading a large number of
chunked bytes) by cancelling any transactions that have been pipelined down the
same connection and rescheduling them elsewhere. It also changes the type of
the connection to "solo", which prevents new transactions from being pipelined
onto this one and provides class-specific negative feedback to the pipeline
manager so that near-future requests to the same host of the same type (e.g.
general) will not be pipelined but other types (e.g. img or js/css) can still
do that.

Content-Length is ideal, because it allows us to identify the problem so early.
But even actually reading the document for a fairly long time gives it a fairly
high probability of not ending soon. (i.e. long document sizes are spread over
a larger range than small ones. duh.)

The pref network.http.pipelining.maxsize controls the threshold. I set the
default at 300KB, which is roughly the bandwidth delay product of a 2mbit 120ms
rtt connection and 1 rtt is mostly what you are giving up by canceling it on
one connection and sending it on another. (modulo maybe needing a handshake).
2012-03-22 19:39:31 -04:00

234 lines
9.7 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is
* Netscape Communications.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@netscape.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsHttpTransaction_h__
#define nsHttpTransaction_h__
#include "nsHttp.h"
#include "nsHttpHeaderArray.h"
#include "nsAHttpTransaction.h"
#include "nsAHttpConnection.h"
#include "nsCOMPtr.h"
#include "nsIPipe.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIInterfaceRequestor.h"
#include "nsISocketTransportService.h"
#include "nsITransport.h"
#include "nsIEventTarget.h"
#include "TimingStruct.h"
//-----------------------------------------------------------------------------
class nsHttpTransaction;
class nsHttpRequestHead;
class nsHttpResponseHead;
class nsHttpChunkedDecoder;
class nsIHttpActivityObserver;
//-----------------------------------------------------------------------------
// nsHttpTransaction represents a single HTTP transaction. It is thread-safe,
// intended to run on the socket thread.
//-----------------------------------------------------------------------------
class nsHttpTransaction : public nsAHttpTransaction
, public nsIInputStreamCallback
, public nsIOutputStreamCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSAHTTPTRANSACTION
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSIOUTPUTSTREAMCALLBACK
nsHttpTransaction();
virtual ~nsHttpTransaction();
//
// called to initialize the transaction
//
// @param caps
// the transaction capabilities (see nsHttp.h)
// @param connInfo
// the connection type for this transaction.
// @param reqHeaders
// the request header struct
// @param reqBody
// the request body (POST or PUT data stream)
// @param reqBodyIncludesHeaders
// fun stuff to support NPAPI plugins.
// @param target
// the dispatch target were notifications should be sent.
// @param callbacks
// the notification callbacks to be given to PSM.
// @param responseBody
// the input stream that will contain the response data. async
// wait on this input stream for data. on first notification,
// headers should be available (check transaction status).
//
nsresult Init(PRUint8 caps,
nsHttpConnectionInfo *connInfo,
nsHttpRequestHead *reqHeaders,
nsIInputStream *reqBody,
bool reqBodyIncludesHeaders,
nsIEventTarget *consumerTarget,
nsIInterfaceRequestor *callbacks,
nsITransportEventSink *eventsink,
nsIAsyncInputStream **responseBody);
// attributes
nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; }
nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nsnull; }
nsISupports *SecurityInfo() { return mSecurityInfo; }
nsIInterfaceRequestor *Callbacks() { return mCallbacks; }
nsIEventTarget *ConsumerTarget() { return mConsumerTarget; }
// Called to take ownership of the response headers; the transaction
// will drop any reference to the response headers after this call.
nsHttpResponseHead *TakeResponseHead();
// Called to find out if the transaction generated a complete response.
bool ResponseIsComplete() { return mResponseIsComplete; }
bool SSLConnectFailed() { return mSSLConnectFailed; }
// SetPriority() may only be used by the connection manager.
void SetPriority(PRInt32 priority) { mPriority = priority; }
PRInt32 Priority() { return mPriority; }
const TimingStruct& Timings() const { return mTimings; }
enum Classifier Classification() { return mClassification; }
private:
nsresult Restart();
char *LocateHttpStart(char *buf, PRUint32 len,
bool aAllowPartialMatch);
nsresult ParseLine(char *line);
nsresult ParseLineSegment(char *seg, PRUint32 len);
nsresult ParseHead(char *, PRUint32 count, PRUint32 *countRead);
nsresult HandleContentStart();
nsresult HandleContent(char *, PRUint32 count, PRUint32 *contentRead, PRUint32 *contentRemaining);
nsresult ProcessData(char *, PRUint32, PRUint32 *);
void DeleteSelfOnConsumerThread();
Classifier Classify();
void CancelPipeline(PRUint32 reason);
static NS_METHOD ReadRequestSegment(nsIInputStream *, void *, const char *,
PRUint32, PRUint32, PRUint32 *);
static NS_METHOD WritePipeSegment(nsIOutputStream *, void *, char *,
PRUint32, PRUint32, PRUint32 *);
bool TimingEnabled() const { return mCaps & NS_HTTP_TIMING_ENABLED; }
private:
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsITransportEventSink> mTransportSink;
nsCOMPtr<nsIEventTarget> mConsumerTarget;
nsCOMPtr<nsISupports> mSecurityInfo;
nsCOMPtr<nsIAsyncInputStream> mPipeIn;
nsCOMPtr<nsIAsyncOutputStream> mPipeOut;
nsCOMPtr<nsISupports> mChannel;
nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor;
nsCString mReqHeaderBuf; // flattened request headers
nsCOMPtr<nsIInputStream> mRequestStream;
PRUint32 mRequestSize;
nsAHttpConnection *mConnection; // hard ref
nsHttpConnectionInfo *mConnInfo; // hard ref
nsHttpRequestHead *mRequestHead; // weak ref
nsHttpResponseHead *mResponseHead; // hard ref
nsAHttpSegmentReader *mReader;
nsAHttpSegmentWriter *mWriter;
nsCString mLineBuf; // may contain a partial line
PRInt64 mContentLength; // equals -1 if unknown
PRInt64 mContentRead; // count of consumed content bytes
// After a 304/204 or other "no-content" style response we will skip over
// up to MAX_INVALID_RESPONSE_BODY_SZ bytes when looking for the next
// response header to deal with servers that actually sent a response
// body where they should not have. This member tracks how many bytes have
// so far been skipped.
PRUint32 mInvalidResponseBytesRead;
nsHttpChunkedDecoder *mChunkedDecoder;
TimingStruct mTimings;
nsresult mStatus;
PRInt16 mPriority;
PRUint16 mRestartCount; // the number of times this transaction has been restarted
PRUint8 mCaps;
enum Classifier mClassification;
PRInt32 mPipelinePosition;
PRInt64 mMaxPipelineObjectSize;
// state flags, all logically boolean, but not packed together into a
// bitfield so as to avoid bitfield-induced races. See bug 560579.
bool mClosed;
bool mConnected;
bool mHaveStatusLine;
bool mHaveAllHeaders;
bool mTransactionDone;
bool mResponseIsComplete;
bool mDidContentStart;
bool mNoContent; // expecting an empty entity body
bool mSentData;
bool mReceivedData;
bool mStatusEventPending;
bool mHasRequestBody;
bool mSSLConnectFailed;
bool mHttpResponseMatched;
bool mPreserveStream;
// mClosed := transaction has been explicitly closed
// mTransactionDone := transaction ran to completion or was interrupted
// mResponseComplete := transaction ran to completion
};
#endif // nsHttpTransaction_h__