bug 528288 spdy - only coalesce (i.e. ip pool) hostnames with compatible ssl certs sr=biesi r=honzab r=bsmith

patch 9
This commit is contained in:
Patrick McManus 2011-12-02 10:28:57 -05:00
parent d7a9653123
commit 7b7e03e318
4 changed files with 112 additions and 19 deletions

View File

@ -51,6 +51,9 @@
#include "nsIDNSService.h"
#include "nsICancelable.h"
#include "nsISSLStatusProvider.h"
#include "nsISSLStatus.h"
using namespace mozilla;
// defined by the socket transport service while active
@ -447,15 +450,22 @@ nsHttpConnectionMgr::ReportSpdyConnection(nsHttpConnection *conn,
PRUint64 timeOfExpire = NowInSeconds() + ttl;
if (!mTimer || timeOfExpire < mTimeOfNextWakeUp)
PruneDeadConnectionsAfter(ttl);
nsConnectionEntry *preferred = GetSpdyPreferred(ent->mDottedDecimalAddress);
// Lookup preferred directly from the hash instead of using
// GetSpdyPreferred() because we want to avoid the cert compatibility
// check at this point because the cert is never part of the hash
// lookup. Filtering on that has to be done at the time of use
// rather than the time of registration (i.e. now).
nsConnectionEntry *preferred =
mSpdyPreferredHash.Get(ent->mDottedDecimalAddress);
LOG(("ReportSpdyConnection %s %s ent=%p ispreferred=%d\n",
ent->mConnInfo->Host(), ent->mDottedDecimalAddress.get(),
ent, preferred));
if (!preferred) {
ent->mSpdyPreferred = true;
SetSpdyPreferred(ent->mDottedDecimalAddress, ent);
SetSpdyPreferred(ent);
ent->mSpdyRedir = false;
}
else if (preferred != ent) {
@ -464,6 +474,36 @@ nsHttpConnectionMgr::ReportSpdyConnection(nsHttpConnection *conn,
ent->mSpdyRedir = true;
conn->DontReuse();
}
// If this is a preferred host for coalescing (aka ip pooling) then
// keep a reference to the server SSL cert. This will be used as an
// extra level of verification when deciding that
// connections from other hostnames are redirected to the preferred host.
//
// Even if mCert is already set update the reference in case the
// reference is changing.
ent->mCert = nsnull;
nsCOMPtr<nsISupports> securityInfo;
nsCOMPtr<nsISSLStatusProvider> sslStatusProvider;
nsCOMPtr<nsISSLStatus> sslStatus;
nsCOMPtr<nsIX509Cert> cert;
conn->GetSecurityInfo(getter_AddRefs(securityInfo));
if (securityInfo)
sslStatusProvider = do_QueryInterface(securityInfo);
if (sslStatusProvider)
sslStatusProvider->
GetSSLStatus(getter_AddRefs(sslStatus));
if (sslStatus)
sslStatus->GetServerCert(getter_AddRefs(cert));
if (cert)
ent->mCert = do_QueryInterface(cert);
ProcessSpdyPendingQ();
}
@ -534,27 +574,52 @@ nsHttpConnectionMgr::TrimAlternateProtocolHash(PLDHashTable *table,
}
nsHttpConnectionMgr::nsConnectionEntry *
nsHttpConnectionMgr::GetSpdyPreferred(nsACString &aDottedDecimal)
nsHttpConnectionMgr::GetSpdyPreferred(nsConnectionEntry *aOriginalEntry)
{
if (!gHttpHandler->IsSpdyEnabled() ||
!gHttpHandler->CoalesceSpdy() ||
aDottedDecimal.IsEmpty())
aOriginalEntry->mDottedDecimalAddress.IsEmpty())
return nsnull;
return mSpdyPreferredHash.Get(aDottedDecimal);
nsConnectionEntry *preferred =
mSpdyPreferredHash.Get(aOriginalEntry->mDottedDecimalAddress);
if (preferred == aOriginalEntry)
return aOriginalEntry; /* no redirection so no cert check required */
if (!preferred || !preferred->mCert)
return nsnull; /* no ip pooling */
nsresult rv;
bool validCert = false;
rv = preferred->mCert->IsValidForHostname(
aOriginalEntry->mConnInfo->GetHost(), &validCert);
if (NS_FAILED(rv) || !validCert) {
LOG(("nsHttpConnectionMgr::GetSpdyPreferredConnection "
"Host %s has cert which cannot be confirmed to use "
"with %s connections",
preferred->mConnInfo->Host(), aOriginalEntry->mConnInfo->Host()));
return nsnull; /* no ip pooling */
}
LOG(("nsHttpConnectionMgr::GetSpdyPreferredConnection "
"Host %s has cert valid for %s connections",
preferred->mConnInfo->Host(), aOriginalEntry->mConnInfo->Host()));
return preferred;
}
void
nsHttpConnectionMgr::SetSpdyPreferred(nsACString &aDottedDecimal,
nsConnectionEntry *ent)
nsHttpConnectionMgr::SetSpdyPreferred(nsConnectionEntry *ent)
{
if (!gHttpHandler->CoalesceSpdy())
return;
if (aDottedDecimal.IsEmpty())
if (ent->mDottedDecimalAddress.IsEmpty())
return;
mSpdyPreferredHash.Put(aDottedDecimal, ent);
mSpdyPreferredHash.Put(ent->mDottedDecimalAddress, ent);
}
void
@ -982,8 +1047,7 @@ nsHttpConnectionMgr::GetConnection(nsConnectionEntry *ent,
ent->mConnInfo->UsingSSL() &&
!ent->mConnInfo->UsingHttpProxy())
{
nsConnectionEntry *preferred =
GetSpdyPreferred(ent->mDottedDecimalAddress);
nsConnectionEntry *preferred = GetSpdyPreferred(ent);
if (preferred)
ent = preferred;
@ -1200,8 +1264,7 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
// SPDY coalescing of hostnames means we might redirect from this
// connection entry onto the preferred one.
nsConnectionEntry *preferredEntry =
GetSpdyPreferred(ent->mDottedDecimalAddress);
nsConnectionEntry *preferredEntry = GetSpdyPreferred(ent);
if (preferredEntry) {
LOG(("nsHttpConnectionMgr::ProcessNewTransaction trans=%p "
"redirected via coalescing from %s to %s\n", trans,
@ -1294,7 +1357,7 @@ nsHttpConnectionMgr::GetSpdyPreferredConn(nsConnectionEntry *ent)
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
NS_ABORT_IF_FALSE(ent, "no connection entry");
nsConnectionEntry *preferred = GetSpdyPreferred(ent->mDottedDecimalAddress);
nsConnectionEntry *preferred = GetSpdyPreferred(ent);
// this entry is spdy-enabled if it is a redirect to another spdy host
if (preferred && preferred != ent) {

View File

@ -54,6 +54,7 @@
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsIX509Cert3.h"
class nsHttpPipeline;
@ -205,6 +206,7 @@ private:
bool mSpdyRedir;
bool mDidDNS;
bool mSpdyPreferred;
nsCOMPtr<nsIX509Cert3> mCert;
};
// nsConnectionHandle
@ -321,9 +323,8 @@ private:
void RecvdConnect();
// Manage the preferred spdy connection entry for this address
nsConnectionEntry *GetSpdyPreferred(nsACString &aDottedDecimal);
void SetSpdyPreferred(nsACString &aDottedDecimal,
nsConnectionEntry *ent);
nsConnectionEntry *GetSpdyPreferred(nsConnectionEntry *aOriginalEntry);
void SetSpdyPreferred(nsConnectionEntry *ent);
void RemoveSpdyPreferred(nsACString &aDottedDecimal);
nsHttpConnection *GetSpdyPreferredConn(nsConnectionEntry *ent);
nsDataHashtable<nsCStringHashKey, nsConnectionEntry *> mSpdyPreferredHash;

View File

@ -43,7 +43,7 @@ interface nsICertVerificationListener;
/**
* Extending nsIX509Cert
*/
[scriptable, uuid(399004d8-b8c7-4eb9-8362-d99f4c0161fd)]
[scriptable, uuid(09143cd9-dee3-4870-8450-8440c87e40e2)]
interface nsIX509Cert3 : nsIX509Cert2 {
/**
@ -88,6 +88,15 @@ interface nsIX509Cert3 : nsIX509Cert2 {
void getAllTokenNames(out unsigned long length,
[retval, array, size_is(length)] out wstring
tokenNames);
/**
* Determine if the certificate can be verified for specific host name
*
* @param aHostName the hostname to be verified
* @return a boolean successful verification
*/
bool isValidForHostname(in AUTF8String aHostName);
};
[scriptable, uuid(2fd0a785-9f2d-4327-8871-8c3e0783891d)]

View File

@ -938,6 +938,26 @@ nsNSSCertificate::GetAllTokenNames(PRUint32 *aLength, PRUnichar*** aTokenNames)
return NS_OK;
}
NS_IMETHODIMP
nsNSSCertificate::IsValidForHostname(const nsACString & aHostName,
bool *retval)
{
*retval = false;
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown())
return NS_ERROR_NOT_AVAILABLE;
if (!mCert)
return NS_OK;
if (CERT_VerifyCertName(mCert,
PromiseFlatCString(aHostName).get()) == SECSuccess)
*retval = true;
return NS_OK;
}
NS_IMETHODIMP
nsNSSCertificate::GetSubjectName(nsAString &_subjectName)
{