diff --git a/docshell/base/IHistory.h b/docshell/base/IHistory.h index 2448784db96..b6d2bbcdde9 100644 --- a/docshell/base/IHistory.h +++ b/docshell/base/IHistory.h @@ -109,7 +109,16 @@ public: /** * 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 }; /** diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index a43c51a613a..035b0fd9d62 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -6069,8 +6069,16 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel, (void)NS_GetReferrerFromChannel(aOldChannel, getter_AddRefs(referrer)); + // Get the HTTP response code, if available. + PRUint32 responseStatus = 0; + nsCOMPtr 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. @@ -9265,7 +9273,8 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner, 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 inputStream; if (aChannel) { nsCOMPtr httpChannel(do_QueryInterface(aChannel)); @@ -9283,7 +9292,6 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner, // 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(); @@ -9447,7 +9455,7 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner, // 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, @@ -10593,9 +10601,13 @@ void nsDocShell::AddURIVisit(nsIURI* aURI, nsIURI* aReferrerURI, nsIURI* aPreviousURI, - PRUint32 aChannelRedirectFlags) + PRUint32 aChannelRedirectFlags, + PRUint32 aResponseStatus) { - NS_ASSERTION(aURI, "Visited URI is null!"); + 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. @@ -10620,6 +10632,19 @@ nsDocShell::AddURIVisit(nsIURI* aURI, 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) { diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 29fa6d0d416..f96700ee2ea 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -520,11 +520,14 @@ protected: * @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);