157004 don't fire onLocationChange for error pages, and don't change the

docshell's currentURI either. be sure to add the failed URL to session history.

r=bz sr=darin
This commit is contained in:
cbiesinger%web.de 2005-01-31 11:26:31 +00:00
parent a2323caa2f
commit 57d7cad17b
5 changed files with 146 additions and 38 deletions

View File

@ -1,6 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: ft=cpp tw=78 sw=4 et ts=4 sts=4 cin
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -552,6 +551,7 @@ nsDocShell::ConvertLoadTypeToDocShellLoadInfo(PRUint32 aLoadType)
docShellLoadType = nsIDocShellLoadInfo::loadRefresh;
break;
case LOAD_BYPASS_HISTORY:
case LOAD_ERROR_PAGE:
docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory;
break;
case LOAD_STOP_CONTENT:
@ -664,6 +664,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
shEntry = nsnull;
}
else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
(parentLoadType == LOAD_ERROR_PAGE) ||
(shEntry &&
((parentLoadType & LOAD_CMD_HISTORY) ||
(parentLoadType == LOAD_RELOAD_NORMAL) ||
@ -1334,13 +1335,19 @@ NS_IMETHODIMP
nsDocShell::SetCurrentURI(nsIURI *aURI)
{
SetCurrentURI(aURI, nsnull);
return NS_OK;
}
void
nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest)
{
// We don't want to send a location change when we're displaying an error
// page, and we don't want to change our idea of "current URI" either
if (mLoadType == LOAD_ERROR_PAGE) {
return;
}
mCurrentURI = aURI; //This assignment addrefs
PRBool isRoot = PR_FALSE; // Is this the root docshell
PRBool isSubFrame = PR_FALSE; // Is this a subframe navigation?
@ -2784,7 +2791,9 @@ nsDocShell::LoadURI(const PRUnichar * aURI,
}
NS_IMETHODIMP
nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI, const PRUnichar *aURL)
nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
const PRUnichar *aURL,
nsIChannel* aFailedChannel)
{
// Get prompt and string bundle servcies
nsCOMPtr<nsIPrompt> prompter;
@ -2942,7 +2951,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI, const PRUnichar *aUR
NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
if (mUseErrorPages) {
// Display an error page
LoadErrorPage(aURI, aURL, error.get(), messageStr.get());
LoadErrorPage(aURI, aURL, error.get(), messageStr.get(),
aFailedChannel);
}
else
{
@ -2955,15 +2965,41 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI, const PRUnichar *aUR
NS_IMETHODIMP
nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL, const PRUnichar *aErrorType, const PRUnichar *aDescription)
nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
const PRUnichar *aErrorType,
const PRUnichar *aDescription,
nsIChannel* aFailedChannel)
{
#ifdef PR_LOGGING
if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
nsCAutoString spec;
aURI->GetSpec(spec);
nsCAutoString chanName;
aFailedChannel->GetName(chanName);
PR_LOG(gDocShellLog, PR_LOG_DEBUG,
("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
}
#endif
// Create an shistory entry for the old load, if we have a channel
if (aFailedChannel) {
mURIResultedInDocument = PR_TRUE;
OnLoadingSite(aFailedChannel);
mOSHE = mLSHE;
}
nsAutoString url;
if (aURI)
{
// Set our current URI
SetCurrentURI(aURI);
nsCAutoString uri;
nsresult rv = aURI->GetSpec(uri);
NS_ENSURE_SUCCESS(rv, rv);
url.AssignWithConversion(uri.get());
CopyUTF8toUTF16(uri, url);
}
else if (aURL)
{
@ -2976,29 +3012,30 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL, const PRUnichar *
// Create a URL to pass all the error information through to the page.
char *escapedUrl = nsEscape(NS_ConvertUCS2toUTF8(url.get()).get(), url_Path);
char *escapedError = nsEscape(NS_ConvertUCS2toUTF8(aErrorType).get(), url_Path);
char *escapedDescription = nsEscape(NS_ConvertUCS2toUTF8(aDescription).get(), url_Path);
char *escapedUrl = nsEscape(NS_ConvertUTF16toUTF8(url.get()).get(), url_Path);
char *escapedError = nsEscape(NS_ConvertUTF16toUTF8(aErrorType).get(), url_Path);
char *escapedDescription = nsEscape(NS_ConvertUTF16toUTF8(aDescription).get(), url_Path);
nsAutoString errorType(aErrorType);
nsAutoString errorPageUrl;
errorPageUrl.AssignLiteral("chrome://global/content/netError.xhtml?e=");
errorPageUrl.AppendWithConversion(escapedError);
errorPageUrl.AppendASCII(escapedError);
errorPageUrl.AppendLiteral("&u=");
errorPageUrl.AppendWithConversion(escapedUrl);
errorPageUrl.AppendASCII(escapedUrl);
errorPageUrl.AppendLiteral("&d=");
errorPageUrl.AppendWithConversion(escapedDescription);
errorPageUrl.AppendASCII(escapedDescription);
PR_FREEIF(escapedDescription);
PR_FREEIF(escapedError);
PR_FREEIF(escapedUrl);
return LoadURI(errorPageUrl.get(), // URI string
LOAD_FLAGS_BYPASS_HISTORY,
nsnull,
nsnull,
nsnull);
nsCOMPtr<nsIURI> errorPageURI;
nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
NS_ENSURE_SUCCESS(rv, rv);
return InternalLoad(errorPageURI, nsnull, nsnull, PR_TRUE, nsnull, nsnull,
nsnull, nsnull, LOAD_ERROR_PAGE,
nsnull, PR_TRUE, nsnull, nsnull);
}
@ -3665,7 +3702,8 @@ nsDocShell::SetTitle(const PRUnichar * aTitle)
// there is no need to update the title. There is no need to
// go to mSessionHistory to update the title. Setting it in mOSHE
// would suffice.
if (mOSHE && (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_HISTORY)) {
if (mOSHE && (mLoadType != LOAD_BYPASS_HISTORY) &&
(mLoadType != LOAD_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) {
mOSHE->SetTitle(mTitle.get());
}
@ -4538,7 +4576,8 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
if (httpChannel) {
// figure out if SH should be saving layout state.
PRBool discardLayoutState = ShouldDiscardLayoutState(httpChannel);
if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) && (mLoadType != LOAD_BYPASS_HISTORY))
if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
(mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE))
mLSHE->SetSaveLayoutStateFlag(PR_FALSE);
}
@ -5592,13 +5631,17 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// been called.
mLSHE = aSHEntry;
nsCOMPtr<nsIRequest> req;
rv = DoURILoad(aURI, aReferrer,
!(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
owner, aTypeHint, aPostData, aHeadersData, aFirstParty,
aDocShell, aRequest);
aDocShell, getter_AddRefs(req));
if (req && aRequest)
NS_ADDREF(*aRequest = req);
if (NS_FAILED(rv)) {
DisplayLoadError(rv, aURI, nsnull);
nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
DisplayLoadError(rv, aURI, nsnull, chan);
}
return rv;
@ -5666,6 +5709,11 @@ nsDocShell::DoURILoad(nsIURI * aURI,
loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
}
if (mLoadType == LOAD_ERROR_PAGE) {
// Error pages are LOAD_BACKGROUND
loadFlags |= nsIChannel::LOAD_BACKGROUND;
}
// open a channel for the url
nsCOMPtr<nsIChannel> channel;
@ -5692,6 +5740,11 @@ nsDocShell::DoURILoad(nsIURI * aURI,
return rv;
}
// Make sure to give the caller a channel if we managed to create one
// This is important for correct error page/session history interaction
if (aRequest)
NS_ADDREF(*aRequest = channel);
channel->SetOriginalURI(aURI);
if (aTypeHint && *aTypeHint) {
channel->SetContentType(nsDependentCString(aTypeHint));
@ -5819,9 +5872,6 @@ nsDocShell::DoURILoad(nsIURI * aURI,
*aDocShell = this;
NS_ADDREF(*aDocShell);
}
if (aRequest) {
CallQueryInterface(channel, aRequest);
}
}
return rv;
@ -6173,6 +6223,19 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel,
PRUint32 aLoadType)
{
NS_ASSERTION(aURI, "uri is null");
#ifdef PR_LOGGING
if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
nsCAutoString spec;
aURI->GetSpec(spec);
nsCAutoString chanName;
aChannel->GetName(chanName);
PR_LOG(gDocShellLog, PR_LOG_DEBUG,
("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(),
chanName.get(), aLoadType));
}
#endif
PRBool updateHistory = PR_TRUE;
PRBool equalUri = PR_FALSE;
@ -6209,6 +6272,7 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel,
// Determine if this type of load should update history.
if (aLoadType == LOAD_BYPASS_HISTORY ||
aLoadType == LOAD_ERROR_PAGE ||
aLoadType & LOAD_CMD_HISTORY ||
aLoadType & LOAD_CMD_RELOAD)
updateHistory = PR_FALSE;
@ -6258,7 +6322,7 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel,
if (cacheChannel)
cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
if (mLSHE)
mLSHE->SetCacheKey(cacheKey);
mLSHE->SetCacheKey(cacheKey);
}
if (updateHistory && shAvailable) {
@ -6357,6 +6421,20 @@ nsresult
nsDocShell::AddToSessionHistory(nsIURI * aURI,
nsIChannel * aChannel, nsISHEntry ** aNewEntry)
{
#ifdef PR_LOGGING
if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
nsCAutoString spec;
aURI->GetSpec(spec);
nsCAutoString chanName;
aChannel->GetName(chanName);
PR_LOG(gDocShellLog, PR_LOG_DEBUG,
("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec.get(),
chanName.get()));
}
#endif
nsresult rv = NS_OK;
nsCOMPtr<nsISHEntry> entry;
PRBool shouldPersist;

View File

@ -100,6 +100,11 @@
#include "nsDocShellTransferableHooks.h"
#include "nsIAuthPromptProvider.h"
/**
* Load flag for error pages. This should be bigger than all flags on
* nsIWebNavigation.
*/
#define LOAD_FLAGS_ERROR_PAGE 0x8000U
#define MAKE_LOAD_TYPE(type, flags) ((type) | ((flags) << 16))
#define LOAD_TYPE_HAS_FLAGS(type, flags) ((type) & ((flags) << 16))
@ -125,7 +130,14 @@ enum LoadType {
LOAD_RELOAD_CHARSET_CHANGE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE),
LOAD_BYPASS_HISTORY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_HISTORY),
LOAD_STOP_CONTENT = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT),
LOAD_STOP_CONTENT_AND_REPLACE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT | nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY)
LOAD_STOP_CONTENT_AND_REPLACE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT | nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY),
/**
* Load type for an error page. These loads are never triggered by users of
* Docshell. Instead, Docshell triggers the load itself when a
* consumer-triggered load failed.
*/
LOAD_ERROR_PAGE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, LOAD_FLAGS_ERROR_PAGE)
// NOTE: Adding a new value? Remember to update IsValidLoadType!
};
static inline PRBool IsValidLoadType(PRUint32 aLoadType)
@ -145,6 +157,7 @@ static inline PRBool IsValidLoadType(PRUint32 aLoadType)
case LOAD_BYPASS_HISTORY:
case LOAD_STOP_CONTENT:
case LOAD_STOP_CONTENT_AND_REPLACE:
case LOAD_ERROR_PAGE:
return PR_TRUE;
}
return PR_FALSE;
@ -312,8 +325,13 @@ protected:
nsresult EnsureTransferableHookData();
NS_IMETHOD EnsureFind();
NS_IMETHOD RefreshURIFromQueue();
NS_IMETHOD DisplayLoadError(nsresult aError, nsIURI *aURI, const PRUnichar *aURL);
NS_IMETHOD LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL, const PRUnichar *aPage, const PRUnichar *aDescription);
NS_IMETHOD DisplayLoadError(nsresult aError, nsIURI *aURI,
const PRUnichar *aURL,
nsIChannel* aFailedChannel = nsnull);
NS_IMETHOD LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
const PRUnichar *aPage,
const PRUnichar *aDescription,
nsIChannel* aFailedChannel);
PRBool IsPrintingOrPP(PRBool aDisplayErrorDialog = PR_TRUE);
nsresult SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer);

View File

@ -686,7 +686,7 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress,
if(url && NS_FAILED(aStatus)) {
if (aStatus == NS_ERROR_FILE_NOT_FOUND) {
DisplayLoadError(aStatus, url, nsnull);
DisplayLoadError(aStatus, url, nsnull, channel);
return NS_OK;
}
@ -819,7 +819,7 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress,
aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED) &&
(isTopFrame || mUseErrorPages)) {
DisplayLoadError(aStatus, url, nsnull);
DisplayLoadError(aStatus, url, nsnull, channel);
}
// Errors to be shown for any frame
else if (aStatus == NS_ERROR_NET_TIMEOUT ||
@ -827,7 +827,7 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress,
aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
aStatus == NS_ERROR_NET_INTERRUPT ||
aStatus == NS_ERROR_NET_RESET) {
DisplayLoadError(aStatus, url, nsnull);
DisplayLoadError(aStatus, url, nsnull, channel);
}
else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
/* A document that was requested to be fetched *only* from
@ -925,7 +925,7 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress,
}
}
else {
DisplayLoadError(aStatus, url, nsnull);
DisplayLoadError(aStatus, url, nsnull, channel);
}
}
} // if we have a host

View File

@ -1,9 +1,15 @@
// Error url MUST be formatted like this:
// chrome://neterror.xhtml?e=error&u=url&d=desc
// Note that this file uses document.documentURI to get
// the URL (with the format from above). This is because
// document.location.href gets the current URI off the docshell,
// which is the URL displayed in the location bar, i.e.
// the URI that the user attempted to load.
function getErrorCode()
{
var url = document.location.href;
var url = document.documentURI;
var error = url.search(/e\=/);
var duffUrl = url.search(/\&u\=/);
return decodeURIComponent(url.slice(error + 2, duffUrl));
@ -11,7 +17,7 @@ function getErrorCode()
function getDuffUrl()
{
var url = document.location.href;
var url = document.documentURI;
var duffUrl = url.search(/u\=/);
var desc = url.search(/\&d\=/);
return decodeURIComponent(url.slice(duffUrl + 2, desc));
@ -19,7 +25,7 @@ function getDuffUrl()
function getDescription()
{
var url = document.location.href;
var url = document.documentURI;
var desc = url.search(/d\=/);
return decodeURIComponent(url.slice(desc + 2));
}

View File

@ -86,7 +86,7 @@
]]></style>
</head>
<body style="font: message-box;" onload="fillIn();">
<body style="font: message-box;">
<!-- ERROR TITLE -->
<div id="errorTitle">
@ -162,6 +162,12 @@
</div>
<p><a id="retry" href="#" onclick="retryThis();">&retry.label;</a></p>
<!--
- Note: It is important to run fillIn using this way, instead of using
- an onload handler. This is because error pages are loaded as
- LOAD_BACKGROUND, which means that onload handlers will not be executed.
-->
<script type="application/x-javascript">fillIn();</script>
</body>
</html>