diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 60482fde842f..590bf7170e69 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -2475,6 +2475,11 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI, const PRUnichar *aUR // before we could read any data from it error.Assign(NS_LITERAL_STRING("netReset")); break; + case NS_ERROR_DOCUMENT_NOT_CACHED: + // Doc falied to load because we are offline and the cache does not + // contain a copy of the document. + error.Assign(NS_LITERAL_STRING("netOffline")); + break; } } diff --git a/docshell/base/nsWebShell.cpp b/docshell/base/nsWebShell.cpp index 1f14ecc0fd93..2d71df92a796 100644 --- a/docshell/base/nsWebShell.cpp +++ b/docshell/base/nsWebShell.cpp @@ -164,6 +164,18 @@ static NS_DEFINE_CID(kCDOMRangeCID, NS_RANGE_CID); //---------------------------------------------------------------------- +static PRBool +IsOffline() +{ + PRBool offline; + nsCOMPtr ios(do_GetIOService()); + if (ios) + ios->GetOffline(&offline); + return offline; +} + +//---------------------------------------------------------------------- + // Note: operator new zeros our memory nsWebShell::nsWebShell() : nsDocShell() { @@ -986,86 +998,96 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress, * the cache is not in cache. May be this is one of those * postdata results. Throw a dialog to the user, * saying that the page has expired from cache and ask if - * they wish to refetch the page from the net. + * they wish to refetch the page from the net. Do this only + * if the request is a form post. */ - nsCOMPtr prompter; - PRBool repost; - nsCOMPtr stringBundle; - GetPromptAndStringBundle(getter_AddRefs(prompter), - getter_AddRefs(stringBundle)); - - if (stringBundle && prompter) { - nsXPIDLString messageStr; - nsresult rv = stringBundle->GetStringFromName(NS_LITERAL_STRING("repost").get(), - getter_Copies(messageStr)); - - if (NS_SUCCEEDED(rv) && messageStr) { - prompter->Confirm(nsnull, messageStr, &repost); - /* If the user pressed cancel in the dialog, - * return failure. Don't try to load the page with out - * the post data. - */ - if (!repost) - return NS_OK; + nsCOMPtr httpChannel(do_QueryInterface(channel)); + nsCAutoString method; + if (httpChannel) + httpChannel->GetRequestMethod(method); + if (method.Equals("POST") && !IsOffline()) { + nsCOMPtr prompter; + PRBool repost; + nsCOMPtr stringBundle; + GetPromptAndStringBundle(getter_AddRefs(prompter), + getter_AddRefs(stringBundle)); + + if (stringBundle && prompter) { + nsXPIDLString messageStr; + nsresult rv = stringBundle->GetStringFromName(NS_LITERAL_STRING("repost").get(), + getter_Copies(messageStr)); + + if (NS_SUCCEEDED(rv) && messageStr) { + prompter->Confirm(nsnull, messageStr, &repost); + /* If the user pressed cancel in the dialog, + * return failure. Don't try to load the page with out + * the post data. + */ + if (!repost) + return NS_OK; - // The user wants to repost the data to the server. - // If the page was loaded due to a back/forward/go - // operation, update the session history index. - // This is similar to the updating done in - // nsDocShell::OnNewURI() for regular pages - nsCOMPtr rootSH=mSessionHistory; - if (!mSessionHistory) { - nsCOMPtr root; - //Get the root docshell - GetSameTypeRootTreeItem(getter_AddRefs(root)); - if (root) { - // QI root to nsIWebNavigation - nsCOMPtr rootAsWebnav(do_QueryInterface(root)); - if (rootAsWebnav) { - // Get the handle to SH from the root docshell - rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH)); + // The user wants to repost the data to the server. + // If the page was loaded due to a back/forward/go + // operation, update the session history index. + // This is similar to the updating done in + // nsDocShell::OnNewURI() for regular pages + nsCOMPtr rootSH=mSessionHistory; + if (!mSessionHistory) { + nsCOMPtr root; + //Get the root docshell + GetSameTypeRootTreeItem(getter_AddRefs(root)); + if (root) { + // QI root to nsIWebNavigation + nsCOMPtr rootAsWebnav(do_QueryInterface(root)); + if (rootAsWebnav) { + // Get the handle to SH from the root docshell + rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH)); + } + } + } // mSessionHistory + + if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) { + nsCOMPtr shInternal(do_QueryInterface(rootSH)); + if (shInternal) + shInternal->UpdateIndex(); + } + /* The user does want to repost the data to the server. + * Initiate a new load again. + */ + /* Get the postdata if any from the channel */ + nsCOMPtr inputStream; + nsCOMPtr referrer; + if (channel) { + nsCOMPtr httpChannel(do_QueryInterface(channel)); + + if(httpChannel) { + httpChannel->GetReferrer(getter_AddRefs(referrer)); + httpChannel->GetUploadStream(getter_AddRefs(inputStream)); } } - } // mSessionHistory - - if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) { - nsCOMPtr shInternal(do_QueryInterface(rootSH)); - if (shInternal) - shInternal->UpdateIndex(); - } - /* The user does want to repost the data to the server. - * Initiate a new load again. - */ - /* Get the postdata if any from the channel */ - nsCOMPtr inputStream; - nsCOMPtr referrer; - if (channel) { - nsCOMPtr httpChannel(do_QueryInterface(channel)); - - if(httpChannel) { - httpChannel->GetReferrer(getter_AddRefs(referrer)); - httpChannel->GetUploadStream(getter_AddRefs(inputStream)); + nsCOMPtr postDataSeekable(do_QueryInterface(inputStream)); + if (postDataSeekable) + { + postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); } - } - nsCOMPtr postDataSeekable(do_QueryInterface(inputStream)); - if (postDataSeekable) - { - postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); - } - InternalLoad(url, // URI - referrer, // Refering URI - nsnull, // Owner - PR_TRUE, // Inherit owner - nsnull, // No window target - inputStream, // Post data stream - nsnull, // No headers stream - LOAD_RELOAD_BYPASS_PROXY_AND_CACHE,// Load type - nsnull, // No SHEntry - PR_TRUE, // first party site - nsnull, // No nsIDocShell - nsnull); // No nsIRequest + InternalLoad(url, // URI + referrer, // Refering URI + nsnull, // Owner + PR_TRUE, // Inherit owner + nsnull, // No window target + inputStream, // Post data stream + nsnull, // No headers stream + LOAD_RELOAD_BYPASS_PROXY_AND_CACHE,// Load type + nsnull, // No SHEntry + PR_TRUE, // first party site + nsnull, // No nsIDocShell + nsnull); // No nsIRequest } } + } + else { + DisplayLoadError(aStatus, url, nsnull); + } } } // if we have a host diff --git a/docshell/resources/content/netError.xhtml b/docshell/resources/content/netError.xhtml index 1e8dc3055e9c..479df375614c 100644 --- a/docshell/resources/content/netError.xhtml +++ b/docshell/resources/content/netError.xhtml @@ -71,8 +71,11 @@ +

&retry.label;

&search.label;

- \ No newline at end of file + diff --git a/docshell/resources/locale/en-US/appstrings.properties b/docshell/resources/locale/en-US/appstrings.properties index dd5ff6c2027f..be57c7761d03 100644 --- a/docshell/resources/locale/en-US/appstrings.properties +++ b/docshell/resources/locale/en-US/appstrings.properties @@ -28,3 +28,4 @@ repost=The page you are trying to view contains POSTDATA that has expired from c repostConfirm=The page you are trying to view contains POSTDATA. If you resend the data, any action the form carried out (such as a search or online purchase) will be repeated. To resend the data, click OK. Otherwise, click Cancel. unknownSocketType=This document cannot be displayed unless you install the Personal Security Manager (PSM). Download and install PSM and try again, or contact your system administrator. netReset=The document contains no data. +netOffline=This document cannot be displayed while offline. diff --git a/docshell/resources/locale/en-US/netError.dtd b/docshell/resources/locale/en-US/netError.dtd index 6f768f6d38ec..cbfad83db8c5 100644 --- a/docshell/resources/locale/en-US/netError.dtd +++ b/docshell/resources/locale/en-US/netError.dtd @@ -33,3 +33,6 @@ + + + diff --git a/netwerk/protocol/http/src/nsHttpChannel.cpp b/netwerk/protocol/http/src/nsHttpChannel.cpp index eecb83e72d65..582ddc802247 100644 --- a/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -209,16 +209,26 @@ nsHttpChannel::Connect(PRBool firstTime) // true when called from AsyncOpen if (firstTime) { PRBool delayed = PR_FALSE; + PRBool offline = PR_FALSE; + + // are we offline? + nsCOMPtr ioService; + rv = nsHttpHandler::get()->GetIOService(getter_AddRefs(ioService)); + if (NS_FAILED(rv)) return rv; + + ioService->GetOffline(&offline); + if (offline) + mFromCacheOnly = PR_TRUE; // open a cache entry for this channel... - rv = OpenCacheEntry(&delayed); + rv = OpenCacheEntry(offline, &delayed); if (NS_FAILED(rv)) { LOG(("OpenCacheEntry failed [rv=%x]\n", rv)); // if this channel is only allowed to pull from the cache, then // we must fail if we were unable to open a cache entry. if (mFromCacheOnly) - return mPostID ? NS_ERROR_DOCUMENT_NOT_CACHED : rv; + return NS_ERROR_DOCUMENT_NOT_CACHED; // otherwise, let's just proceed without using the cache. } @@ -239,11 +249,11 @@ nsHttpChannel::Connect(PRBool firstTime) return ReadFromCache(); } else if (mFromCacheOnly) { - // The cache no longer contains the requested resource, and we - // are not allowed to refetch it, so there's nothing more to do. - // If this was a refetch of a POST transaction's resposne, then - // this failure indicates that the response is no longer cached. - return mPostID ? NS_ERROR_DOCUMENT_NOT_CACHED : NS_BINDING_FAILED; + // the cache contains the requested resource, but it must be + // validated before we can reuse it. since we are not allowed + // to hit the net, there's nothing more to do. the document + // is effectively not in the cache. + return NS_ERROR_DOCUMENT_NOT_CACHED; } } @@ -836,7 +846,7 @@ nsHttpChannel::ProcessNotModified() } nsresult -nsHttpChannel::OpenCacheEntry(PRBool *delayed) +nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed) { nsresult rv; @@ -882,20 +892,10 @@ nsHttpChannel::OpenCacheEntry(PRBool *delayed) getter_AddRefs(session)); if (NS_FAILED(rv)) return rv; - // Are we offline? - PRBool offline = PR_FALSE; - - nsCOMPtr ioService; - rv = nsHttpHandler::get()->GetIOService(getter_AddRefs(ioService)); - ioService->GetOffline(&offline); - // Set the desired cache access mode accordingly... nsCacheAccessMode accessRequested; - if (offline) { - // Since we are offline, we can only read from the cache. - accessRequested = nsICache::ACCESS_READ; - mFromCacheOnly = PR_TRUE; - } + if (offline) + accessRequested = nsICache::ACCESS_READ; // have no way of writing to cache else if (mLoadFlags & LOAD_BYPASS_CACHE) accessRequested = nsICache::ACCESS_WRITE; // replace cache entry else @@ -913,7 +913,7 @@ nsHttpChannel::OpenCacheEntry(PRBool *delayed) // we'll have to wait for the cache entry *delayed = PR_TRUE; } - else if (rv == NS_OK) { + else if (NS_SUCCEEDED(rv)) { mCacheEntry->GetAccessGranted(&mCacheAccess); LOG(("got cache entry [access=%x]\n", mCacheAccess)); } @@ -3220,11 +3220,16 @@ nsHttpChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry, nsresult rv; - if (NS_FAILED(mStatus)) { + if (mCanceled && NS_FAILED(mStatus)) { LOG(("channel was canceled [this=%x status=%x]\n", this, mStatus)); rv = mStatus; } - else // advance to the next state... + else if (mFromCacheOnly && NS_FAILED(status)) + // if this channel is only allowed to pull from the cache, then + // we must fail if we were unable to open a cache entry. + rv = NS_ERROR_DOCUMENT_NOT_CACHED; + else + // advance to the next state... rv = Connect(PR_FALSE); // a failure from Connect means that we have to abort the channel. diff --git a/netwerk/protocol/http/src/nsHttpChannel.h b/netwerk/protocol/http/src/nsHttpChannel.h index 165b66218cb7..41f5ec0f404c 100644 --- a/netwerk/protocol/http/src/nsHttpChannel.h +++ b/netwerk/protocol/http/src/nsHttpChannel.h @@ -99,7 +99,7 @@ private: nsresult ProcessAuthentication(PRUint32 httpStatus); // cache specific methods - nsresult OpenCacheEntry(PRBool *delayed); + nsresult OpenCacheEntry(PRBool offline, PRBool *delayed); nsresult GenerateCacheKey(nsACString &key); nsresult UpdateExpirationTime(); nsresult CheckCache();