зеркало из https://github.com/mozilla/pjs.git
implement navigator.isLocallyAvailable. b=373231, r=biesi, sr=jst
This commit is contained in:
Родитель
78eff2581b
Коммит
08e612af60
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
interface nsIDOMOfflineResourceList;
|
interface nsIDOMOfflineResourceList;
|
||||||
|
|
||||||
[scriptable, uuid(609439fa-63e4-4f71-9512-904867f154e7)]
|
[scriptable, uuid(21c6561e-4778-47ed-96d0-eadc46d6a3ec)]
|
||||||
interface nsIDOMClientInformation : nsISupports
|
interface nsIDOMClientInformation : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +51,8 @@ interface nsIDOMClientInformation : nsISupports
|
||||||
void registerContentHandler(in DOMString mimeType, in DOMString uri, in DOMString title);
|
void registerContentHandler(in DOMString mimeType, in DOMString uri, in DOMString title);
|
||||||
void registerProtocolHandler(in DOMString protocol, in DOMString uri, in DOMString title);
|
void registerProtocolHandler(in DOMString protocol, in DOMString uri, in DOMString title);
|
||||||
|
|
||||||
|
boolean isLocallyAvailable(in DOMString uri, in boolean whenOffline);
|
||||||
|
|
||||||
readonly attribute nsIDOMOfflineResourceList offlineResources;
|
readonly attribute nsIDOMOfflineResourceList offlineResources;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
#include "nsStyleCoord.h"
|
#include "nsStyleCoord.h"
|
||||||
#include "nsMimeTypeArray.h"
|
#include "nsMimeTypeArray.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
|
#include "nsICachingChannel.h"
|
||||||
#include "nsPluginArray.h"
|
#include "nsPluginArray.h"
|
||||||
#include "nsIPluginHost.h"
|
#include "nsIPluginHost.h"
|
||||||
#ifdef OJI
|
#ifdef OJI
|
||||||
|
@ -8503,6 +8504,77 @@ nsNavigator::RegisterProtocolHandler(const nsAString& aProtocol,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsNavigator::IsLocallyAvailable(const nsAString &aURI,
|
||||||
|
PRBool aWhenOffline,
|
||||||
|
PRBool *aIsAvailable)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIURI> uri;
|
||||||
|
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// This method of checking the cache will only work for http/https urls
|
||||||
|
PRBool match;
|
||||||
|
rv = uri->SchemeIs("http", &match);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
if (!match) {
|
||||||
|
rv = uri->SchemeIs("https", &match);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
if (!match) return NS_ERROR_DOM_BAD_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same origin check
|
||||||
|
nsCOMPtr<nsIJSContextStack> stack = do_GetService(sJSStackContractID);
|
||||||
|
NS_ENSURE_TRUE(stack, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
JSContext *cx = nsnull;
|
||||||
|
rv = stack->Peek(&cx);
|
||||||
|
NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
rv = nsContentUtils::GetSecurityManager()->CheckSameOrigin(cx, uri);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// these load flags cause an error to be thrown if there is no
|
||||||
|
// valid cache entry, and skip the load if there is.
|
||||||
|
// if the cache is busy, assume that it is not yet available rather
|
||||||
|
// than waiting for it to become available.
|
||||||
|
PRUint32 loadFlags = nsIChannel::INHIBIT_CACHING |
|
||||||
|
nsIChannel::LOAD_NO_NETWORK_IO |
|
||||||
|
nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
|
||||||
|
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
|
||||||
|
|
||||||
|
if (aWhenOffline) {
|
||||||
|
loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE |
|
||||||
|
nsICachingChannel::LOAD_ONLY_FROM_CACHE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIChannel> channel;
|
||||||
|
rv = NS_NewChannel(getter_AddRefs(channel), uri,
|
||||||
|
nsnull, nsnull, nsnull, loadFlags);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIInputStream> stream;
|
||||||
|
rv = channel->Open(getter_AddRefs(stream));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
stream->Close();
|
||||||
|
|
||||||
|
nsresult status;
|
||||||
|
rv = channel->GetStatus(&status);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(status)) {
|
||||||
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||||
|
rv = httpChannel->GetRequestSucceeded(aIsAvailable);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
} else {
|
||||||
|
*aIsAvailable = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsNavigator::GetOfflineResources(nsIDOMOfflineResourceList **aList)
|
nsNavigator::GetOfflineResources(nsIDOMOfflineResourceList **aList)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,6 +47,7 @@ include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
_TEST_FILES = \
|
_TEST_FILES = \
|
||||||
test_offlineResources.html \
|
test_offlineResources.html \
|
||||||
|
test_isLocallyAvailable.html \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
libs:: $(_TEST_FILES)
|
libs:: $(_TEST_FILES)
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>navigator.isLocallyAvailable Test</title>
|
||||||
|
|
||||||
|
<link rel="offline-resource" href="http://localhost:8888/tests/SimpleTest/SimpleTest.js">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function run_test()
|
||||||
|
{
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
|
||||||
|
// check invalid urls
|
||||||
|
try {
|
||||||
|
navigator.isLocallyAvailable("http://different.origin.com", false);
|
||||||
|
ok(false, "can't check from a different origin");
|
||||||
|
} catch(e) {
|
||||||
|
ok(true, "can't check from a different origin");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
navigator.isLocallyAvailable("ftp://localhost/blah/blah", false);
|
||||||
|
ok(false, "urls must be http or https");
|
||||||
|
} catch(e) {
|
||||||
|
ok(true, "urls must be http or https");
|
||||||
|
}
|
||||||
|
|
||||||
|
// check an URL that should definitely not be there
|
||||||
|
ok(navigator.isLocallyAvailable("http://localhost:8888/blah/blah/blah",
|
||||||
|
false) == false,
|
||||||
|
"unknown item shouldn't be available online");
|
||||||
|
ok(navigator.isLocallyAvailable("http://localhost:8888/blah/blah/blah",
|
||||||
|
true) == false,
|
||||||
|
"unknown item shouldn't be available offline");
|
||||||
|
|
||||||
|
// check a URL that should be available on and offline
|
||||||
|
var url = "http://localhost:8888/tests/SimpleTest/SimpleTest.js";
|
||||||
|
ok(navigator.isLocallyAvailable(url, false) == true,
|
||||||
|
url + " should be available online");
|
||||||
|
ok(navigator.isLocallyAvailable(url, true) == true,
|
||||||
|
url + " should be available offline");
|
||||||
|
|
||||||
|
// Pull it out of the disk cache
|
||||||
|
var cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
|
||||||
|
.getService(Components.interfaces.nsICacheService);
|
||||||
|
var session = cacheService.createSession
|
||||||
|
("HTTP",
|
||||||
|
Components.interfaces.nsICache.STORE_ON_DISK,
|
||||||
|
Components.interfaces.nsICache.STREAM_BASED);
|
||||||
|
var entry = session.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_WRITE, false);
|
||||||
|
entry.doom();
|
||||||
|
entry.close();
|
||||||
|
|
||||||
|
// Now it should be available offline but not online
|
||||||
|
ok(navigator.isLocallyAvailable(url, false) == false,
|
||||||
|
url + " should not be available online");
|
||||||
|
|
||||||
|
ok(navigator.isLocallyAvailable(url, true) == true,
|
||||||
|
url + " should be available offline");
|
||||||
|
|
||||||
|
// Clear the offline cache/ownership on the way out
|
||||||
|
var cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
|
||||||
|
.getService(Components.interfaces.nsICacheService);
|
||||||
|
var cacheSession = cacheService.createSession("HTTP-offline",
|
||||||
|
Components.interfaces.nsICache.STORE_OFFLINE,
|
||||||
|
true)
|
||||||
|
.QueryInterface(Components.interfaces.nsIOfflineCacheSession);
|
||||||
|
cacheSession.setOwnedKeys(window.location.host,
|
||||||
|
window.location.protocol + "//" + window.location.host + window.location.pathname,
|
||||||
|
0, []);
|
||||||
|
cacheSession.setOwnedKeys(window.location.host, "", 0, []);
|
||||||
|
cacheSession.evictUnownedEntries();
|
||||||
|
|
||||||
|
cacheService.evictEntries(Components.interfaces.nsICache.STORE_OFFLINE);
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give the offline resources some time to load.
|
||||||
|
setTimeout("run_test()", 1000);
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -50,7 +50,7 @@ interface nsIFile;
|
||||||
* 3) Support for uniquely identifying cached data in cases when the URL
|
* 3) Support for uniquely identifying cached data in cases when the URL
|
||||||
* is insufficient (e.g., HTTP form submission).
|
* is insufficient (e.g., HTTP form submission).
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(855bcc4d-0987-45b6-b138-3bf0bf407703)]
|
[scriptable, uuid(afafb719-bdf5-49c8-a4a9-db39ec331c9b)]
|
||||||
interface nsICachingChannel : nsISupports
|
interface nsICachingChannel : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -123,6 +123,12 @@ interface nsICachingChannel : nsISupports
|
||||||
* Caching channel specific load flags:
|
* Caching channel specific load flags:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This load flag causes the offline cache to be checked when fetching
|
||||||
|
* a request. It will be set automatically if the browser is offline.
|
||||||
|
*/
|
||||||
|
const unsigned long LOAD_CHECK_OFFLINE_CACHE = 1 << 27;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This load flag causes the local cache to be skipped when fetching a
|
* This load flag causes the local cache to be skipped when fetching a
|
||||||
* request. Unlike LOAD_BYPASS_CACHE, it does not force an end-to-end load
|
* request. Unlike LOAD_BYPASS_CACHE, it does not force an end-to-end load
|
||||||
|
@ -139,7 +145,8 @@ interface nsICachingChannel : nsISupports
|
||||||
/**
|
/**
|
||||||
* This load flag inhibits fetching from the net if the data in the cache
|
* This load flag inhibits fetching from the net if the data in the cache
|
||||||
* has been evicted. An error of NS_ERROR_DOCUMENT_NOT_CACHED will be sent
|
* has been evicted. An error of NS_ERROR_DOCUMENT_NOT_CACHED will be sent
|
||||||
* to the listener's onStopRequest in this case.
|
* to the listener's onStopRequest in this case. This flag is set
|
||||||
|
* automatically when the application is offline.
|
||||||
*/
|
*/
|
||||||
const unsigned long LOAD_ONLY_FROM_CACHE = 1 << 30;
|
const unsigned long LOAD_ONLY_FROM_CACHE = 1 << 30;
|
||||||
|
|
||||||
|
|
|
@ -259,4 +259,11 @@ interface nsIChannel : nsIRequest
|
||||||
* should only do so with good reason.
|
* should only do so with good reason.
|
||||||
*/
|
*/
|
||||||
const unsigned long LOAD_CALL_CONTENT_SNIFFERS = 1 << 21;
|
const unsigned long LOAD_CALL_CONTENT_SNIFFERS = 1 << 21;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This load flag inhibits fetching from the net. An error of
|
||||||
|
* NS_ERROR_NEEDS_NETWORK will be sent to the listener's onStopRequest
|
||||||
|
* if network IO is necessary to complete the request.
|
||||||
|
*/
|
||||||
|
const unsigned long LOAD_NO_NETWORK_IO = 1 << 22;
|
||||||
};
|
};
|
||||||
|
|
|
@ -208,6 +208,13 @@
|
||||||
#define NS_ERROR_NET_INTERRUPT \
|
#define NS_ERROR_NET_INTERRUPT \
|
||||||
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 71)
|
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 71)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The requested action would require network IO, but
|
||||||
|
* nsIChannel::LOAD_NO_NETWORK_IO was specified.
|
||||||
|
*/
|
||||||
|
#define NS_ERROR_NEEDS_NETWORK \
|
||||||
|
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 72)
|
||||||
|
|
||||||
// XXX really need to better rationalize these error codes. are consumers of
|
// XXX really need to better rationalize these error codes. are consumers of
|
||||||
// necko really expected to know how to discern the meaning of these??
|
// necko really expected to know how to discern the meaning of these??
|
||||||
|
|
||||||
|
|
|
@ -1662,6 +1662,13 @@ nsFtpState::Connect()
|
||||||
mState = FTP_COMMAND_CONNECT;
|
mState = FTP_COMMAND_CONNECT;
|
||||||
mNextState = FTP_S_USER;
|
mNextState = FTP_S_USER;
|
||||||
|
|
||||||
|
if (mChannel->HasLoadFlag(nsIChannel::LOAD_NO_NETWORK_IO)){
|
||||||
|
mInternalError = NS_ERROR_NEEDS_NETWORK;
|
||||||
|
mState = FTP_ERROR;
|
||||||
|
CloseWithStatus(mInternalError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult rv = Process();
|
nsresult rv = Process();
|
||||||
|
|
||||||
// check for errors.
|
// check for errors.
|
||||||
|
|
|
@ -187,7 +187,10 @@ nsresult
|
||||||
nsGopherContentStream::OpenSocket(nsIEventTarget *target)
|
nsGopherContentStream::OpenSocket(nsIEventTarget *target)
|
||||||
{
|
{
|
||||||
// This function is called to get things started.
|
// This function is called to get things started.
|
||||||
//
|
|
||||||
|
if (mChannel->HasLoadFlag(nsIChannel::LOAD_NO_NETWORK_IO))
|
||||||
|
return NS_ERROR_NEEDS_NETWORK;
|
||||||
|
|
||||||
// We begin by opening a socket to the specified host and wait for the
|
// We begin by opening a socket to the specified host and wait for the
|
||||||
// socket to become writable.
|
// socket to become writable.
|
||||||
|
|
||||||
|
|
|
@ -272,7 +272,7 @@ nsHttpChannel::Connect(PRBool firstTime)
|
||||||
// are we offline?
|
// are we offline?
|
||||||
PRBool offline = gIOService->IsOffline();
|
PRBool offline = gIOService->IsOffline();
|
||||||
if (offline)
|
if (offline)
|
||||||
mLoadFlags |= LOAD_ONLY_FROM_CACHE;
|
mLoadFlags |= (LOAD_ONLY_FROM_CACHE | LOAD_CHECK_OFFLINE_CACHE);
|
||||||
else if (PL_strcmp(mConnectionInfo->ProxyType(), "unknown") == 0)
|
else if (PL_strcmp(mConnectionInfo->ProxyType(), "unknown") == 0)
|
||||||
return ResolveProxy(); // Lazily resolve proxy info
|
return ResolveProxy(); // Lazily resolve proxy info
|
||||||
|
|
||||||
|
@ -330,6 +330,10 @@ nsHttpChannel::Connect(PRBool firstTime)
|
||||||
// check to see if authorization headers should be included
|
// check to see if authorization headers should be included
|
||||||
AddAuthorizationHeaders();
|
AddAuthorizationHeaders();
|
||||||
|
|
||||||
|
if (mLoadFlags & LOAD_NO_NETWORK_IO) {
|
||||||
|
return NS_ERROR_NEEDS_NETWORK;
|
||||||
|
}
|
||||||
|
|
||||||
// hit the net...
|
// hit the net...
|
||||||
rv = SetupTransaction();
|
rv = SetupTransaction();
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
@ -1307,9 +1311,10 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
|
||||||
|
|
||||||
// Set the desired cache access mode accordingly...
|
// Set the desired cache access mode accordingly...
|
||||||
nsCacheAccessMode accessRequested;
|
nsCacheAccessMode accessRequested;
|
||||||
if (offline || (mLoadFlags & INHIBIT_CACHING)) {
|
if (mLoadFlags & (LOAD_ONLY_FROM_CACHE | INHIBIT_CACHING)) {
|
||||||
// If we have been asked to bypass the cache and not write to the
|
// If we have been asked to bypass the cache and not write to the
|
||||||
// cache, then don't use the cache at all.
|
// cache, then don't use the cache at all. Unless we're actually
|
||||||
|
// offline, which takes precedence over BYPASS_LOCAL_CACHE.
|
||||||
if (BYPASS_LOCAL_CACHE(mLoadFlags) && !offline)
|
if (BYPASS_LOCAL_CACHE(mLoadFlags) && !offline)
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
accessRequested = nsICache::ACCESS_READ;
|
accessRequested = nsICache::ACCESS_READ;
|
||||||
|
@ -1330,7 +1335,7 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
|
||||||
rv = session->OpenCacheEntry(cacheKey, accessRequested, PR_FALSE,
|
rv = session->OpenCacheEntry(cacheKey, accessRequested, PR_FALSE,
|
||||||
getter_AddRefs(mCacheEntry));
|
getter_AddRefs(mCacheEntry));
|
||||||
|
|
||||||
if (offline &&
|
if ((mLoadFlags & LOAD_CHECK_OFFLINE_CACHE) &&
|
||||||
!(NS_SUCCEEDED(rv) || rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION)) {
|
!(NS_SUCCEEDED(rv) || rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION)) {
|
||||||
// couldn't find it in the main cache, check the offline cache
|
// couldn't find it in the main cache, check the offline cache
|
||||||
|
|
||||||
|
@ -1545,10 +1550,12 @@ nsHttpChannel::CheckCache()
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
buf.Adopt(0);
|
buf.Adopt(0);
|
||||||
|
|
||||||
// If we were only granted read access, then assume the entry is valid.
|
// Don't bother to validate LOAD_ONLY_FROM_CACHE items.
|
||||||
// unless it is INHBIT_CACHING
|
// Don't bother to validate items that are read-only,
|
||||||
if (mCacheAccess == nsICache::ACCESS_READ &&
|
// unless they are read-only because of INHIBIT_CACHING.
|
||||||
!(mLoadFlags & INHIBIT_CACHING)) {
|
if (mLoadFlags & LOAD_ONLY_FROM_CACHE ||
|
||||||
|
(mCacheAccess == nsICache::ACCESS_READ &&
|
||||||
|
!(mLoadFlags & INHIBIT_CACHING))) {
|
||||||
mCachedContentIsValid = PR_TRUE;
|
mCachedContentIsValid = PR_TRUE;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче