bug 1094522 - claim conns with null transactions instead of starting new ones r=hurley
authorPatrick McManus <mcmanus@ducksong.com>
Tue, 27 Jan 2015 21:55:38 -0500
changeset 239746 050e9b432799d3761179fc52fd0973c10ed5bb54
parent 239745 b6d3a8960d38adc7d16a69f011db20d4e43dc83b
child 239747 c665e2057216792ec94eac31c645c8ad79ba4a6c
push id506
push usermleibovic@mozilla.com
push dateThu, 29 Jan 2015 12:40:10 +0000
reviewershurley
bugs1094522
milestone38.0a1
bug 1094522 - claim conns with null transactions instead of starting new ones r=hurley
netwerk/protocol/http/NullHttpTransaction.cpp
netwerk/protocol/http/NullHttpTransaction.h
netwerk/protocol/http/TunnelUtils.cpp
netwerk/protocol/http/TunnelUtils.h
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
--- a/netwerk/protocol/http/NullHttpTransaction.cpp
+++ b/netwerk/protocol/http/NullHttpTransaction.cpp
@@ -92,16 +92,17 @@ NS_IMPL_ISUPPORTS(NullHttpTransaction, N
 NullHttpTransaction::NullHttpTransaction(nsHttpConnectionInfo *ci,
                                          nsIInterfaceRequestor *callbacks,
                                          uint32_t caps)
   : mStatus(NS_OK)
   , mCaps(caps | NS_HTTP_ALLOW_KEEPALIVE)
   , mCapsToClear(0)
   , mRequestHead(nullptr)
   , mIsDone(false)
+  , mClaimed(false)
   , mCallbacks(callbacks)
   , mConnectionInfo(ci)
 {
   nsresult rv;
   mActivityDistributor = do_GetService(NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID,
                                        &rv);
   if (NS_FAILED(rv)) {
     return;
@@ -121,16 +122,26 @@ NullHttpTransaction::NullHttpTransaction
 }
 
 NullHttpTransaction::~NullHttpTransaction()
 {
   mCallbacks = nullptr;
   delete mRequestHead;
 }
 
+bool
+NullHttpTransaction::Claim()
+{
+  if (mClaimed) {
+    return false;
+  }
+  mClaimed = true;
+  return true;
+}
+
 void
 NullHttpTransaction::SetConnection(nsAHttpConnection *conn)
 {
   mConnection = conn;
 }
 
 nsAHttpConnection *
 NullHttpTransaction::Connection()
--- a/netwerk/protocol/http/NullHttpTransaction.h
+++ b/netwerk/protocol/http/NullHttpTransaction.h
@@ -33,18 +33,21 @@ public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_NULLHTTPTRANSACTION_IID)
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSAHTTPTRANSACTION
 
   NullHttpTransaction(nsHttpConnectionInfo *ci,
                       nsIInterfaceRequestor *callbacks,
                       uint32_t caps);
 
+  bool Claim();
+
   // Overload of nsAHttpTransaction methods
   bool IsNullTransaction() MOZ_OVERRIDE MOZ_FINAL { return true; }
+  NullHttpTransaction *QueryNullTransaction() MOZ_OVERRIDE MOZ_FINAL { return this; }
   bool ResponseTimeoutEnabled() const MOZ_OVERRIDE MOZ_FINAL {return true; }
   PRIntervalTime ResponseTimeout() MOZ_OVERRIDE MOZ_FINAL
   {
     return PR_SecondsToInterval(15);
   }
 
 protected:
   virtual ~NullHttpTransaction();
@@ -57,16 +60,17 @@ private:
   // mCapsToClear holds flags that should be cleared in mCaps, e.g. unset
   // NS_HTTP_REFRESH_DNS when DNS refresh request has completed to avoid
   // redundant requests on the network. To deal with raciness, only unsetting
   // bitfields should be allowed: 'lost races' will thus err on the
   // conservative side, e.g. by going ahead with a 2nd DNS refresh.
   uint32_t mCapsToClear;
   nsHttpRequestHead *mRequestHead;
   bool mIsDone;
+  bool mClaimed;
 
 protected:
   nsRefPtr<nsAHttpConnection> mConnection;
   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
   nsRefPtr<nsHttpConnectionInfo> mConnectionInfo;
   nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor;
 };
 
--- a/netwerk/protocol/http/TunnelUtils.cpp
+++ b/netwerk/protocol/http/TunnelUtils.cpp
@@ -745,16 +745,25 @@ bool
 TLSFilterTransaction::IsNullTransaction()
 {
   if (!mTransaction) {
     return false;
   }
   return mTransaction->IsNullTransaction();
 }
 
+NullHttpTransaction *
+TLSFilterTransaction::QueryNullTransaction()
+{
+  if (!mTransaction) {
+    return nullptr;
+  }
+  return mTransaction->QueryNullTransaction();
+}
+
 nsHttpTransaction *
 TLSFilterTransaction::QueryHttpTransaction()
 {
   if (!mTransaction) {
     return nullptr;
   }
   return mTransaction->QueryHttpTransaction();
 }
--- a/netwerk/protocol/http/TunnelUtils.h
+++ b/netwerk/protocol/http/TunnelUtils.h
@@ -80,16 +80,17 @@ the encrypted text available in mOutputD
 
 **************************************************************************/
 
 struct PRSocketOptionData;
 
 namespace mozilla { namespace net {
 
 class nsHttpRequestHead;
+class NullHttpTransaction;
 class TLSFilterTransaction;
 
 class NudgeTunnelCallback : public nsISupports
 {
 public:
   virtual void OnTunnelNudged(TLSFilterTransaction *) = 0;
 };
 
@@ -122,16 +123,17 @@ public:
   void     newIODriver(nsIAsyncInputStream *aSocketIn,
                        nsIAsyncOutputStream *aSocketOut,
                        nsIAsyncInputStream **outSocketIn,
                        nsIAsyncOutputStream **outSocketOut);
 
   // nsAHttpTransaction overloads
   nsHttpPipeline *QueryPipeline() MOZ_OVERRIDE;
   bool IsNullTransaction() MOZ_OVERRIDE;
+  NullHttpTransaction *QueryNullTransaction() MOZ_OVERRIDE;
   nsHttpTransaction *QueryHttpTransaction() MOZ_OVERRIDE;
   SpdyConnectTransaction *QuerySpdyConnectTransaction() MOZ_OVERRIDE;
 
 private:
   nsresult StartTimerCallback();
   void Cleanup();
   int32_t FilterOutput(const char *aBuf, int32_t aAmount);
   int32_t FilterInput(char *aBuf, int32_t aAmount);
--- a/netwerk/protocol/http/nsAHttpTransaction.h
+++ b/netwerk/protocol/http/nsAHttpTransaction.h
@@ -18,16 +18,17 @@ namespace mozilla { namespace net {
 
 class nsAHttpConnection;
 class nsAHttpSegmentReader;
 class nsAHttpSegmentWriter;
 class nsHttpTransaction;
 class nsHttpPipeline;
 class nsHttpRequestHead;
 class nsHttpConnectionInfo;
+class NullHttpTransaction;
 class SpdyConnectTransaction;
 
 //----------------------------------------------------------------------------
 // Abstract base class for a HTTP transaction:
 //
 // A transaction is a "sink" for the response data.  The connection pushes
 // data to the transaction by writing to it.  The transaction supports
 // WriteSegments and may refuse to accept data if its buffers are full (its
@@ -114,29 +115,30 @@ public:
     // Used to inform the connection that it is being used in a pipelined
     // context. That may influence the handling of some errors.
     // The value is the pipeline position (> 1).
     virtual nsresult SetPipelinePosition(int32_t) = 0;
     virtual int32_t  PipelinePosition() = 0;
 
     // Occasionally the abstract interface has to give way to base implementations
     // to respect differences between spdy, pipelines, etc..
-    // These Query* (and IsNUllTransaction()) functions provide a way to do
+    // These Query* (and IsNullTransaction()) functions provide a way to do
     // that without using xpcom or rtti. Any calling code that can't deal with
     // a null response from one of them probably shouldn't be using nsAHttpTransaction
 
     // If we used rtti this would be the result of doing
     // dynamic_cast<nsHttpPipeline *>(this).. i.e. it can be nullptr for
     // non pipeline implementations of nsAHttpTransaction
     virtual nsHttpPipeline *QueryPipeline() { return nullptr; }
 
     // equivalent to !!dynamic_cast<NullHttpTransaction *>(this)
     // A null transaction is expected to return BASE_STREAM_CLOSED on all of
     // its IO functions all the time.
     virtual bool IsNullTransaction() { return false; }
+    virtual NullHttpTransaction *QueryNullTransaction() { return nullptr; }
 
     // If we used rtti this would be the result of doing
     // dynamic_cast<nsHttpTransaction *>(this).. i.e. it can be nullptr for
     // non nsHttpTransaction implementations of nsAHttpTransaction
     virtual nsHttpTransaction *QueryHttpTransaction() { return nullptr; }
 
     // If we used rtti this would be the result of doing
     // dynamic_cast<SpdyConnectTransaction *>(this).. i.e. it can be nullptr for
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -1495,16 +1495,28 @@ nsHttpConnectionMgr::MakeNewConnection(n
             }
 
             // return OK because we have essentially opened a new connection
             // by converting a speculative half-open to general use
             return NS_OK;
         }
     }
 
+    uint32_t activeLength = ent->mActiveConns.Length();
+    for (uint32_t i = 0; i < activeLength; i++) {
+        nsAHttpTransaction *activeTrans = ent->mActiveConns[i]->Transaction();
+        NullHttpTransaction *nullTrans = activeTrans ? activeTrans->QueryNullTransaction() : nullptr;
+        if (nullTrans && nullTrans->Claim()) {
+            LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s] "
+                 "Claiming a null transaction for later use\n",
+                 ent->mConnInfo->HashKey().get()));
+            return NS_OK;
+        }
+    }
+
     // If this host is trying to negotiate a SPDY session right now,
     // don't create any new connections until the result of the
     // negotiation is known.
     if (!(trans->Caps() & NS_HTTP_DISALLOW_SPDY) &&
         (trans->Caps() & NS_HTTP_ALLOW_KEEPALIVE) &&
         RestrictConnections(ent)) {
         LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s] "
              "Not Available Due to RestrictConnections()\n",