зеркало из https://github.com/mozilla/pjs.git
bug 447866 http pipelining is bursty r=honzab
--HG-- extra : rebase_source : e927c5961b2f6c79c1aa73897900e95ed3f286c5
This commit is contained in:
Родитель
e2109fe3bc
Коммит
7abd00c179
|
@ -2075,6 +2075,13 @@ SpdySession::Status()
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
PRUint8
|
||||
SpdySession::Caps()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(false, "SpdySession::Caps()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
SpdySession::Available()
|
||||
{
|
||||
|
@ -2132,6 +2139,26 @@ SpdySession::TakeSubTransactions(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SpdySession::AddTransaction(nsAHttpTransaction *)
|
||||
{
|
||||
// This API is meant for pipelining, SpdySession's should be
|
||||
// extended with AddStream()
|
||||
|
||||
NS_ABORT_IF_FALSE(false,
|
||||
"SpdySession::AddTransaction() should not be called");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
PRUint16
|
||||
SpdySession::PipelineDepthAvailable()
|
||||
{
|
||||
// any attempt at pipelining will be turned into parallelism
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Pass through methods of nsAHttpConnection
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -2179,6 +2206,13 @@ SpdySession::PushBack(const char *buf, PRUint32 len)
|
|||
return mConnection->PushBack(buf, len);
|
||||
}
|
||||
|
||||
bool
|
||||
SpdySession::IsProxyConnectInProgress()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mConnection, "no connection");
|
||||
return mConnection->IsProxyConnectInProgress();
|
||||
}
|
||||
|
||||
bool
|
||||
SpdySession::LastTransactionExpectedNoContent()
|
||||
{
|
||||
|
|
|
@ -127,6 +127,11 @@ public:
|
|||
// than it should have (eg. containing part of the next pipelined response).
|
||||
virtual nsresult PushBack(const char *data, PRUint32 length) = 0;
|
||||
|
||||
// Used to determine if the connection wants read events even though
|
||||
// it has not written out a transaction. Used when a connection has issued
|
||||
// a preamble such as a proxy ssl CONNECT sequence.
|
||||
virtual bool IsProxyConnectInProgress() = 0;
|
||||
|
||||
// Used by a transaction to manage the state of previous response bodies on
|
||||
// the same connection and work around buggy servers.
|
||||
virtual bool LastTransactionExpectedNoContent() = 0;
|
||||
|
@ -154,6 +159,7 @@ public:
|
|||
bool IsPersistent(); \
|
||||
bool IsReused(); \
|
||||
nsresult PushBack(const char *, PRUint32); \
|
||||
bool IsProxyConnectInProgress(); \
|
||||
bool LastTransactionExpectedNoContent(); \
|
||||
void SetLastTransactionExpectedNoContent(bool); \
|
||||
nsHttpConnection *TakeHttpConnection(); \
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
// called to check the transaction status.
|
||||
virtual bool IsDone() = 0;
|
||||
virtual nsresult Status() = 0;
|
||||
virtual PRUint8 Caps() = 0;
|
||||
|
||||
// called to find out how much request data is available for writing.
|
||||
virtual PRUint32 Available() = 0;
|
||||
|
@ -114,6 +115,14 @@ public:
|
|||
//
|
||||
virtual nsresult TakeSubTransactions(
|
||||
nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions) = 0;
|
||||
|
||||
// called to add a sub-transaction in the case of pipelined transactions
|
||||
// classes that do not implement sub transactions
|
||||
// return NS_ERROR_NOT_IMPLEMENTED
|
||||
virtual nsresult AddTransaction(nsAHttpTransaction *transaction) = 0;
|
||||
|
||||
// called to count the number of sub transactions that can be added
|
||||
virtual PRUint16 PipelineDepthAvailable() = 0;
|
||||
};
|
||||
|
||||
#define NS_DECL_NSAHTTPTRANSACTION \
|
||||
|
@ -125,6 +134,7 @@ public:
|
|||
nsresult status, PRUint64 progress); \
|
||||
bool IsDone(); \
|
||||
nsresult Status(); \
|
||||
PRUint8 Caps(); \
|
||||
PRUint32 Available(); \
|
||||
nsresult ReadSegments(nsAHttpSegmentReader *, PRUint32, PRUint32 *); \
|
||||
nsresult WriteSegments(nsAHttpSegmentWriter *, PRUint32, PRUint32 *); \
|
||||
|
@ -132,7 +142,9 @@ public:
|
|||
void SetSSLConnectFailed(); \
|
||||
nsHttpRequestHead *RequestHead(); \
|
||||
PRUint32 Http1xTransactionCount(); \
|
||||
nsresult TakeSubTransactions(nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions);
|
||||
nsresult TakeSubTransactions(nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions); \
|
||||
nsresult AddTransaction(nsAHttpTransaction *); \
|
||||
PRUint16 PipelineDepthAvailable();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsAHttpSegmentReader
|
||||
|
|
|
@ -86,6 +86,7 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mCompletedProxyConnect(false)
|
||||
, mLastTransactionExpectedNoContent(false)
|
||||
, mIdleMonitoring(false)
|
||||
, mProxyConnectInProgress(false)
|
||||
, mHttp1xTransactionCount(0)
|
||||
, mNPNComplete(false)
|
||||
, mSetupNPNCalled(false)
|
||||
|
@ -153,6 +154,7 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info,
|
|||
NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
|
||||
|
||||
mConnInfo = info;
|
||||
mSupportsPipelining = mConnInfo->SupportsPipelining();
|
||||
mMaxHangTime = PR_SecondsToInterval(maxHangTime);
|
||||
mLastReadTime = PR_IntervalNow();
|
||||
|
||||
|
@ -369,6 +371,7 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, PRUint8 caps, PRInt32 pri)
|
|||
rv = SetupProxyConnect();
|
||||
if (NS_FAILED(rv))
|
||||
goto failed_activation;
|
||||
mProxyConnectInProgress = true;
|
||||
}
|
||||
|
||||
// Clear the per activation counter
|
||||
|
@ -733,6 +736,7 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
}
|
||||
}
|
||||
mKeepAliveMask = mKeepAlive;
|
||||
mConnInfo->SetSupportsPipelining(mSupportsPipelining);
|
||||
|
||||
// if this connection is persistent, then the server may send a "Keep-Alive"
|
||||
// header specifying the maximum number of times the connection can be
|
||||
|
@ -1094,6 +1098,7 @@ nsHttpConnection::OnSocketWritable()
|
|||
}
|
||||
|
||||
LOG((" writing transaction request stream\n"));
|
||||
mProxyConnectInProgress = false;
|
||||
rv = mTransaction->ReadSegments(this, nsIOService::gDefaultSegmentSize, &n);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpConnectionInfo.h"
|
||||
#include "nsAHttpConnection.h"
|
||||
#include "nsAHttpTransaction.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -56,6 +55,9 @@
|
|||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIEventTarget.h"
|
||||
|
||||
class nsHttpRequestHead;
|
||||
class nsHttpResponseHead;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnection - represents a connection to a HTTP server (or proxy)
|
||||
//
|
||||
|
@ -115,6 +117,11 @@ public:
|
|||
void DontReuse();
|
||||
void DropTransport() { DontReuse(); mSocketTransport = 0; }
|
||||
|
||||
bool IsProxyConnectInProgress()
|
||||
{
|
||||
return mProxyConnectInProgress;
|
||||
}
|
||||
|
||||
bool LastTransactionExpectedNoContent()
|
||||
{
|
||||
return mLastTransactionExpectedNoContent;
|
||||
|
@ -228,6 +235,7 @@ private:
|
|||
bool mCompletedProxyConnect;
|
||||
bool mLastTransactionExpectedNoContent;
|
||||
bool mIdleMonitoring;
|
||||
bool mProxyConnectInProgress;
|
||||
|
||||
// The number of <= HTTP/1.1 transactions performed on this connection. This
|
||||
// excludes spdy transactions.
|
||||
|
|
|
@ -60,6 +60,7 @@ public:
|
|||
: mRef(0)
|
||||
, mProxyInfo(proxyInfo)
|
||||
, mUsingSSL(usingSSL)
|
||||
, mSupportsPipelining(false)
|
||||
{
|
||||
LOG(("Creating nsHttpConnectionInfo @%x\n", this));
|
||||
|
||||
|
@ -125,6 +126,11 @@ public:
|
|||
void SetAnonymous(bool anon)
|
||||
{ mHashKey.SetCharAt(anon ? 'A' : '.', 2); }
|
||||
bool GetAnonymous() { return mHashKey.CharAt(2) == 'A'; }
|
||||
|
||||
bool SupportsPipelining() { return mSupportsPipelining; }
|
||||
void SetSupportsPipelining(bool support)
|
||||
{ mSupportsPipelining = support; }
|
||||
|
||||
bool ShouldForceConnectMethod();
|
||||
const nsCString &GetHost() { return mHost; }
|
||||
|
||||
|
@ -136,6 +142,7 @@ private:
|
|||
nsCOMPtr<nsProxyInfo> mProxyInfo;
|
||||
bool mUsingHttpProxy;
|
||||
bool mUsingSSL;
|
||||
bool mSupportsPipelining;
|
||||
};
|
||||
|
||||
#endif // nsHttpConnectionInfo_h__
|
||||
|
|
|
@ -352,26 +352,38 @@ nsHttpConnectionMgr::GetSocketThreadTarget(nsIEventTarget **target)
|
|||
void
|
||||
nsHttpConnectionMgr::AddTransactionToPipeline(nsHttpPipeline *pipeline)
|
||||
{
|
||||
/* called on an existing pipeline anytime we might add more data to an
|
||||
existing pipeline such as when a transaction completes (and
|
||||
therefore the quota has new room), or when we receive headers which
|
||||
might change our view of pipelining */
|
||||
|
||||
LOG(("nsHttpConnectionMgr::AddTransactionToPipeline [pipeline=%x]\n", pipeline));
|
||||
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
PRUint16 avail = pipeline->PipelineDepthAvailable();
|
||||
|
||||
nsRefPtr<nsHttpConnectionInfo> ci;
|
||||
pipeline->GetConnectionInfo(getter_AddRefs(ci));
|
||||
if (ci) {
|
||||
if (ci && avail && ci->SupportsPipelining()) {
|
||||
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
|
||||
if (ent) {
|
||||
// search for another request to pipeline...
|
||||
PRInt32 i, count = ent->mPendingQ.Length();
|
||||
for (i=0; i<count; ++i) {
|
||||
for (i = 0; i < count; ) {
|
||||
nsHttpTransaction *trans = ent->mPendingQ[i];
|
||||
if (trans->Caps() & NS_HTTP_ALLOW_PIPELINING) {
|
||||
pipeline->AddTransaction(trans);
|
||||
|
||||
// remove transaction from pending queue
|
||||
ent->mPendingQ.RemoveElementAt(i);
|
||||
--count;
|
||||
|
||||
NS_RELEASE(trans);
|
||||
break;
|
||||
if (--avail == 0)
|
||||
break;
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -956,6 +968,69 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionMgr::ProcessPipelinePendingQForEntry(nsConnectionEntry *ent)
|
||||
{
|
||||
LOG(("nsHttpConnectionMgr::ProcessPipelinePendingQForEntry [ci=%s]\n",
|
||||
ent->mConnInfo->HashKey().get()));
|
||||
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
if (mMaxPipelinedRequests < 2)
|
||||
return false;
|
||||
|
||||
PRUint32 activeCount = ent->mActiveConns.Length();
|
||||
PRUint32 originalPendingCount = ent->mPendingQ.Length();
|
||||
PRUint32 pendingCount = originalPendingCount;
|
||||
PRUint32 pendingIndex = 0;
|
||||
|
||||
for (PRUint32 activeIndex = 0;
|
||||
(activeIndex < activeCount) && (pendingIndex < pendingCount);
|
||||
++activeIndex) {
|
||||
nsHttpConnection *conn = ent->mActiveConns[activeIndex];
|
||||
|
||||
if (!conn->SupportsPipelining())
|
||||
continue;
|
||||
|
||||
nsAHttpTransaction *activeTrans = conn->Transaction();
|
||||
if (!activeTrans)
|
||||
continue;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
PRUint16 avail = activeTrans->PipelineDepthAvailable();
|
||||
|
||||
while (NS_SUCCEEDED(rv) && avail && (pendingIndex < pendingCount)) {
|
||||
nsHttpTransaction *trans = ent->mPendingQ[pendingIndex];
|
||||
if (trans->Caps() & NS_HTTP_ALLOW_PIPELINING) {
|
||||
rv = activeTrans->AddTransaction(trans);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// remove transaction from pending queue
|
||||
ent->mPendingQ.RemoveElementAt(pendingIndex);
|
||||
|
||||
// adjust iterator to reflect coalesced queue
|
||||
--pendingCount;
|
||||
--avail;
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
}
|
||||
else
|
||||
// skip over this one
|
||||
++pendingIndex;
|
||||
}
|
||||
}
|
||||
return originalPendingCount != pendingCount;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionMgr::ProcessPipelinePendingQForCI(nsHttpConnectionInfo *ci)
|
||||
{
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
|
||||
|
||||
return ent && ProcessPipelinePendingQForEntry(ent);
|
||||
}
|
||||
|
||||
// we're at the active connection limit if any one of the following conditions is true:
|
||||
// (1) at max-connections
|
||||
// (2) keep-alive enabled and at max-persistent-connections-per-server/proxy
|
||||
|
@ -1230,12 +1305,13 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
|
|||
|
||||
nsHttpPipeline *pipeline = nsnull;
|
||||
nsAHttpTransaction *trans = aTrans;
|
||||
|
||||
/* Use pipeline datastructure even if connection does not currently qualify
|
||||
to pipeline this transaction because a different pipeline-eligible
|
||||
transaction might be placed on the active connection */
|
||||
|
||||
if (conn->SupportsPipelining() && (caps & NS_HTTP_ALLOW_PIPELINING)) {
|
||||
LOG((" looking to build pipeline...\n"));
|
||||
if (BuildPipeline(ent, trans, &pipeline))
|
||||
trans = pipeline;
|
||||
}
|
||||
if (BuildPipeline(ent, trans, &pipeline))
|
||||
trans = pipeline;
|
||||
|
||||
// give the transaction the indirect reference to the connection.
|
||||
trans->SetConnection(handle);
|
||||
|
@ -1268,40 +1344,48 @@ nsHttpConnectionMgr::BuildPipeline(nsConnectionEntry *ent,
|
|||
nsAHttpTransaction *firstTrans,
|
||||
nsHttpPipeline **result)
|
||||
{
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
if (mMaxPipelinedRequests < 2)
|
||||
return false;
|
||||
|
||||
nsHttpPipeline *pipeline = nsnull;
|
||||
nsHttpTransaction *trans;
|
||||
/* form a pipeline here even if nothing is pending so that we
|
||||
can stream-feed it as new transactions arrive */
|
||||
|
||||
PRUint32 i = 0, numAdded = 0;
|
||||
while (i < ent->mPendingQ.Length()) {
|
||||
trans = ent->mPendingQ[i];
|
||||
if (trans->Caps() & NS_HTTP_ALLOW_PIPELINING) {
|
||||
if (numAdded == 0) {
|
||||
pipeline = new nsHttpPipeline;
|
||||
if (!pipeline)
|
||||
return false;
|
||||
pipeline->AddTransaction(firstTrans);
|
||||
numAdded = 1;
|
||||
nsHttpPipeline *pipeline = new nsHttpPipeline(mMaxPipelinedRequests);
|
||||
|
||||
/* the first transaction can go in unconditionally - 1 transaction
|
||||
on a nsHttpPipeline object is not a real HTTP pipeline */
|
||||
|
||||
PRUint16 numAdded = 1;
|
||||
pipeline->AddTransaction(firstTrans);
|
||||
|
||||
if (ent->mConnInfo->SupportsPipelining() &&
|
||||
firstTrans->Caps() & NS_HTTP_ALLOW_PIPELINING) {
|
||||
PRUint32 i = 0;
|
||||
nsHttpTransaction *trans;
|
||||
|
||||
while (i < ent->mPendingQ.Length()) {
|
||||
trans = ent->mPendingQ[i];
|
||||
if (trans->Caps() & NS_HTTP_ALLOW_PIPELINING) {
|
||||
pipeline->AddTransaction(trans);
|
||||
|
||||
// remove transaction from pending queue
|
||||
ent->mPendingQ.RemoveElementAt(i);
|
||||
NS_RELEASE(trans);
|
||||
|
||||
if (++numAdded == mMaxPipelinedRequests)
|
||||
break;
|
||||
}
|
||||
else {
|
||||
++i; // skip to next pending transaction
|
||||
}
|
||||
pipeline->AddTransaction(trans);
|
||||
|
||||
// remove transaction from pending queue
|
||||
ent->mPendingQ.RemoveElementAt(i);
|
||||
NS_RELEASE(trans);
|
||||
|
||||
if (++numAdded == mMaxPipelinedRequests)
|
||||
break;
|
||||
}
|
||||
else
|
||||
++i; // skip to next pending transaction
|
||||
}
|
||||
|
||||
if (numAdded == 0)
|
||||
return false;
|
||||
|
||||
LOG((" pipelined %u transactions\n", numAdded));
|
||||
if (numAdded > 1)
|
||||
LOG((" pipelined %u transactions\n", numAdded));
|
||||
|
||||
NS_ADDREF(*result = pipeline);
|
||||
return true;
|
||||
}
|
||||
|
@ -1375,6 +1459,11 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
|||
// put this transaction on the pending queue...
|
||||
InsertTransactionSorted(ent->mPendingQ, trans);
|
||||
NS_ADDREF(trans);
|
||||
|
||||
/* there still remains the possibility that the transaction we just
|
||||
queued could go out right away as a pipelined request on an existing
|
||||
connection */
|
||||
ProcessPipelinePendingQForEntry(ent);
|
||||
rv = NS_OK;
|
||||
}
|
||||
else {
|
||||
|
@ -2297,6 +2386,12 @@ nsHttpConnectionMgr::nsConnectionHandle::TakeHttpConnection()
|
|||
return conn;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionMgr::nsConnectionHandle::IsProxyConnectInProgress()
|
||||
{
|
||||
return mConn->IsProxyConnectInProgress();
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionMgr::nsConnectionHandle::LastTransactionExpectedNoContent()
|
||||
{
|
||||
|
|
|
@ -142,7 +142,7 @@ public:
|
|||
// NOTE: functions below may be called only on the socket thread.
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// removes the next transaction for the specified connection from the
|
||||
// removes the next transactions for the specified connection from the
|
||||
// pending transaction queue.
|
||||
void AddTransactionToPipeline(nsHttpPipeline *);
|
||||
|
||||
|
@ -160,6 +160,10 @@ public:
|
|||
// bit different.
|
||||
void ReportSpdyConnection(nsHttpConnection *, bool usingSpdy);
|
||||
|
||||
|
||||
// Similar to ProcessPendingQ, but only considers adding transactions to
|
||||
// existing connections
|
||||
bool ProcessPipelinePendingQForCI(nsHttpConnectionInfo *);
|
||||
private:
|
||||
virtual ~nsHttpConnectionMgr();
|
||||
class nsHalfOpenSocket;
|
||||
|
@ -311,6 +315,7 @@ private:
|
|||
static PLDHashOperator ClosePersistentConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
bool ProcessPendingQForEntry(nsConnectionEntry *);
|
||||
bool AtActiveConnectionLimit(nsConnectionEntry *, PRUint8 caps);
|
||||
bool ProcessPipelinePendingQForEntry(nsConnectionEntry *);
|
||||
void GetConnection(nsConnectionEntry *, nsHttpTransaction *,
|
||||
bool, nsHttpConnection **);
|
||||
nsresult DispatchTransaction(nsConnectionEntry *, nsHttpTransaction *,
|
||||
|
|
|
@ -92,12 +92,14 @@ private:
|
|||
// nsHttpPipeline <public>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsHttpPipeline::nsHttpPipeline()
|
||||
: mConnection(nsnull)
|
||||
nsHttpPipeline::nsHttpPipeline(PRUint16 maxPipelineDepth)
|
||||
: mMaxPipelineDepth(maxPipelineDepth)
|
||||
, mConnection(nsnull)
|
||||
, mStatus(NS_OK)
|
||||
, mRequestIsPartial(false)
|
||||
, mResponseIsPartial(false)
|
||||
, mClosed(false)
|
||||
, mUtilizedPipeline(false)
|
||||
, mPushBackBuf(nsnull)
|
||||
, mPushBackLen(0)
|
||||
, mPushBackMax(0)
|
||||
|
@ -124,6 +126,9 @@ nsHttpPipeline::AddTransaction(nsAHttpTransaction *trans)
|
|||
{
|
||||
LOG(("nsHttpPipeline::AddTransaction [this=%x trans=%x]\n", this, trans));
|
||||
|
||||
if (mRequestQ.Length() || mResponseQ.Length())
|
||||
mUtilizedPipeline = true;
|
||||
|
||||
NS_ADDREF(trans);
|
||||
mRequestQ.AppendElement(trans);
|
||||
|
||||
|
@ -137,6 +142,27 @@ nsHttpPipeline::AddTransaction(nsAHttpTransaction *trans)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint16
|
||||
nsHttpPipeline::PipelineDepthAvailable()
|
||||
{
|
||||
PRUint16 currentTransactions = mRequestQ.Length() + mResponseQ.Length();
|
||||
|
||||
// Check to see if there are too many transactions currently in use.
|
||||
if (currentTransactions >= mMaxPipelineDepth)
|
||||
return 0;
|
||||
|
||||
// Check to see if this connection is being used by a non-pipelineable
|
||||
// transaction already.
|
||||
nsAHttpTransaction *trans = Request(0);
|
||||
if (!trans)
|
||||
trans = Response(0);
|
||||
if (trans && !(trans->Caps() & NS_HTTP_ALLOW_PIPELINING))
|
||||
return 0;
|
||||
|
||||
// There is still some room available.
|
||||
return mMaxPipelineDepth - currentTransactions;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpPipeline::nsISupports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -164,9 +190,26 @@ nsHttpPipeline::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ASSERTION(mConnection, "no connection");
|
||||
|
||||
nsRefPtr<nsHttpConnectionInfo> ci;
|
||||
GetConnectionInfo(getter_AddRefs(ci));
|
||||
|
||||
NS_ABORT_IF_FALSE(ci, "no connection info");
|
||||
|
||||
bool pipeliningBefore = ci->SupportsPipelining();
|
||||
|
||||
// trans has now received its response headers; forward to the real connection
|
||||
return mConnection->OnHeadersAvailable(trans, requestHead, responseHead, reset);
|
||||
nsresult rv = mConnection->OnHeadersAvailable(trans,
|
||||
requestHead,
|
||||
responseHead,
|
||||
reset);
|
||||
|
||||
if (!pipeliningBefore && ci->SupportsPipelining())
|
||||
// The received headers have expanded the eligible
|
||||
// pipeline depth for this connection
|
||||
gHttpHandler->ConnMgr()->ProcessPipelinePendingQForCI(ci);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -261,7 +304,9 @@ nsHttpPipeline::IsPersistent()
|
|||
bool
|
||||
nsHttpPipeline::IsReused()
|
||||
{
|
||||
return true; // pipelining requires this
|
||||
if (!mUtilizedPipeline && mConnection)
|
||||
return mConnection->IsReused();
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -309,6 +354,13 @@ nsHttpPipeline::PushBack(const char *data, PRUint32 length)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpPipeline::IsProxyConnectInProgress()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mConnection, "no connection");
|
||||
return mConnection->IsProxyConnectInProgress();
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpPipeline::LastTransactionExpectedNoContent()
|
||||
{
|
||||
|
@ -425,8 +477,13 @@ nsHttpPipeline::GetSecurityCallbacks(nsIInterfaceRequestor **result,
|
|||
{
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
// return security callbacks from first request
|
||||
// depending on timing this could be either the request or the response
|
||||
// that is needed - but they both go to the same host. A request for these
|
||||
// callbacks directly in nsHttpTransaction would not make a distinction
|
||||
// over whether the the request had been transmitted yet.
|
||||
nsAHttpTransaction *trans = Request(0);
|
||||
if (!trans)
|
||||
trans = Response(0);
|
||||
if (trans)
|
||||
trans->GetSecurityCallbacks(result, target);
|
||||
else {
|
||||
|
@ -546,6 +603,16 @@ nsHttpPipeline::Status()
|
|||
return mStatus;
|
||||
}
|
||||
|
||||
PRUint8
|
||||
nsHttpPipeline::Caps()
|
||||
{
|
||||
nsAHttpTransaction *trans = Request(0);
|
||||
if (!trans)
|
||||
trans = Response(0);
|
||||
|
||||
return trans ? trans->Caps() : 0;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsHttpPipeline::Available()
|
||||
{
|
||||
|
@ -632,6 +699,17 @@ nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer,
|
|||
nsresult rv;
|
||||
|
||||
trans = Response(0);
|
||||
// This code deals with the establishment of a CONNECT tunnel through
|
||||
// an HTTP proxy. It allows the connection to do the CONNECT/200
|
||||
// HTTP transaction to establish an SSL tunnel as a precursor to the
|
||||
// actual pipeline of regular HTTP transactions.
|
||||
if (!trans && mRequestQ.Length() &&
|
||||
mConnection->IsProxyConnectInProgress()) {
|
||||
LOG(("nsHttpPipeline::WriteSegments [this=%p] Forced Delegation\n",
|
||||
this));
|
||||
trans = Request(0);
|
||||
}
|
||||
|
||||
if (!trans) {
|
||||
if (mRequestQ.Length() > 0)
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
|
@ -701,22 +779,32 @@ nsHttpPipeline::Close(nsresult reason)
|
|||
nsAHttpTransaction *trans;
|
||||
|
||||
// any pending requests can ignore this error and be restarted
|
||||
// unless it is during a CONNECT tunnel request
|
||||
count = mRequestQ.Length();
|
||||
for (i=0; i<count; ++i) {
|
||||
for (i = 0; i < count; ++i) {
|
||||
trans = Request(i);
|
||||
trans->Close(NS_ERROR_NET_RESET);
|
||||
if (mConnection && mConnection->IsProxyConnectInProgress())
|
||||
trans->Close(reason);
|
||||
else
|
||||
trans->Close(NS_ERROR_NET_RESET);
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
mRequestQ.Clear();
|
||||
|
||||
trans = Response(0);
|
||||
if (trans) {
|
||||
// if the current response is partially complete, then it cannot be
|
||||
// restarted and will have to fail with the status of the connection.
|
||||
if (mResponseIsPartial)
|
||||
// The current transaction can be restarted via reset
|
||||
// if the response has not started to arrive and the reason
|
||||
// for failure is innocuous (e.g. not an SSL error)
|
||||
if (!mResponseIsPartial &&
|
||||
(reason == NS_ERROR_NET_RESET ||
|
||||
reason == NS_OK ||
|
||||
reason == NS_BASE_STREAM_CLOSED)) {
|
||||
trans->Close(NS_ERROR_NET_RESET);
|
||||
}
|
||||
else {
|
||||
trans->Close(reason);
|
||||
else
|
||||
trans->Close(NS_ERROR_NET_RESET);
|
||||
}
|
||||
NS_RELEASE(trans);
|
||||
|
||||
// any remaining pending responses can be restarted
|
||||
|
|
|
@ -57,11 +57,9 @@ public:
|
|||
NS_DECL_NSAHTTPTRANSACTION
|
||||
NS_DECL_NSAHTTPSEGMENTREADER
|
||||
|
||||
nsHttpPipeline();
|
||||
nsHttpPipeline(PRUint16 maxPipelineDepth);
|
||||
virtual ~nsHttpPipeline();
|
||||
|
||||
nsresult AddTransaction(nsAHttpTransaction *);
|
||||
|
||||
private:
|
||||
nsresult FillSendBuf();
|
||||
|
||||
|
@ -84,6 +82,7 @@ private:
|
|||
return mResponseQ[i];
|
||||
}
|
||||
|
||||
PRUint16 mMaxPipelineDepth;
|
||||
nsAHttpConnection *mConnection;
|
||||
nsTArray<nsAHttpTransaction*> mRequestQ; // array of transactions
|
||||
nsTArray<nsAHttpTransaction*> mResponseQ; // array of transactions
|
||||
|
@ -99,6 +98,10 @@ private:
|
|||
// indicates whether or not the pipeline has been explicitly closed.
|
||||
bool mClosed;
|
||||
|
||||
// indicates whether or not a true pipeline (more than 1 request without
|
||||
// a synchronous response) has been formed.
|
||||
bool mUtilizedPipeline;
|
||||
|
||||
// used when calling ReadSegments/WriteSegments on a transaction.
|
||||
nsAHttpSegmentReader *mReader;
|
||||
nsAHttpSegmentWriter *mWriter;
|
||||
|
|
|
@ -456,6 +456,12 @@ nsHttpTransaction::Status()
|
|||
return mStatus;
|
||||
}
|
||||
|
||||
PRUint8
|
||||
nsHttpTransaction::Caps()
|
||||
{
|
||||
return mCaps;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsHttpTransaction::Available()
|
||||
{
|
||||
|
@ -704,6 +710,18 @@ nsHttpTransaction::Close(nsresult reason)
|
|||
mPipeOut->CloseWithStatus(reason);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpTransaction::AddTransaction(nsAHttpTransaction *trans)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
PRUint16
|
||||
nsHttpTransaction::PipelineDepthAvailable()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpTransaction <private>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -113,7 +113,6 @@ public:
|
|||
nsIAsyncInputStream **responseBody);
|
||||
|
||||
// attributes
|
||||
PRUint8 Caps() { return mCaps; }
|
||||
nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; }
|
||||
nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nsnull; }
|
||||
nsISupports *SecurityInfo() { return mSecurityInfo; }
|
||||
|
|
Загрузка…
Ссылка в новой задаче