Bug 738762 - Pass redirect and error information to global history.
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 29 Mar 2012 15:07:09 +0200
changeset 90623 1001d5a9f57a4b92d7dba13e13ecc04442f47ef4
parent 90606 d3cc19901240f812a2a5afd0a8e9cb601311d496
child 90624 7bffc102114e6ada087d5a6abfd0f0c1a88100f6
push id22370
push userbmo@edmorley.co.uk
push dateFri, 30 Mar 2012 15:14:13 +0000
treeherdermozilla-central@0cfa44a13b25 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs738762
milestone14.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 738762 - Pass redirect and error information to global history. r=bz
docshell/base/IHistory.h
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
--- a/docshell/base/IHistory.h
+++ b/docshell/base/IHistory.h
@@ -104,17 +104,26 @@ public:
         TOP_LEVEL = 1 << 0,
         /**
          * Indicates whether the URI was loaded as part of a permanent redirect.
          */
         REDIRECT_PERMANENT = 1 << 1,
         /**
          * Indicates whether the URI was loaded as part of a temporary redirect.
          */
-        REDIRECT_TEMPORARY = 1 << 2
+        REDIRECT_TEMPORARY = 1 << 2,
+        /**
+         * Indicates the URI is redirecting  (Response code 3xx).
+         */
+        REDIRECT_SOURCE = 1 << 3,
+        /**
+         * Indicates the URI caused an error that is unlikely fixable by a
+         * retry, like a not found or unfetchable page.
+         */
+        UNRECOVERABLE_ERROR = 1 << 4
     };
 
     /**
      * Adds a history visit for the URI.
      *
      * @pre aURI must not be null.
      *
      * @param aURI
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6064,18 +6064,26 @@ nsDocShell::OnRedirectStateChange(nsICha
         SaveLastVisit(aNewChannel, previousURI, previousFlags);
     }
     else {
         nsCOMPtr<nsIURI> referrer;
         // Treat referrer as null if there is an error getting it.
         (void)NS_GetReferrerFromChannel(aOldChannel,
                                         getter_AddRefs(referrer));
 
+        // Get the HTTP response code, if available.
+        PRUint32 responseStatus = 0;
+        nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
+        if (httpChannel) {
+            (void)httpChannel->GetResponseStatus(&responseStatus);
+        }
+
         // Add visit N -1 => N
-        AddURIVisit(oldURI, referrer, previousURI, previousFlags);
+        AddURIVisit(oldURI, referrer, previousURI, previousFlags,
+                    responseStatus);
 
         // Since N + 1 could be the final destination, we will not save N => N + 1
         // here.  OnNewURI will do that, so we will cache it.
         SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
     }
 
     // check if the new load should go through the application cache.
     nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
@@ -9260,17 +9268,18 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
                ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(),
                 chanName.get(), aLoadType));
     }
 #endif
 
     bool equalUri = false;
 
-    // Get the post data from the channel
+    // Get the post data and the HTTP response code from the channel.
+    PRUint32 responseStatus = 0;
     nsCOMPtr<nsIInputStream> inputStream;
     if (aChannel) {
         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
 
         // Check if the HTTPChannel is hiding under a multiPartChannel
         if (!httpChannel)  {
             GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
         }
@@ -9278,17 +9287,16 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
         if (httpChannel) {
             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
             if (uploadChannel) {
                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
             }
 
             // If the response status indicates an error, unlink this session
             // history entry from any entries sharing its document.
-            PRUint32 responseStatus;
             nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
             if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
                 mLSHE->AbandonBFCacheEntry();
             }
         }
     }
 
     // Determine if this type of load should update history.
@@ -9442,17 +9450,17 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
         }
 
         // Note: We don't use |referrer| when our global history is
         //       based on IHistory.
         nsCOMPtr<nsIURI> referrer;
         // Treat referrer as null if there is an error getting it.
         (void)NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
 
-        AddURIVisit(aURI, referrer, previousURI, previousFlags);
+        AddURIVisit(aURI, referrer, previousURI, previousFlags, responseStatus);
     }
 
     // If this was a history load or a refresh,
     // update the index in SH. 
     if (rootSH && (mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD))) {
         nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
         if (shInternal) {
             rootSH->GetIndex(&mPreviousTransIndex);
@@ -10588,19 +10596,23 @@ nsDocShell::SaveLastVisit(nsIChannel* aC
     props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
                                aChannelRedirectFlags);
 }
 
 void
 nsDocShell::AddURIVisit(nsIURI* aURI,
                         nsIURI* aReferrerURI,
                         nsIURI* aPreviousURI,
-                        PRUint32 aChannelRedirectFlags)
-{
-    NS_ASSERTION(aURI, "Visited URI is null!");
+                        PRUint32 aChannelRedirectFlags,
+                        PRUint32 aResponseStatus)
+{
+    MOZ_ASSERT(aURI, "Visited URI is null!");
+    MOZ_ASSERT(mLoadType != LOAD_ERROR_PAGE &&
+               mLoadType != LOAD_BYPASS_HISTORY,
+               "Do not add error or bypass pages to global history");
 
     // Only content-type docshells save URI visits.  Also don't do
     // anything here if we're not supposed to use global history.
     if (mItemType != typeContent || !mUseGlobalHistory) {
         return;
     }
 
     nsCOMPtr<IHistory> history = services::GetHistoryService();
@@ -10615,16 +10627,29 @@ nsDocShell::AddURIVisit(nsIURI* aURI,
         if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
             visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
         }
         else if (aChannelRedirectFlags &
                  nsIChannelEventSink::REDIRECT_PERMANENT) {
             visitURIFlags |= IHistory::REDIRECT_PERMANENT;
         }
 
+        if (aResponseStatus >= 300 && aResponseStatus < 400) {
+            visitURIFlags |= IHistory::REDIRECT_SOURCE;
+        }
+        // Errors 400-501 and 505 are considered unrecoverable, in the sense a
+        // simple retry attempt by the user is unlikely to solve them.
+        // 408 is special cased, since may actually indicate a temporary
+        // connection problem.
+        else if (aResponseStatus != 408 &&
+                 (aResponseStatus >= 400 && aResponseStatus <= 501 ||
+                  aResponseStatus == 505)) {
+            visitURIFlags |= IHistory::UNRECOVERABLE_ERROR;
+        }
+
         (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
     }
     else if (mGlobalHistory) {
         // Falls back to sync global history interface.
         (void)mGlobalHistory->AddURI(aURI,
                                      !!aChannelRedirectFlags,
                                      !IsFrame(),
                                      aReferrerURI);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -515,21 +515,24 @@ protected:
      *        The URI that was just visited
      * @param aReferrerURI
      *        The referrer URI of this request
      * @param aPreviousURI
      *        The previous URI of this visit (may be the same as aReferrerURI)
      * @param aChannelRedirectFlags
      *        For redirects, the redirect flags from nsIChannelEventSink
      *        (0 otherwise)
+     * @param aResponseStatus
+     *        For HTTP channels, the response code (0 otherwise).
      */
     void AddURIVisit(nsIURI* aURI,
                      nsIURI* aReferrerURI,
                      nsIURI* aPreviousURI,
-                     PRUint32 aChannelRedirectFlags);
+                     PRUint32 aChannelRedirectFlags,
+                     PRUint32 aResponseStatus=0);
 
     // Helper Routines
     nsresult   ConfirmRepost(bool * aRepost);
     NS_IMETHOD GetPromptAndStringBundle(nsIPrompt ** aPrompt,
         nsIStringBundle ** aStringBundle);
     NS_IMETHOD GetChildOffset(nsIDOMNode * aChild, nsIDOMNode * aParent,
         PRInt32 * aOffset);
     nsIScrollableFrame* GetRootScrollFrame();