bug 628561 release http persistent connection on force reload r=bz
authorPatrick McManus <mcmanus@ducksong.com>
Fri, 22 Jul 2011 12:31:37 -0400
changeset 73241 9ff13e309d9e6ed8f8e3e5ac7eae57bcdc46f1e8
parent 73228 e21430d2b2cb6b1c504dee447134d9efdcb6144e
child 73242 cfa6b93e92fc25d9e3f8bac08529014389dc89fa
push id20841
push usermak77@bonardo.net
push dateMon, 25 Jul 2011 12:14:44 +0000
treeherdermozilla-central@87645ab8ab27 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs628561
milestone8.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 628561 release http persistent connection on force reload r=bz A force-reload now clears persistent connections to the server related to the force-reloaded resource. This will allow renogitation of DNS or server load balancing.
docshell/base/nsDocShell.cpp
netwerk/base/public/nsIRequest.idl
netwerk/protocol/http/nsHttp.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9209,17 +9209,18 @@ nsresult nsDocShell::DoChannelLoad(nsICh
         break;
 
     case LOAD_NORMAL_BYPASS_CACHE:
     case LOAD_NORMAL_BYPASS_PROXY:
     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
     case LOAD_RELOAD_BYPASS_CACHE:
     case LOAD_RELOAD_BYPASS_PROXY:
     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
-        loadFlags |= nsIRequest::LOAD_BYPASS_CACHE;
+        loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
+                     nsIRequest::LOAD_FRESH_CONNECTION;
         break;
 
     case LOAD_NORMAL:
     case LOAD_LINK:
         // Set cache checking flags
         switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
         case 0:
             loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
--- a/netwerk/base/public/nsIRequest.idl
+++ b/netwerk/base/public/nsIRequest.idl
@@ -219,9 +219,15 @@ interface nsIRequest : nsISupports
     const unsigned long VALIDATE_ONCE_PER_SESSION = 1 << 13;
 
     /**
      * When set, this flag indicates that no user-specific data should be added
      * to the request when opened. This means that things like authorization
      * tokens or cookie headers should not be added.
      */
     const unsigned long LOAD_ANONYMOUS = 1 << 14;
+
+    /**
+     * When set, this flag indicates that caches of network connections,
+     * particularly HTTP persistent connections, should not be used.
+     */
+    const unsigned long LOAD_FRESH_CONNECTION = 1 << 15;
 };
--- a/netwerk/protocol/http/nsHttp.h
+++ b/netwerk/protocol/http/nsHttp.h
@@ -121,16 +121,21 @@ typedef PRUint8 nsHttpVersion;
 
 // a transaction with this caps flag will not pass SSL client-certificates
 // to the server (see bug #466080), but is may also be used for other things
 #define NS_HTTP_LOAD_ANONYMOUS       (1<<4)
 
 // a transaction with this caps flag keeps timing information
 #define NS_HTTP_TIMING_ENABLED       (1<<5)
 
+// a transaction with this caps flag will not only not use an existing
+// persistent connection but it will close outstanding ones to the same
+// host. Used by a forced reload to reset the connection states.
+#define NS_HTTP_CLEAR_KEEPALIVES     (1<<6)
+
 //-----------------------------------------------------------------------------
 // some default values
 //-----------------------------------------------------------------------------
 
 // hard upper limit on the number of requests that can be pipelined
 #define NS_HTTP_MAX_PIPELINED_REQUESTS 8 
 
 #define NS_HTTP_DEFAULT_PORT  80
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -3632,16 +3632,20 @@ nsHttpChannel::AsyncOpen(nsIStreamListen
     //    trying to establish a keep-alive connection.
     if (mRequestHead.HasHeaderValue(nsHttp::Connection, "close"))
         mCaps &= ~(NS_HTTP_ALLOW_KEEPALIVE | NS_HTTP_ALLOW_PIPELINING);
     
     if ((mLoadFlags & VALIDATE_ALWAYS) || 
         (BYPASS_LOCAL_CACHE(mLoadFlags)))
         mCaps |= NS_HTTP_REFRESH_DNS;
 
+    // Force-Reload should reset the persistent connection pool for this host
+    if (mLoadFlags & LOAD_FRESH_CONNECTION)
+        mCaps |= NS_HTTP_CLEAR_KEEPALIVES;
+    
     mIsPending = PR_TRUE;
     mWasOpened = PR_TRUE;
 
     mListener = listener;
     mListenerContext = context;
 
     // add ourselves to the load group.  from this point forward, we'll report
     // all failures asynchronously.
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -679,16 +679,34 @@ nsHttpConnectionMgr::AtActiveConnectionL
     }
 
     // use >= just to be safe
     return (totalCount >= maxConns) || ( (caps & NS_HTTP_ALLOW_KEEPALIVE) &&
                                          (persistCount >= maxPersistConns) );
 }
 
 void
+nsHttpConnectionMgr::ClosePersistentConnections(nsConnectionEntry *ent)
+{
+    LOG(("nsHttpConnectionMgr::ClosePersistentConnections [ci=%s]\n",
+         ent->mConnInfo->HashKey().get()));
+    while (ent->mIdleConns.Length()) {
+        nsHttpConnection *conn = ent->mIdleConns[0];
+        ent->mIdleConns.RemoveElementAt(0);
+        mNumIdleConns--;
+        conn->Close(NS_ERROR_ABORT);
+        NS_RELEASE(conn);
+    }
+    
+    PRInt32 activeCount = ent->mActiveConns.Length();
+    for (PRInt32 i=0; i < activeCount; i++)
+        ent->mActiveConns[i]->DontReuse();
+}
+
+void
 nsHttpConnectionMgr::GetConnection(nsConnectionEntry *ent,
                                    nsHttpTransaction *trans,
                                    PRBool onlyReusedConnection,
                                    nsHttpConnection **result)
 {
     LOG(("nsHttpConnectionMgr::GetConnection [ci=%s caps=%x]\n",
         ent->mConnInfo->HashKey().get(), PRUint32(trans->Caps())));
 
@@ -920,16 +938,21 @@ nsHttpConnectionMgr::ProcessNewTransacti
         if (!clone)
             return NS_ERROR_OUT_OF_MEMORY;
         ent = new nsConnectionEntry(clone);
         if (!ent)
             return NS_ERROR_OUT_OF_MEMORY;
         mCT.Put(&key, ent);
     }
 
+    // If we are doing a force reload then close out any existing conns
+    // to this host so that changes in DNS, LBs, etc.. are reflected
+    if (caps & NS_HTTP_CLEAR_KEEPALIVES)
+        ClosePersistentConnections(ent);
+
     // Check if the transaction already has a sticky reference to a connection.
     // If so, then we can just use it directly by transferring its reference
     // to the new connection var instead of calling GetConnection() to search
     // for an available one.
 
     nsAHttpConnection *wrappedConnection = trans->Connection();
     nsHttpConnection  *conn;
     conn = wrappedConnection ? wrappedConnection->TakeHttpConnection() : nsnull;
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -267,16 +267,17 @@ private:
     PRBool   AtActiveConnectionLimit(nsConnectionEntry *, PRUint8 caps);
     void     GetConnection(nsConnectionEntry *, nsHttpTransaction *,
                            PRBool, nsHttpConnection **);
     nsresult DispatchTransaction(nsConnectionEntry *, nsAHttpTransaction *,
                                  PRUint8 caps, nsHttpConnection *);
     PRBool   BuildPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **);
     nsresult ProcessNewTransaction(nsHttpTransaction *);
     nsresult EnsureSocketThreadTargetIfOnline();
+    void     ClosePersistentConnections(nsConnectionEntry *ent);
     nsresult CreateTransport(nsConnectionEntry *, nsHttpTransaction *);
     void     AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
     void     StartedConnect();
     void     RecvdConnect();
     
     // message handlers have this signature
     typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(PRInt32, void *);