bug 528288 - disallow spdy from http created in nsNSSCallbacks to avoid OSCP/CRL loops with alternate-protocol sr=biesi r=honzab
authorPatrick McManus <mcmanus@ducksong.com>
Fri, 02 Dec 2011 10:28:57 -0500
changeset 81190 2cb0358aa68b1ad502a6f6c4efe88fe9308259ae
parent 81189 9aed66c3a561683acbe305a6cb0e8d74fb5fa24e
child 81191 86e3d2e80614aace6d638b7da82bf777e7a803ac
push id21564
push usermak77@bonardo.net
push dateSat, 03 Dec 2011 11:10:17 +0000
treeherdermozilla-central@a68c96c1d8e0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbiesi, honzab
bugs528288
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 528288 - disallow spdy from http created in nsNSSCallbacks to avoid OSCP/CRL loops with alternate-protocol sr=biesi r=honzab patch 15
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsIHttpChannelInternal.idl
security/manager/ssl/src/nsNSSCallbacks.cpp
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -75,16 +75,17 @@ HttpBaseChannel::HttpBaseChannel()
   , mForceAllowThirdPartyCookie(false)
   , mUploadStreamHasHeaders(false)
   , mInheritApplicationCache(true)
   , mChooseApplicationCache(false)
   , mLoadedFromApplicationCache(false)
   , mChannelIsForDownload(false)
   , mTracingEnabled(true)
   , mTimingEnabled(false)
+  , mAllowSpdy(true)
   , mSuspendCount(0)
   , mRedirectedCachekeys(nsnull)
 {
   LOG(("Creating HttpBaseChannel @%x\n", this));
 
   // grab a reference to the handler to ensure that it doesn't go away.
   NS_ADDREF(gHttpHandler);
 
@@ -1305,16 +1306,32 @@ HttpBaseChannel::HTTPUpgrade(const nsACS
     NS_ENSURE_ARG(!aProtocolName.IsEmpty());
     NS_ENSURE_ARG_POINTER(aListener);
     
     mUpgradeProtocol = aProtocolName;
     mUpgradeProtocolCallback = aListener;
     return NS_OK;
 }
 
+NS_IMETHODIMP
+HttpBaseChannel::GetAllowSpdy(bool *aAllowSpdy)
+{
+  NS_ENSURE_ARG_POINTER(aAllowSpdy);
+
+  *aAllowSpdy = mAllowSpdy;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy)
+{
+  mAllowSpdy = aAllowSpdy;
+  return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 // HttpBaseChannel::nsISupportsPriority
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpBaseChannel::GetPriority(PRInt32 *value)
 {
   *value = mPriority;
@@ -1614,16 +1631,18 @@ HttpBaseChannel::SetupReplacementChannel
   httpChannel->SetAllowPipelining(mAllowPipelining);
   // convey the new redirection limit
   httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
 
   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
   if (httpInternal) {
     // convey the mForceAllowThirdPartyCookie flag
     httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie);
+    // convey the spdy flag
+    httpInternal->SetAllowSpdy(mAllowSpdy);
 
     // update the DocumentURI indicator since we are being redirected.
     // if this was a top-level document channel, then the new channel
     // should have its mDocumentURI point to newURI; otherwise, we
     // just need to pass along our mDocumentURI to the new channel.
     if (newURI && (mURI == mDocumentURI))
       httpInternal->SetDocumentURI(newURI);
     else
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -162,16 +162,19 @@ public:
   NS_IMETHOD GetCanceled(bool *aCanceled);
   NS_IMETHOD GetChannelIsForDownload(bool *aChannelIsForDownload);
   NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload);
   NS_IMETHOD SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys);
   NS_IMETHOD GetLocalAddress(nsACString& addr);
   NS_IMETHOD GetLocalPort(PRInt32* port);
   NS_IMETHOD GetRemoteAddress(nsACString& addr);
   NS_IMETHOD GetRemotePort(PRInt32* port);
+  NS_IMETHOD GetAllowSpdy(bool *aAllowSpdy);
+  NS_IMETHOD SetAllowSpdy(bool aAllowSpdy);
+  
   inline void CleanRedirectCacheChainIfNecessary()
   {
       if (mRedirectedCachekeys) {
           delete mRedirectedCachekeys;
           mRedirectedCachekeys = nsnull;
       }
   }
   NS_IMETHOD HTTPUpgrade(const nsACString & aProtocolName,
@@ -290,16 +293,17 @@ protected:
   PRUint32                          mUploadStreamHasHeaders     : 1;
   PRUint32                          mInheritApplicationCache    : 1;
   PRUint32                          mChooseApplicationCache     : 1;
   PRUint32                          mLoadedFromApplicationCache : 1;
   PRUint32                          mChannelIsForDownload       : 1;
   PRUint32                          mTracingEnabled             : 1;
   // True if timing collection is enabled
   PRUint32                          mTimingEnabled              : 1;
+  PRUint32                          mAllowSpdy                  : 1;
 
   // Current suspension depth for this channel object
   PRUint32                          mSuspendCount;
 
   nsTArray<nsCString>              *mRedirectedCachekeys;
 };
 
 // Share some code while working around C++'s absurd inability to handle casting
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1074,17 +1074,17 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
 
   SendAsyncOpen(IPC::URI(mURI), IPC::URI(mOriginalURI),
                 IPC::URI(mDocumentURI), IPC::URI(mReferrer), mLoadFlags,
                 mRequestHeaders, mRequestHead.Method(),
                 IPC::InputStream(mUploadStream), mUploadStreamHasHeaders,
                 mPriority, mRedirectionLimit, mAllowPipelining,
                 mForceAllowThirdPartyCookie, mSendResumeAt,
                 mStartPos, mEntityID, mChooseApplicationCache, 
-                appCacheClientId);
+                appCacheClientId, mAllowSpdy);
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIHttpChannel
 //-----------------------------------------------------------------------------
 
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -138,17 +138,18 @@ HttpChannelParent::RecvAsyncOpen(const I
                                  const PRUint16&            priority,
                                  const PRUint8&             redirectionLimit,
                                  const bool&              allowPipelining,
                                  const bool&              forceAllowThirdPartyCookie,
                                  const bool&                doResumeAt,
                                  const PRUint64&            startPos,
                                  const nsCString&           entityID,
                                  const bool&                chooseApplicationCache,
-                                 const nsCString&           appCacheClientID)
+                                 const nsCString&           appCacheClientID,
+                                 const bool&                allowSpdy)
 {
   nsCOMPtr<nsIURI> uri(aURI);
   nsCOMPtr<nsIURI> originalUri(aOriginalURI);
   nsCOMPtr<nsIURI> docUri(aDocURI);
   nsCOMPtr<nsIURI> referrerUri(aReferrerURI);
 
   nsCString uriSpec;
   uri->GetSpec(uriSpec);
@@ -198,16 +199,17 @@ HttpChannelParent::RecvAsyncOpen(const I
     httpChan->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
   }
 
   if (priority != nsISupportsPriority::PRIORITY_NORMAL)
     httpChan->SetPriority(priority);
   httpChan->SetRedirectionLimit(redirectionLimit);
   httpChan->SetAllowPipelining(allowPipelining);
   httpChan->SetForceAllowThirdPartyCookie(forceAllowThirdPartyCookie);
+  httpChan->SetAllowSpdy(allowSpdy);
 
   nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
     do_QueryInterface(mChannel);
   nsCOMPtr<nsIApplicationCacheService> appCacheService =
     do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID);
 
   bool setChooseApplicationCache = chooseApplicationCache;
   if (appCacheChan && appCacheService) {
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -92,17 +92,18 @@ protected:
                              const PRUint16&            priority,
                              const PRUint8&             redirectionLimit,
                              const bool&              allowPipelining,
                              const bool&              forceAllowThirdPartyCookie,
                              const bool&                doResumeAt,
                              const PRUint64&            startPos,
                              const nsCString&           entityID,
                              const bool&                chooseApplicationCache,
-                             const nsCString&           appCacheClientID);
+                             const nsCString&           appCacheClientID,
+                             const bool&                allowSpdy);
 
   virtual bool RecvConnectChannel(const PRUint32& channelId);
   virtual bool RecvSetPriority(const PRUint16& priority);
   virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset);
   virtual bool RecvSuspend();
   virtual bool RecvResume();
   virtual bool RecvCancel(const nsresult& status);
   virtual bool RecvRedirect2Verify(const nsresult& result,
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -76,17 +76,18 @@ parent:
             PRUint16            priority,
             PRUint8             redirectionLimit,
             bool                allowPipelining,
             bool                forceAllowThirdPartyCookie,
             bool                resumeAt,
             PRUint64            startPos,
             nsCString           entityID,
             bool                chooseApplicationCache,
-            nsCString           appCacheClientID);
+            nsCString           appCacheClientID,
+            bool                allowSpdy);
 
   // Used to connect redirected-to channel on the parent with redirected-to
   // channel on the child.
   ConnectChannel(PRUint32 channelId);
 
   SetPriority(PRUint16 priority);
 
   SetCacheTokenCachedCharset(nsCString charset);
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -206,17 +206,17 @@ nsHttpChannel::Connect(bool firstTime)
                      "Something is wrong with STS: IsStsURI failed.");
 
         if (NS_SUCCEEDED(rv) && isStsHost) {
             LOG(("nsHttpChannel::Connect() STS permissions found\n"));
             return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
         }
 
         // Check for a previous SPDY Alternate-Protocol directive
-        if (gHttpHandler->IsSpdyEnabled()) {
+        if (gHttpHandler->IsSpdyEnabled() && mAllowSpdy) {
             nsCAutoString hostPort;
 
             if (NS_SUCCEEDED(mURI->GetHostPort(hostPort)) &&
                 gHttpHandler->ConnMgr()->GetSpdyAlternateProtocol(hostPort)) {
                 LOG(("nsHttpChannel::Connect() Alternate-Protocol found\n"));
                 return AsyncCall(
                     &nsHttpChannel::HandleAsyncRedirectChannelToHttps);
             }
@@ -514,16 +514,19 @@ nsHttpChannel::SetupTransaction()
               mRequestHead.Method() == nsHttp::Head ||
               mRequestHead.Method() == nsHttp::Propfind ||
               mRequestHead.Method() == nsHttp::Proppatch)) {
             LOG(("  pipelining disallowed\n"));
             mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
         }
     }
 
+    if (!mAllowSpdy)
+        mCaps |= NS_HTTP_DISALLOW_SPDY;
+
     // use the URI path if not proxying (transparent proxying such as SSL proxy
     // does not count here). also, figure out what version we should be speaking.
     nsCAutoString buf, path;
     nsCString* requestURI;
     if (mConnectionInfo->UsingSSL() ||
         mConnectionInfo->ShouldForceConnectMethod() ||
         !mConnectionInfo->UsingHttpProxy()) {
         rv = mURI->GetPath(path);
@@ -4099,17 +4102,17 @@ nsHttpChannel::OnStartRequest(nsIRequest
 
     if (!mSecurityInfo && !mCachePump && mTransaction) {
         // grab the security info from the connection object; the transaction
         // is guaranteed to own a reference to the connection.
         mSecurityInfo = mTransaction->SecurityInfo();
     }
 
     if (gHttpHandler->IsSpdyEnabled() && !mCachePump && NS_FAILED(mStatus) &&
-        (mLoadFlags & LOAD_REPLACE) && mOriginalURI) {
+        (mLoadFlags & LOAD_REPLACE) && mOriginalURI && mAllowSpdy) {
         // 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);
     }
 
--- a/netwerk/protocol/http/nsIHttpChannelInternal.idl
+++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl
@@ -48,17 +48,17 @@ interface nsIAsyncInputStream;
 interface nsIAsyncOutputStream;
 interface nsIURI;
 interface nsIProxyInfo;
 
 /**
  * The callback interface for nsIHttpChannelInternal::HTTPUpgrade()
  */
 
-[scriptable, uuid(5644af88-09e1-4fbd-83da-f012b3b30180)]
+[scriptable, uuid(4b967b6d-cd1c-49ae-a457-23ff76f5a2e8)]
 interface nsIHttpUpgradeListener : nsISupports
 {
     void onTransportAvailable(in nsISocketTransport   aTransport,
                               in nsIAsyncInputStream  aSocketIn,
                               in nsIAsyncOutputStream aSocketOut);
 };
 
 /**
@@ -176,9 +176,16 @@ interface nsIHttpChannelInternal : nsISu
      * @param aProtocolName
      *        The value of the HTTP Upgrade request header
      * @param aListener
      *        The callback object used to handle a successful upgrade
      */
     void HTTPUpgrade(in ACString aProtocolName,
                      in nsIHttpUpgradeListener aListener);
 
+    /**
+     * Enable/Disable Spdy negotiation on per channel basis.
+     * The network.http.spdy.enabled preference is still a pre-requisite
+     * for starting spdy.
+     */
+    attribute boolean allowSpdy;
+
 };
--- a/security/manager/ssl/src/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/src/nsNSSCallbacks.cpp
@@ -48,16 +48,17 @@
 #include "nsITokenDialogs.h"
 #include "nsNSSShutDown.h"
 #include "nsIUploadChannel.h"
 #include "nsThreadUtils.h"
 #include "nsIPrompt.h"
 #include "nsProxyRelease.h"
 #include "PSMRunnable.h"
 #include "nsIConsoleService.h"
+#include "nsIHttpChannelInternal.h"
 
 #include "ssl.h"
 #include "ocsp.h"
 #include "nssb64.h"
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
@@ -128,16 +129,26 @@ nsHTTPDownloadEvent::Run()
     NS_ENSURE_STATE(uploadChannel);
 
     rv = uploadChannel->SetUploadStream(uploadStream, 
                                         mRequestSession->mPostContentType,
                                         -1);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  // Do not use SPDY for internal security operations. It could result
+  // in the silent upgrade to ssl, which in turn could require an SSL
+  // operation to fufill something like a CRL fetch, which is an
+  // endless loop.
+  nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(chan);
+  if (internalChannel) {
+    rv = internalChannel->SetAllowSpdy(false);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
   nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(chan);
   NS_ENSURE_STATE(hchan);
 
   rv = hchan->SetRequestMethod(mRequestSession->mRequestMethod);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mResponsibleForDoneSignal = false;
   mListener->mResponsibleForDoneSignal = true;