bug 528288 - HTTP Alternate-Protocol header for transitioning from http to spdy r=honzab

patch 2
This commit is contained in:
Patrick McManus 2011-12-02 10:28:57 -05:00
parent 795431c27d
commit 3e4edc0d65
6 changed files with 132 additions and 0 deletions

View File

@ -56,6 +56,7 @@ HTTP_ATOM(Accept_Language, "Accept-Language")
HTTP_ATOM(Accept_Ranges, "Accept-Ranges")
HTTP_ATOM(Age, "Age")
HTTP_ATOM(Allow, "Allow")
HTTP_ATOM(Alternate_Protocol, "Alternate-Protocol")
HTTP_ATOM(Authentication, "Authentication")
HTTP_ATOM(Authorization, "Authorization")
HTTP_ATOM(Cache_Control, "Cache-Control")

View File

@ -209,6 +209,18 @@ nsHttpChannel::Connect(bool firstTime)
LOG(("nsHttpChannel::Connect() STS permissions found\n"));
return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
}
// Check for a previous SPDY Alternate-Protocol directive
if (gHttpHandler->IsSpdyEnabled()) {
nsCAutoString hostPort;
if (NS_SUCCEEDED(mURI->GetHostPort(hostPort)) &&
gHttpHandler->ConnMgr()->GetSpdyAlternateProtocol(hostPort)) {
LOG(("nsHttpChannel::Connect() Alternate-Protocol found\n"));
return AsyncCall(
&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
}
}
}
// ensure that we are using a valid hostname
@ -4091,6 +4103,16 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
mSecurityInfo = mTransaction->SecurityInfo();
}
if (gHttpHandler->IsSpdyEnabled() && !mCachePump && NS_FAILED(mStatus) &&
(mLoadFlags & LOAD_REPLACE) && mOriginalURI) {
// For sanity's sake we may want to cancel an alternate protocol
// redirection involving the original host name
nsCAutoString hostPort;
if (NS_SUCCEEDED(mOriginalURI->GetHostPort(hostPort)))
gHttpHandler->ConnMgr()->RemoveSpdyAlternateProtocol(hostPort);
}
// don't enter this block if we're reading from the cache...
if (NS_SUCCEEDED(mStatus) && !mCachePump && mTransaction) {
// mTransactionPump doesn't hit OnInputStreamReady and call this until

View File

@ -320,6 +320,32 @@ nsHttpConnection::SetupNPN(PRUint8 caps)
}
}
void
nsHttpConnection::HandleAlternateProtocol(nsHttpResponseHead *responseHead)
{
// Look for the Alternate-Protocol header. Alternate-Protocol is
// essentially a way to rediect future transactions from http to
// spdy.
//
if (!gHttpHandler->IsSpdyEnabled() || mUsingSpdy)
return;
const char *val = responseHead->PeekHeader(nsHttp::Alternate_Protocol);
if (!val)
return;
// The spec allows redirections to any port, but due to concerns over
// silently redirecting to stealth ports we only allow port 443
//
// Alternate-Protocol: 5678:somethingelse, 443:npn-spdy/2
if (nsHttp::FindToken(val, "443:npn-spdy/2", HTTP_HEADER_VALUE_SEPS)) {
LOG(("Connection %p Transaction %p found Alternate-Protocol "
"header %s", this, mTransaction.get(), val));
gHttpHandler->ConnMgr()->ReportSpdyAlternateProtocol(this);
}
}
nsresult
nsHttpConnection::AddTransaction(nsAHttpTransaction *httpTransaction,
@ -615,6 +641,9 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
LOG(("Connection can be reused [this=%x idle-timeout=%u]\n", this, mIdleTimeout));
}
if (!mProxyConnectStream)
HandleAlternateProtocol(responseHead);
// if we're doing an SSL proxy connect, then we need to check whether or not
// the connect was successful. if so, then we have to reset the transaction
// and step-up the socket connection to SSL. finally, we have to wake up the

View File

@ -176,6 +176,10 @@ private:
bool EnsureNPNComplete();
void SetupNPN(PRUint8 caps);
// Inform the connection manager of any SPDY Alternate-Protocol
// redirections
void HandleAlternateProtocol(nsHttpResponseHead *);
// Directly Add a transaction to an active connection for SPDY
nsresult AddTransaction(nsAHttpTransaction *, PRInt32);

View File

@ -97,6 +97,7 @@ nsHttpConnectionMgr::nsHttpConnectionMgr()
{
LOG(("Creating nsHttpConnectionMgr @%x\n", this));
mCT.Init();
mAlternateProtocolHash.Init(16);
}
nsHttpConnectionMgr::~nsHttpConnectionMgr()
@ -466,6 +467,68 @@ nsHttpConnectionMgr::ReportSpdyConnection(nsHttpConnection *conn,
ProcessSpdyPendingQ();
}
bool
nsHttpConnectionMgr::GetSpdyAlternateProtocol(nsACString &hostPortKey)
{
// The Alternate Protocol hash is protected under the monitor because
// it is read from both the main and the network thread.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mAlternateProtocolHash.Contains(hostPortKey);
}
void
nsHttpConnectionMgr::ReportSpdyAlternateProtocol(nsHttpConnection *conn)
{
// For now lets not bypass proxies due to the alternate-protocol header
if (conn->ConnectionInfo()->UsingHttpProxy())
return;
nsCString hostPortKey(conn->ConnectionInfo()->Host());
if (conn->ConnectionInfo()->Port() != 80) {
hostPortKey.Append(NS_LITERAL_CSTRING(":"));
hostPortKey.AppendInt(conn->ConnectionInfo()->Port());
}
// The Alternate Protocol hash is protected under the monitor because
// it is read from both the main and the network thread.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
// Check to see if this is already present
if (mAlternateProtocolHash.Contains(hostPortKey))
return;
if (mAlternateProtocolHash.mHashTable.entryCount > 2000)
PL_DHashTableEnumerate(&mAlternateProtocolHash.mHashTable,
&nsHttpConnectionMgr::TrimAlternateProtocolHash,
this);
mAlternateProtocolHash.Put(hostPortKey);
}
void
nsHttpConnectionMgr::RemoveSpdyAlternateProtocol(nsACString &hostPortKey)
{
// The Alternate Protocol hash is protected under the monitor because
// it is read from both the main and the network thread.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mAlternateProtocolHash.Remove(hostPortKey);
}
PLDHashOperator
nsHttpConnectionMgr::TrimAlternateProtocolHash(PLDHashTable *table,
PLDHashEntryHdr *hdr,
PRUint32 number,
void *closure)
{
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
if (self->mAlternateProtocolHash.mHashTable.entryCount > 2000)
return PL_DHASH_REMOVE;
return PL_DHASH_STOP;
}
nsHttpConnectionMgr::nsConnectionEntry *
nsHttpConnectionMgr::GetSpdyPreferred(nsACString &aDottedDecimal)
{

View File

@ -50,6 +50,7 @@
#include "mozilla/ReentrantMonitor.h"
#include "nsISocketTransportService.h"
#include "nsIDNSListener.h"
#include "nsHashSets.h"
#include "nsIObserver.h"
#include "nsITimer.h"
@ -133,6 +134,11 @@ public:
// been initialized.
nsresult UpdateParam(nsParamName name, PRUint16 value);
// Lookup/Cancel HTTP->SPDY redirections
bool GetSpdyAlternateProtocol(nsACString &key);
void ReportSpdyAlternateProtocol(nsHttpConnection *);
void RemoveSpdyAlternateProtocol(nsACString &key);
//-------------------------------------------------------------------------
// NOTE: functions below may be called only on the socket thread.
//-------------------------------------------------------------------------
@ -405,6 +411,13 @@ private:
// nsConnectionEntry object.
//
nsClassHashtable<nsCStringHashKey, nsConnectionEntry> mCT;
// this table is protected by the monitor
nsCStringHashSet mAlternateProtocolHash;
static PLDHashOperator TrimAlternateProtocolHash(PLDHashTable *table,
PLDHashEntryHdr *hdr,
PRUint32 number,
void *closure);
};
#endif // !nsHttpConnectionMgr_h__