bug 447866 pre patch 0 - pipeline and spdy mix r=honzab

This commit is contained in:
Patrick McManus 2012-02-15 16:41:18 -05:00
parent 2fed82f6c6
commit ea7056c261
6 changed files with 176 additions and 20 deletions

View File

@ -1949,6 +1949,40 @@ SpdySession::Http1xTransactionCount()
return 0;
}
// used as an enumerator by TakeSubTransactions()
static PLDHashOperator
TakeStream(nsAHttpTransaction *key,
nsAutoPtr<SpdyStream> &stream,
void *closure)
{
nsTArray<nsRefPtr<nsAHttpTransaction> > *list =
static_cast<nsTArray<nsRefPtr<nsAHttpTransaction> > *>(closure);
list->AppendElement(key);
// removing the stream from the hash will delete the stream
// and drop the transaction reference the hash held
return PL_DHASH_REMOVE;
}
nsresult
SpdySession::TakeSubTransactions(
nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions)
{
// Generally this cannot be done with spdy as transactions are
// started right away.
LOG3(("SpdySession::TakeSubTransactions %p\n", this));
if (mConcurrentHighWater > 0)
return NS_ERROR_ALREADY_OPENED;
LOG3((" taking %d\n", mStreamTransactionHash.Count()));
mStreamTransactionHash.Enumerate(TakeStream, &outTransactions);
return NS_OK;
}
//-----------------------------------------------------------------------------
// Pass through methods of nsAHttpConnection
//-----------------------------------------------------------------------------

View File

@ -39,6 +39,7 @@
#define nsAHttpTransaction_h__
#include "nsISupports.h"
#include "nsTArray.h"
class nsAHttpConnection;
class nsAHttpSegmentReader;
@ -101,6 +102,18 @@ public:
// abstract object. Pipelines may have multiple, SPDY has 0,
// normal http transactions have 1.
virtual PRUint32 Http1xTransactionCount() = 0;
// called to remove the unused sub transactions from an object that can
// handle multiple transactions simultaneously (i.e. pipelines or spdy).
//
// Returns NS_ERROR_NOT_IMPLEMENTED if the object does not implement
// sub-transactions.
//
// Returns NS_ERROR_ALREADY_OPENED if the subtransactions have been
// at least partially written and cannot be moved.
//
virtual nsresult TakeSubTransactions(
nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions) = 0;
};
#define NS_DECL_NSAHTTPTRANSACTION \
@ -118,7 +131,8 @@ public:
void Close(nsresult reason); \
void SetSSLConnectFailed(); \
nsHttpRequestHead *RequestHead(); \
PRUint32 Http1xTransactionCount();
PRUint32 Http1xTransactionCount(); \
nsresult TakeSubTransactions(nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions);
//-----------------------------------------------------------------------------
// nsAHttpSegmentReader

View File

@ -170,6 +170,93 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info,
return NS_OK;
}
void
nsHttpConnection::StartSpdy()
{
LOG(("nsHttpConnection::StartSpdy [this=%p]\n", this));
NS_ABORT_IF_FALSE(!mSpdySession, "mSpdySession should be null");
mUsingSpdy = true;
mEverUsedSpdy = true;
// Setting the connection as reused allows some transactions that fail
// with NS_ERROR_NET_RESET to be restarted and SPDY uses that code
// to handle clean rejections (such as those that arrived after
// a server goaway was generated).
mIsReused = true;
// If mTransaction is a pipeline object it might represent
// several requests. If so, we need to unpack that and
// pack them all into a new spdy session.
nsTArray<nsRefPtr<nsAHttpTransaction> > list;
nsresult rv = mTransaction->TakeSubTransactions(list);
if (rv == NS_ERROR_ALREADY_OPENED) {
// Has the interface for TakeSubTransactions() changed?
LOG(("TakeSubTranscations somehow called after "
"nsAHttpTransaction began processing\n"));
NS_ABORT_IF_FALSE(false,
"TakeSubTranscations somehow called after "
"nsAHttpTransaction began processing");
mTransaction->Close(NS_ERROR_ABORT);
return;
}
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
// Has the interface for TakeSubTransactions() changed?
LOG(("unexpected rv from nnsAHttpTransaction::TakeSubTransactions()"));
NS_ABORT_IF_FALSE(false,
"unexpected result from "
"nsAHttpTransaction::TakeSubTransactions()");
mTransaction->Close(NS_ERROR_ABORT);
return;
}
if (NS_FAILED(rv)) { // includes NS_ERROR_NOT_IMPLEMENTED
NS_ABORT_IF_FALSE(list.IsEmpty(), "sub transaction list not empty");
// This is ok - treat mTransaction as a single real request.
// Wrap the old http transaction into the new spdy session
// as the first stream.
mSpdySession = new SpdySession(mTransaction,
mSocketTransport,
mPriority);
LOG(("nsHttpConnection::StartSpdy moves single transaction %p "
"into SpdySession %p\n", mTransaction.get(), mSpdySession.get()));
}
else {
NS_ABORT_IF_FALSE(!list.IsEmpty(), "sub transaction list empty");
PRInt32 count = list.Length();
LOG(("nsHttpConnection::StartSpdy moving transaction list len=%d "
"into SpdySession %p\n", count, mSpdySession.get()));
for (PRInt32 index = 0; index < count; ++index) {
if (!mSpdySession) {
mSpdySession = new SpdySession(list[index],
mSocketTransport,
mPriority);
}
else {
// AddStream() cannot fail
if (!mSpdySession->AddStream(list[index], mPriority)) {
NS_ABORT_IF_FALSE(false, "SpdySession::AddStream failed");
LOG(("SpdySession::AddStream failed\n"));
mTransaction->Close(NS_ERROR_ABORT);
return;
}
}
}
}
mSupportsPipelining = false; // dont use http/1 pipelines with spdy
mTransaction = mSpdySession;
mIdleTimeout = gHttpHandler->SpdyTimeout();
}
bool
nsHttpConnection::EnsureNPNComplete()
{
@ -215,31 +302,15 @@ nsHttpConnection::EnsureNPNComplete()
goto npnComplete;
return false;
}
if (NS_FAILED(rv))
goto npnComplete;
LOG(("nsHttpConnection::EnsureNPNComplete %p negotiated to '%s'",
this, negotiatedNPN.get()));
if (negotiatedNPN.Equals(NS_LITERAL_CSTRING("spdy/2"))) {
mUsingSpdy = true;
mEverUsedSpdy = true;
// Setting the connection as reused allows some transactions that fail
// with NS_ERROR_NET_RESET to be restarted and SPDY uses that code
// to handle clean rejections (such as those that arrived after
// a server goaway was generated).
mIsReused = true;
// Wrap the old http transaction into the new spdy session
// as the first stream
mSpdySession = new SpdySession(mTransaction,
mSocketTransport,
mPriority);
mTransaction = mSpdySession;
mIdleTimeout = gHttpHandler->SpdyTimeout();
}
if (negotiatedNPN.Equals(NS_LITERAL_CSTRING("spdy/2")))
StartSpdy();
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SPDY_NPN_CONNECT,
mUsingSpdy);

View File

@ -180,6 +180,9 @@ private:
// redirections
void HandleAlternateProtocol(nsHttpResponseHead *);
// Start the Spdy transaction handler when NPN indicates spdy/2
void StartSpdy();
// Directly Add a transaction to an active connection for SPDY
nsresult AddTransaction(nsAHttpTransaction *, PRInt32);

View File

@ -364,6 +364,33 @@ nsHttpPipeline::Http1xTransactionCount()
return mHttp1xTransactionCount;
}
nsresult
nsHttpPipeline::TakeSubTransactions(
nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions)
{
LOG(("nsHttpPipeline::TakeSubTransactions [this=%p]\n", this));
if (mResponseQ.Length() || mRequestIsPartial)
return NS_ERROR_ALREADY_OPENED;
// request queue could be empty if it was already canceled, in which
// case it is safe to treat this as a case without any
// sub-transactions.
if (!mRequestQ.Length())
return NS_ERROR_NOT_IMPLEMENTED;
PRInt32 i, count = mRequestQ.Length();
for (i = 0; i < count; ++i) {
nsAHttpTransaction *trans = Request(i);
outTransactions.AppendElement(trans);
NS_RELEASE(trans);
}
mRequestQ.Clear();
LOG((" took %d\n", count));
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsHttpPipeline::nsAHttpConnection
//-----------------------------------------------------------------------------

View File

@ -341,6 +341,13 @@ nsHttpTransaction::Http1xTransactionCount()
return 1;
}
nsresult
nsHttpTransaction::TakeSubTransactions(
nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//----------------------------------------------------------------------------
// nsHttpTransaction::nsAHttpTransaction
//----------------------------------------------------------------------------