fixes bug 45421 "Offline: No feedback when browsing to an uncached URL in

offline mode" r=adamlock sr=rpotts
This commit is contained in:
darin%netscape.com 2002-09-15 23:40:43 +00:00
Родитель 3b649a913b
Коммит 0c2e6c2638
7 изменённых файлов: 137 добавлений и 98 удалений

Просмотреть файл

@ -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;
}
}

Просмотреть файл

@ -164,6 +164,18 @@ static NS_DEFINE_CID(kCDOMRangeCID, NS_RANGE_CID);
//----------------------------------------------------------------------
static PRBool
IsOffline()
{
PRBool offline;
nsCOMPtr<nsIIOService> 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<nsIPrompt> prompter;
PRBool repost;
nsCOMPtr<nsIStringBundle> 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<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
nsCAutoString method;
if (httpChannel)
httpChannel->GetRequestMethod(method);
if (method.Equals("POST") && !IsOffline()) {
nsCOMPtr<nsIPrompt> prompter;
PRBool repost;
nsCOMPtr<nsIStringBundle> 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<nsISHistory> rootSH=mSessionHistory;
if (!mSessionHistory) {
nsCOMPtr<nsIDocShellTreeItem> root;
//Get the root docshell
GetSameTypeRootTreeItem(getter_AddRefs(root));
if (root) {
// QI root to nsIWebNavigation
nsCOMPtr<nsIWebNavigation> 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<nsISHistory> rootSH=mSessionHistory;
if (!mSessionHistory) {
nsCOMPtr<nsIDocShellTreeItem> root;
//Get the root docshell
GetSameTypeRootTreeItem(getter_AddRefs(root));
if (root) {
// QI root to nsIWebNavigation
nsCOMPtr<nsIWebNavigation> 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<nsISHistoryInternal> 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<nsIInputStream> inputStream;
nsCOMPtr<nsIURI> referrer;
if (channel) {
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if(httpChannel) {
httpChannel->GetReferrer(getter_AddRefs(referrer));
httpChannel->GetUploadStream(getter_AddRefs(inputStream));
}
}
} // mSessionHistory
if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) {
nsCOMPtr<nsISHistoryInternal> 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<nsIInputStream> inputStream;
nsCOMPtr<nsIURI> referrer;
if (channel) {
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if(httpChannel) {
httpChannel->GetReferrer(getter_AddRefs(referrer));
httpChannel->GetUploadStream(getter_AddRefs(inputStream));
nsCOMPtr<nsISeekableStream> postDataSeekable(do_QueryInterface(inputStream));
if (postDataSeekable)
{
postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
}
}
nsCOMPtr<nsISeekableStream> 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

Просмотреть файл

@ -71,8 +71,11 @@
<div id="unknownSocketType" style="display:none;">
<p>&unknownSocketType.longDesc;</p>
</div>
<div id="netOffline" style="display:none;">
<p>&netOffline.longDesc;</p>
</div>
<p><a id="retry" href="#" onclick="retryThis();">&retry.label;</a></p>
<p><a id="search" href="#" onclick="searchThis();">&search.label;</a></p>
</body>
</html>
</html>

Просмотреть файл

@ -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.

Просмотреть файл

@ -33,3 +33,6 @@
<!ENTITY netReset.title "netReset title">
<!ENTITY netReset.longDesc "netReset long description goes here.">
<!ENTITY netOffline.title "netOffline title">
<!ENTITY netOffline.longDesc "netOffline long description goes here.">

Просмотреть файл

@ -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<nsIIOService> 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<nsIIOService> 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.

Просмотреть файл

@ -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();