Bug 367447. Support <link rel="offline-resource">. Patch by Dave Camp, r+sr=biesi
git-svn-id: svn://10.0.0.236/trunk@221859 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -661,7 +661,12 @@ nsContentSink::ProcessLink(nsIContent* aElement,
|
||||
PRBool hasPrefetch = (linkTypes.IndexOf(NS_LITERAL_STRING("prefetch")) != -1);
|
||||
// prefetch href if relation is "next" or "prefetch"
|
||||
if (hasPrefetch || linkTypes.IndexOf(NS_LITERAL_STRING("next")) != -1) {
|
||||
PrefetchHref(aHref, hasPrefetch);
|
||||
PrefetchHref(aHref, hasPrefetch, PR_FALSE);
|
||||
}
|
||||
|
||||
// fetch href into the offline cache if relation is "offline-resource"
|
||||
if (linkTypes.IndexOf(NS_LITERAL_STRING("offline-resource")) != -1) {
|
||||
PrefetchHref(aHref, PR_TRUE, PR_TRUE);
|
||||
}
|
||||
|
||||
// is it a stylesheet link?
|
||||
@@ -746,7 +751,9 @@ nsContentSink::ProcessMETATag(nsIContent* aContent)
|
||||
|
||||
|
||||
void
|
||||
nsContentSink::PrefetchHref(const nsAString &aHref, PRBool aExplicit)
|
||||
nsContentSink::PrefetchHref(const nsAString &aHref,
|
||||
PRBool aExplicit,
|
||||
PRBool aOffline)
|
||||
{
|
||||
//
|
||||
// SECURITY CHECK: disable prefetching from mailnews!
|
||||
@@ -789,12 +796,14 @@ nsContentSink::PrefetchHref(const nsAString &aHref, PRBool aExplicit)
|
||||
charset.IsEmpty() ? nsnull : PromiseFlatCString(charset).get(),
|
||||
mDocumentBaseURI);
|
||||
if (uri) {
|
||||
prefetchService->PrefetchURI(uri, mDocumentURI, aExplicit);
|
||||
if (aOffline)
|
||||
prefetchService->PrefetchURIForOfflineUse(uri, mDocumentURI, aExplicit);
|
||||
else
|
||||
prefetchService->PrefetchURI(uri, mDocumentURI, aExplicit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsContentSink::ScrollToRef()
|
||||
{
|
||||
|
||||
@@ -165,7 +165,7 @@ protected:
|
||||
const nsSubstring& aType,
|
||||
const nsSubstring& aMedia);
|
||||
|
||||
void PrefetchHref(const nsAString &aHref, PRBool aExplicit);
|
||||
void PrefetchHref(const nsAString &aHref, PRBool aExplicit, PRBool aOffline);
|
||||
|
||||
void ScrollToRef();
|
||||
nsresult RefreshIfEnabled(nsIViewManager* vm);
|
||||
|
||||
@@ -2996,7 +2996,14 @@ HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode)
|
||||
nsAutoString hrefVal;
|
||||
element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
|
||||
if (!hrefVal.IsEmpty()) {
|
||||
PrefetchHref(hrefVal, hasPrefetch);
|
||||
PrefetchHref(hrefVal, hasPrefetch, PR_FALSE);
|
||||
}
|
||||
}
|
||||
if (linkTypes.IndexOf(NS_LITERAL_STRING("offline-resource")) != -1) {
|
||||
nsAutoString hrefVal;
|
||||
element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
|
||||
if (!hrefVal.IsEmpty()) {
|
||||
PrefetchHref(hrefVal, PR_TRUE, PR_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,11 @@ pref("browser.cache.memory.enable", true);
|
||||
pref("browser.cache.disk_cache_ssl", false);
|
||||
// 0 = once-per-session, 1 = each-time, 2 = never, 3 = when-appropriate/automatically
|
||||
pref("browser.cache.check_doc_frequency", 3);
|
||||
|
||||
pref("browser.cache.offline.enable", true);
|
||||
// offline cache capacity in kilobytes
|
||||
pref("browser.cache.offline.capacity", 51200);
|
||||
|
||||
// Fastback caching - if this pref is negative, then we calculate the number
|
||||
// of content viewers to cache based on the amount of available memory.
|
||||
pref("browser.sessionhistory.max_total_viewers", -1);
|
||||
|
||||
@@ -50,7 +50,7 @@ interface nsIFile;
|
||||
* 3) Support for uniquely identifying cached data in cases when the URL
|
||||
* is insufficient (e.g., HTTP form submission).
|
||||
*/
|
||||
[scriptable, uuid(b1f95f5e-ee05-4434-9d34-89a935d7feef)]
|
||||
[scriptable, uuid(855bcc4d-0987-45b6-b138-3bf0bf407703)]
|
||||
interface nsICachingChannel : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -97,6 +97,14 @@ interface nsICachingChannel : nsISupports
|
||||
*/
|
||||
attribute boolean cacheAsFile;
|
||||
|
||||
/**
|
||||
* Specifies whether or not the data should be placed in the offline cache,
|
||||
* in addition to normal memory/disk caching. This may fail if the offline
|
||||
* cache is not present. The value of this attribute should be set before
|
||||
* opening the channel.
|
||||
*/
|
||||
attribute boolean cacheForOfflineUse;
|
||||
|
||||
/**
|
||||
* Get the "file" where the cached data can be found. This is valid for
|
||||
* as long as a reference to the cache token is held. This may return
|
||||
|
||||
@@ -106,6 +106,8 @@ public:
|
||||
return mContentSniffers.GetEntries();
|
||||
}
|
||||
|
||||
PRBool IsOffline() { return mOffline; }
|
||||
|
||||
private:
|
||||
// These shouldn't be called directly:
|
||||
// - construct using GetInstance
|
||||
|
||||
3
mozilla/netwerk/cache/public/nsICache.idl
vendored
3
mozilla/netwerk/cache/public/nsICache.idl
vendored
@@ -143,11 +143,14 @@ interface nsICache
|
||||
* storage (ie. typically on a system's hard disk).
|
||||
* STORE_ON_DISK_AS_FILE - Requires the cache entry to reside in persistent
|
||||
* storage, and in a separate file.
|
||||
* STORE_OFFLINE - Requires the cache entry to reside in persistent,
|
||||
* reliable storage for offline use.
|
||||
*/
|
||||
const nsCacheStoragePolicy STORE_ANYWHERE = 0;
|
||||
const nsCacheStoragePolicy STORE_IN_MEMORY = 1;
|
||||
const nsCacheStoragePolicy STORE_ON_DISK = 2;
|
||||
const nsCacheStoragePolicy STORE_ON_DISK_AS_FILE = 3;
|
||||
const nsCacheStoragePolicy STORE_OFFLINE = 4;
|
||||
|
||||
/**
|
||||
* All entries for a cache session are stored as streams of data or
|
||||
|
||||
2
mozilla/netwerk/cache/src/Makefile.in
vendored
2
mozilla/netwerk/cache/src/Makefile.in
vendored
@@ -88,6 +88,8 @@ CPPSRCS += \
|
||||
endif
|
||||
endif
|
||||
|
||||
LOCAL_INCLUDES=-I$(srcdir)/../../base/src
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
|
||||
|
||||
5
mozilla/netwerk/cache/src/nsCacheEntry.h
vendored
5
mozilla/netwerk/cache/src/nsCacheEntry.h
vendored
@@ -192,6 +192,11 @@ public:
|
||||
(StoragePolicy() == nsICache::STORE_ON_DISK_AS_FILE);
|
||||
}
|
||||
|
||||
PRBool IsAllowedOffline()
|
||||
{
|
||||
return (StoragePolicy() == nsICache::STORE_OFFLINE);
|
||||
}
|
||||
|
||||
nsCacheStoragePolicy StoragePolicy()
|
||||
{
|
||||
return (nsCacheStoragePolicy)(mFlags & eStoragePolicyMask);
|
||||
|
||||
260
mozilla/netwerk/cache/src/nsCacheService.cpp
vendored
260
mozilla/netwerk/cache/src/nsCacheService.cpp
vendored
@@ -60,6 +60,7 @@
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefBranch2.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsIOService.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@@ -82,6 +83,11 @@
|
||||
#define DISK_CACHE_MAX_ENTRY_SIZE_PREF "browser.cache.disk.max_entry_size"
|
||||
#define DISK_CACHE_CAPACITY 51200
|
||||
|
||||
#define OFFLINE_CACHE_ENABLE_PREF "browser.cache.offline.enable"
|
||||
#define OFFLINE_CACHE_DIR_PREF "browser.cache.offline.parent_directory"
|
||||
#define OFFLINE_CACHE_CAPACITY_PREF "browser.cache.offline.capacity"
|
||||
#define OFFLINE_CACHE_CAPACITY 51200
|
||||
|
||||
#define MEMORY_CACHE_ENABLE_PREF "browser.cache.memory.enable"
|
||||
#define MEMORY_CACHE_CAPACITY_PREF "browser.cache.memory.capacity"
|
||||
#define MEMORY_CACHE_MAX_ENTRY_SIZE_PREF "browser.cache.memory.max_entry_size"
|
||||
@@ -97,6 +103,8 @@ public:
|
||||
: mHaveProfile(PR_FALSE)
|
||||
, mDiskCacheEnabled(PR_FALSE)
|
||||
, mDiskCacheCapacity(0)
|
||||
, mOfflineCacheEnabled(PR_FALSE)
|
||||
, mOfflineCacheCapacity(0)
|
||||
, mMemoryCacheEnabled(PR_TRUE)
|
||||
, mMemoryCacheCapacity(-1)
|
||||
{
|
||||
@@ -111,6 +119,10 @@ public:
|
||||
PRBool DiskCacheEnabled();
|
||||
PRInt32 DiskCacheCapacity() { return mDiskCacheCapacity; }
|
||||
nsILocalFile * DiskCacheParentDirectory() { return mDiskCacheParentDirectory; }
|
||||
|
||||
PRBool OfflineCacheEnabled();
|
||||
PRInt32 OfflineCacheCapacity() { return mOfflineCacheCapacity; }
|
||||
nsILocalFile * OfflineCacheParentDirectory() { return mOfflineCacheParentDirectory; }
|
||||
|
||||
PRBool MemoryCacheEnabled();
|
||||
PRInt32 MemoryCacheCapacity();
|
||||
@@ -121,6 +133,10 @@ private:
|
||||
PRBool mDiskCacheEnabled;
|
||||
PRInt32 mDiskCacheCapacity;
|
||||
nsCOMPtr<nsILocalFile> mDiskCacheParentDirectory;
|
||||
|
||||
PRBool mOfflineCacheEnabled;
|
||||
PRInt32 mOfflineCacheCapacity;
|
||||
nsCOMPtr<nsILocalFile> mOfflineCacheParentDirectory;
|
||||
|
||||
PRBool mMemoryCacheEnabled;
|
||||
PRInt32 mMemoryCacheCapacity;
|
||||
@@ -159,6 +175,9 @@ nsCacheProfilePrefObserver::Install()
|
||||
DISK_CACHE_ENABLE_PREF,
|
||||
DISK_CACHE_CAPACITY_PREF,
|
||||
DISK_CACHE_DIR_PREF,
|
||||
OFFLINE_CACHE_ENABLE_PREF,
|
||||
OFFLINE_CACHE_CAPACITY_PREF,
|
||||
OFFLINE_CACHE_DIR_PREF,
|
||||
MEMORY_CACHE_ENABLE_PREF,
|
||||
MEMORY_CACHE_CAPACITY_PREF
|
||||
};
|
||||
@@ -210,6 +229,11 @@ nsCacheProfilePrefObserver::Remove()
|
||||
prefs->RemoveObserver(DISK_CACHE_CAPACITY_PREF, this);
|
||||
prefs->RemoveObserver(DISK_CACHE_DIR_PREF, this);
|
||||
|
||||
// remove Offline cache pref observers
|
||||
prefs->RemoveObserver(OFFLINE_CACHE_ENABLE_PREF, this);
|
||||
prefs->RemoveObserver(OFFLINE_CACHE_CAPACITY_PREF, this);
|
||||
prefs->RemoveObserver(OFFLINE_CACHE_DIR_PREF, this);
|
||||
|
||||
// remove Memory cache pref observers
|
||||
prefs->RemoveObserver(MEMORY_CACHE_ENABLE_PREF, this);
|
||||
prefs->RemoveObserver(MEMORY_CACHE_CAPACITY_PREF, this);
|
||||
@@ -278,7 +302,32 @@ nsCacheProfilePrefObserver::Observe(nsISupports * subject,
|
||||
// XXX the next time the profile changes (browser launch)
|
||||
#endif
|
||||
} else
|
||||
|
||||
// which preference changed?
|
||||
if (!strcmp(OFFLINE_CACHE_ENABLE_PREF, data.get())) {
|
||||
|
||||
rv = branch->GetBoolPref(OFFLINE_CACHE_ENABLE_PREF,
|
||||
&mOfflineCacheEnabled);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsCacheService::SetOfflineCacheEnabled(OfflineCacheEnabled());
|
||||
|
||||
} else if (!strcmp(OFFLINE_CACHE_CAPACITY_PREF, data.get())) {
|
||||
|
||||
PRInt32 capacity = 0;
|
||||
rv = branch->GetIntPref(OFFLINE_CACHE_CAPACITY_PREF, &capacity);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mOfflineCacheCapacity = PR_MAX(0, capacity);
|
||||
nsCacheService::SetOfflineCacheCapacity(mOfflineCacheCapacity);
|
||||
#if 0
|
||||
} else if (!strcmp(DISK_OFFLINE_DIR_PREF, data.get())) {
|
||||
// XXX We probaby don't want to respond to this pref except after
|
||||
// XXX profile changes. Ideally, there should be some kind of user
|
||||
// XXX notification that the pref change won't take effect until
|
||||
// XXX the next time the profile changes (browser launch)
|
||||
#endif
|
||||
} else
|
||||
#endif // !NECKO_DISK_CACHE
|
||||
|
||||
if (!strcmp(MEMORY_CACHE_ENABLE_PREF, data.get())) {
|
||||
|
||||
rv = branch->GetBoolPref(MEMORY_CACHE_ENABLE_PREF,
|
||||
@@ -356,6 +405,47 @@ nsCacheProfilePrefObserver::ReadPrefs(nsIPrefBranch* branch)
|
||||
if (directory)
|
||||
mDiskCacheParentDirectory = do_QueryInterface(directory, &rv);
|
||||
}
|
||||
|
||||
// read offline cache device prefs
|
||||
mOfflineCacheEnabled = PR_TRUE; // presume offline cache is enabled
|
||||
(void) branch->GetBoolPref(OFFLINE_CACHE_ENABLE_PREF,
|
||||
&mOfflineCacheEnabled);
|
||||
|
||||
mOfflineCacheCapacity = OFFLINE_CACHE_CAPACITY;
|
||||
(void)branch->GetIntPref(OFFLINE_CACHE_CAPACITY_PREF,
|
||||
&mOfflineCacheCapacity);
|
||||
mOfflineCacheCapacity = PR_MAX(0, mOfflineCacheCapacity);
|
||||
|
||||
(void) branch->GetComplexValue(OFFLINE_CACHE_DIR_PREF, // ignore error
|
||||
NS_GET_IID(nsILocalFile),
|
||||
getter_AddRefs(mOfflineCacheParentDirectory));
|
||||
|
||||
if (!mOfflineCacheParentDirectory) {
|
||||
nsCOMPtr<nsIFile> directory;
|
||||
|
||||
// try to get the offline cache parent directory
|
||||
rv = NS_GetSpecialDirectory(NS_APP_CACHE_PARENT_DIR,
|
||||
getter_AddRefs(directory));
|
||||
if (NS_FAILED(rv)) {
|
||||
// try to get the profile directory (there may not be a profile yet)
|
||||
nsCOMPtr<nsIFile> profDir;
|
||||
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(profDir));
|
||||
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR,
|
||||
getter_AddRefs(directory));
|
||||
if (!directory)
|
||||
directory = profDir;
|
||||
}
|
||||
#if DEBUG
|
||||
if (!directory) {
|
||||
// use current process directory during development
|
||||
rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
|
||||
getter_AddRefs(directory));
|
||||
}
|
||||
#endif
|
||||
if (directory)
|
||||
mOfflineCacheParentDirectory = do_QueryInterface(directory, &rv);
|
||||
}
|
||||
#endif // !NECKO_DISK_CACHE
|
||||
|
||||
// read memory cache device prefs
|
||||
@@ -376,7 +466,17 @@ nsCacheProfilePrefObserver::DiskCacheEnabled()
|
||||
return mDiskCacheEnabled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PRBool
|
||||
nsCacheProfilePrefObserver::OfflineCacheEnabled()
|
||||
{
|
||||
if ((mOfflineCacheCapacity == 0) || (!mOfflineCacheParentDirectory))
|
||||
return PR_FALSE;
|
||||
|
||||
return mOfflineCacheEnabled;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsCacheProfilePrefObserver::MemoryCacheEnabled()
|
||||
{
|
||||
@@ -472,6 +572,7 @@ nsCacheService::nsCacheService()
|
||||
mEnableDiskDevice(PR_TRUE),
|
||||
mMemoryDevice(nsnull),
|
||||
mDiskDevice(nsnull),
|
||||
mOfflineDevice(nsnull),
|
||||
mTotalEntries(0),
|
||||
mCacheHits(0),
|
||||
mCacheMisses(0),
|
||||
@@ -527,9 +628,10 @@ nsCacheService::Init()
|
||||
NS_ADDREF(mObserver);
|
||||
|
||||
mObserver->Install();
|
||||
mEnableDiskDevice = mObserver->DiskCacheEnabled();
|
||||
mEnableMemoryDevice = mObserver->MemoryCacheEnabled();
|
||||
|
||||
mEnableDiskDevice = mObserver->DiskCacheEnabled();
|
||||
mEnableOfflineDevice = mObserver->OfflineCacheEnabled();
|
||||
mEnableMemoryDevice = mObserver->MemoryCacheEnabled();
|
||||
|
||||
mInitialized = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -561,10 +663,13 @@ nsCacheService::Shutdown()
|
||||
delete mDiskDevice;
|
||||
mDiskDevice = nsnull;
|
||||
|
||||
delete mOfflineDevice;
|
||||
mOfflineDevice = nsnull;
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
LogCacheStatistics();
|
||||
#endif
|
||||
#endif
|
||||
#endif // !NECKO_DISK_CACHE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,7 +765,19 @@ nsCacheService::EvictEntriesForClient(const char * clientID,
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
}
|
||||
#endif // !NECKO_DISK_CACHE
|
||||
|
||||
if (storagePolicy == nsICache::STORE_ANYWHERE ||
|
||||
storagePolicy == nsICache::STORE_OFFLINE) {
|
||||
if (mEnableOfflineDevice) {
|
||||
if (!mOfflineDevice) {
|
||||
rv = CreateOfflineDevice();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
rv = mOfflineDevice->EvictEntries(clientID);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
}
|
||||
#endif // ! NECKO_DISK_CACHE
|
||||
|
||||
if (storagePolicy == nsICache::STORE_ANYWHERE ||
|
||||
storagePolicy == nsICache::STORE_IN_MEMORY) {
|
||||
@@ -702,6 +819,10 @@ nsCacheService::IsStorageEnabledForPolicy_Locked(nsCacheStoragePolicy storagePo
|
||||
storagePolicy == nsICache::STORE_ON_DISK_AS_FILE)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (gService->mEnableOfflineDevice &&
|
||||
storagePolicy == nsICache::STORE_OFFLINE) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
@@ -735,6 +856,15 @@ NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor)
|
||||
rv = mDiskDevice->Visit(visitor);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (mEnableOfflineDevice) {
|
||||
if (!mOfflineDevice) {
|
||||
rv = CreateOfflineDevice();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
rv = mOfflineDevice->Visit(visitor);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
#endif // !NECKO_DISK_CACHE
|
||||
|
||||
// XXX notify any shutdown process that visitation is complete for THIS visitor.
|
||||
@@ -786,6 +916,39 @@ nsCacheService::CreateDiskDevice()
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheService::CreateOfflineDevice()
|
||||
{
|
||||
#ifdef NECKO_DISK_CACHE
|
||||
CACHE_LOG_ALWAYS(("Creating offline device"));
|
||||
|
||||
// XXX: want a sql-based device
|
||||
if (!mEnableOfflineDevice) return NS_ERROR_NOT_AVAILABLE;
|
||||
if (mOfflineDevice) return NS_OK;
|
||||
|
||||
mOfflineDevice = new nsDiskCacheDevice;
|
||||
if (!mOfflineDevice) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// set the preferences
|
||||
mOfflineDevice->SetCacheParentDirectoryAndName(mObserver->OfflineCacheParentDirectory(),
|
||||
NS_LITERAL_CSTRING("OfflineCache"));
|
||||
mOfflineDevice->SetCapacity(mObserver->OfflineCacheCapacity());
|
||||
|
||||
nsresult rv = mOfflineDevice->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
CACHE_LOG_DEBUG(("mOfflineDevice->Init() failed (0x%.8x)\n", rv));
|
||||
CACHE_LOG_DEBUG((" - disabling offline cache for this session.\n"));
|
||||
|
||||
mEnableOfflineDevice = PR_FALSE;
|
||||
delete mOfflineDevice;
|
||||
mOfflineDevice = nsnull;
|
||||
}
|
||||
return rv;
|
||||
#else // !NECKO_DISK_CACHE
|
||||
NS_NOTREACHED("nsCacheService::CreateOfflineDevice");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheService::CreateMemoryDevice()
|
||||
@@ -1115,6 +1278,23 @@ nsCacheService::SearchCacheDevices(nsCString * key, nsCacheStoragePolicy policy,
|
||||
#endif // !NECKO_DISK_CACHE
|
||||
}
|
||||
|
||||
if (!entry && (policy == nsICache::STORE_OFFLINE ||
|
||||
(policy == nsICache::STORE_ANYWHERE &&
|
||||
gIOService->IsOffline()))) {
|
||||
|
||||
#ifdef NECKO_DISK_CACHE
|
||||
if (mEnableOfflineDevice) {
|
||||
if (!mOfflineDevice) {
|
||||
nsresult rv = CreateOfflineDevice();
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
entry = mOfflineDevice->FindEntry(key, collision);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -1156,6 +1336,23 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NECKO_DISK_CACHE
|
||||
if (!device && entry->IsStreamData() &&
|
||||
entry->IsAllowedOffline() && mEnableOfflineDevice) {
|
||||
if (!mOfflineDevice) {
|
||||
(void)CreateOfflineDevice(); // ignore the error (check for mOfflineDevice instead)
|
||||
}
|
||||
|
||||
if (mOfflineDevice) {
|
||||
entry->MarkBinding();
|
||||
nsresult rv = mOfflineDevice->BindEntry(entry);
|
||||
entry->ClearBinding();
|
||||
if (NS_SUCCEEDED(rv))
|
||||
device = mOfflineDevice;
|
||||
}
|
||||
}
|
||||
#endif // ! NECKO_DISK_CACHE
|
||||
|
||||
if (device)
|
||||
entry->SetCacheDevice(device);
|
||||
return device;
|
||||
@@ -1219,6 +1416,14 @@ nsCacheService::OnProfileShutdown(PRBool cleanse)
|
||||
gService->mDiskDevice->Shutdown();
|
||||
gService->mEnableDiskDevice = PR_FALSE;
|
||||
}
|
||||
|
||||
if (gService->mOfflineDevice && gService->mEnableOfflineDevice) {
|
||||
if (cleanse)
|
||||
gService->mOfflineDevice->EvictEntries(nsnull);
|
||||
|
||||
gService->mOfflineDevice->Shutdown();
|
||||
gService->mEnableOfflineDevice = PR_FALSE;
|
||||
}
|
||||
#endif // !NECKO_DISK_CACHE
|
||||
|
||||
if (gService->mMemoryDevice) {
|
||||
@@ -1236,9 +1441,10 @@ nsCacheService::OnProfileChanged()
|
||||
|
||||
nsCacheServiceAutoLock lock;
|
||||
|
||||
gService->mEnableDiskDevice = gService->mObserver->DiskCacheEnabled();
|
||||
gService->mEnableMemoryDevice = gService->mObserver->MemoryCacheEnabled();
|
||||
|
||||
gService->mEnableDiskDevice = gService->mObserver->DiskCacheEnabled();
|
||||
gService->mEnableOfflineDevice = gService->mObserver->OfflineCacheEnabled();
|
||||
gService->mEnableMemoryDevice = gService->mObserver->MemoryCacheEnabled();
|
||||
|
||||
#ifdef NECKO_DISK_CACHE
|
||||
if (gService->mDiskDevice) {
|
||||
gService->mDiskDevice->SetCacheParentDirectory(gService->mObserver->DiskCacheParentDirectory());
|
||||
@@ -1252,6 +1458,19 @@ nsCacheService::OnProfileChanged()
|
||||
// XXX delete mDiskDevice?
|
||||
}
|
||||
}
|
||||
|
||||
if (gService->mOfflineDevice) {
|
||||
gService->mOfflineDevice->SetCacheParentDirectory(gService->mObserver->OfflineCacheParentDirectory());
|
||||
gService->mOfflineDevice->SetCapacity(gService->mObserver->OfflineCacheCapacity());
|
||||
|
||||
// XXX initialization of mOfflineDevice could be made lazily, if mEnableOfflineDevice is false
|
||||
nsresult rv = gService->mOfflineDevice->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("nsCacheService::OnProfileChanged: Re-initializing offline device failed");
|
||||
gService->mEnableOfflineDevice = PR_FALSE;
|
||||
// XXX delete mOfflineDevice?
|
||||
}
|
||||
}
|
||||
#endif // !NECKO_DISK_CACHE
|
||||
|
||||
// If memoryDevice exists, reset its size to the new profile
|
||||
@@ -1292,6 +1511,29 @@ nsCacheService::SetDiskCacheCapacity(PRInt32 capacity)
|
||||
gService->mEnableDiskDevice = gService->mObserver->DiskCacheEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
nsCacheService::SetOfflineCacheEnabled(PRBool enabled)
|
||||
{
|
||||
if (!gService) return;
|
||||
nsCacheServiceAutoLock lock;
|
||||
gService->mEnableOfflineDevice = enabled;
|
||||
}
|
||||
|
||||
void
|
||||
nsCacheService::SetOfflineCacheCapacity(PRInt32 capacity)
|
||||
{
|
||||
if (!gService) return;
|
||||
nsCacheServiceAutoLock lock;
|
||||
|
||||
#ifdef NECKO_DISK_CACHE
|
||||
if (gService->mOfflineDevice) {
|
||||
gService->mOfflineDevice->SetCapacity(capacity);
|
||||
}
|
||||
#endif // !NECKO_DISK_CACHE
|
||||
|
||||
gService->mEnableOfflineDevice = gService->mObserver->OfflineCacheEnabled();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsCacheService::SetMemoryCache()
|
||||
|
||||
6
mozilla/netwerk/cache/src/nsCacheService.h
vendored
6
mozilla/netwerk/cache/src/nsCacheService.h
vendored
@@ -150,6 +150,9 @@ public:
|
||||
static void SetDiskCacheEnabled(PRBool enabled);
|
||||
static void SetDiskCacheCapacity(PRInt32 capacity);
|
||||
|
||||
static void SetOfflineCacheEnabled(PRBool enabled);
|
||||
static void SetOfflineCacheCapacity(PRInt32 capacity);
|
||||
|
||||
static void SetMemoryCache();
|
||||
|
||||
nsresult Init();
|
||||
@@ -165,6 +168,7 @@ private:
|
||||
static void Unlock();
|
||||
|
||||
nsresult CreateDiskDevice();
|
||||
nsresult CreateOfflineDevice();
|
||||
nsresult CreateMemoryDevice();
|
||||
|
||||
nsresult CreateRequest(nsCacheSession * session,
|
||||
@@ -240,9 +244,11 @@ private:
|
||||
|
||||
PRBool mEnableMemoryDevice;
|
||||
PRBool mEnableDiskDevice;
|
||||
PRBool mEnableOfflineDevice;
|
||||
|
||||
nsMemoryCacheDevice * mMemoryDevice;
|
||||
nsDiskCacheDevice * mDiskDevice;
|
||||
nsDiskCacheDevice * mOfflineDevice;
|
||||
|
||||
nsCacheEntryHashTable mActiveEntries;
|
||||
PRCList mDoomedEntries;
|
||||
|
||||
37
mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp
vendored
37
mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp
vendored
@@ -929,6 +929,43 @@ nsDiskCacheDevice::SetCacheParentDirectory(nsILocalFile * parentDir)
|
||||
mCacheDirectory = do_QueryInterface(directory);
|
||||
}
|
||||
|
||||
// XXX: This is here to support the offline cache, and can be removed
|
||||
// XXX: once it has its own cache implementation
|
||||
void
|
||||
nsDiskCacheDevice::SetCacheParentDirectoryAndName(nsILocalFile * parentDir,
|
||||
const nsACString & str)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool exists;
|
||||
|
||||
if (Initialized()) {
|
||||
NS_ASSERTION(PR_FALSE, "Cannot switch cache directory when initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!parentDir) {
|
||||
mCacheDirectory = nsnull;
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure parent directory exists
|
||||
rv = parentDir->Exists(&exists);
|
||||
if (NS_SUCCEEDED(rv) && !exists)
|
||||
rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
if (NS_FAILED(rv)) return;
|
||||
|
||||
// ensure cache directory exists
|
||||
nsCOMPtr<nsIFile> directory;
|
||||
|
||||
rv = parentDir->Clone(getter_AddRefs(directory));
|
||||
if (NS_FAILED(rv)) return;
|
||||
rv = directory->AppendNative(str);
|
||||
if (NS_FAILED(rv)) return;
|
||||
|
||||
mCacheDirectory = do_QueryInterface(directory);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
nsDiskCacheDevice::getCacheDirectory(nsILocalFile ** result)
|
||||
|
||||
@@ -93,6 +93,10 @@ public:
|
||||
void SetCacheParentDirectory(nsILocalFile * parentDir);
|
||||
void SetCapacity(PRUint32 capacity);
|
||||
|
||||
// XXX: This is here to support the offline cache, and can be removed
|
||||
// XXX: once it has its own cache implementation
|
||||
void SetCacheParentDirectoryAndName(nsILocalFile * parentDir,
|
||||
const nsACString & str);
|
||||
|
||||
/* private: */
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ nsHttpChannel::nsHttpChannel()
|
||||
, mSuppressDefensiveAuth(PR_FALSE)
|
||||
, mResuming(PR_FALSE)
|
||||
, mInitedCacheEntry(PR_FALSE)
|
||||
, mCacheForOfflineUse(PR_FALSE)
|
||||
{
|
||||
LOG(("Creating nsHttpChannel @%x\n", this));
|
||||
|
||||
@@ -267,14 +268,9 @@ 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 = gHttpHandler->GetIOService(getter_AddRefs(ioService));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
ioService->GetOffline(&offline);
|
||||
// are we offline?
|
||||
PRBool offline = gIOService->IsOffline();
|
||||
if (offline)
|
||||
mLoadFlags |= LOAD_ONLY_FROM_CACHE;
|
||||
else if (PL_strcmp(mConnectionInfo->ProxyType(), "unknown") == 0)
|
||||
@@ -297,7 +293,14 @@ nsHttpChannel::Connect(PRBool firstTime)
|
||||
return NS_ERROR_DOCUMENT_NOT_CACHED;
|
||||
// otherwise, let's just proceed without using the cache.
|
||||
}
|
||||
|
||||
|
||||
// if cacheForOfflineUse has been set, open up an offline cache
|
||||
// entry to update
|
||||
if (mCacheForOfflineUse) {
|
||||
rv = OpenOfflineCacheEntryForWriting();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && delayed)
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -785,6 +788,12 @@ nsHttpChannel::ProcessResponse()
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
InitCacheEntry();
|
||||
CloseCacheEntry();
|
||||
|
||||
if (mCacheForOfflineUse) {
|
||||
// Store response in the offline cache
|
||||
InitOfflineCacheEntry();
|
||||
CloseOfflineCacheEntry();
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG(("ProcessRedirection failed [rv=%x]\n", rv));
|
||||
@@ -884,8 +893,30 @@ nsHttpChannel::ProcessNormal()
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// install cache listener if we still have a cache entry open
|
||||
if (mCacheEntry && (mCacheAccess & nsICache::ACCESS_WRITE))
|
||||
if (mCacheEntry && (mCacheAccess & nsICache::ACCESS_WRITE)) {
|
||||
rv = InstallCacheListener();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
// create offline cache entry if offline caching was requested
|
||||
if (mCacheForOfflineUse) {
|
||||
PRBool shouldCacheForOfflineUse;
|
||||
rv = ShouldUpdateOfflineCacheEntry(&shouldCacheForOfflineUse);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (shouldCacheForOfflineUse) {
|
||||
LOG(("writing to the offline cache"));
|
||||
rv = InitOfflineCacheEntry();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mOfflineCacheEntry) {
|
||||
rv = InstallOfflineCacheListener();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
} else {
|
||||
LOG(("offline cache is up to date, not updating"));
|
||||
CloseOfflineCacheEntry();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -1262,10 +1293,6 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
|
||||
storagePolicy = nsICache::STORE_IN_MEMORY;
|
||||
else
|
||||
storagePolicy = nsICache::STORE_ANYWHERE; // allow on disk
|
||||
nsCOMPtr<nsICacheSession> session;
|
||||
rv = gHttpHandler->GetCacheSession(storagePolicy,
|
||||
getter_AddRefs(session));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Set the desired cache access mode accordingly...
|
||||
nsCacheAccessMode accessRequested;
|
||||
@@ -1281,11 +1308,30 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
|
||||
else
|
||||
accessRequested = nsICache::ACCESS_READ_WRITE; // normal browsing
|
||||
|
||||
nsCOMPtr<nsICacheSession> session;
|
||||
rv = gHttpHandler->GetCacheSession(storagePolicy,
|
||||
getter_AddRefs(session));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// we'll try to synchronously open the cache entry... however, it may be
|
||||
// in use and not yet validated, in which case we'll try asynchronously
|
||||
// opening the cache entry.
|
||||
rv = session->OpenCacheEntry(cacheKey, accessRequested, PR_FALSE,
|
||||
getter_AddRefs(mCacheEntry));
|
||||
|
||||
if (offline &&
|
||||
!(NS_SUCCEEDED(rv) || rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION)) {
|
||||
// couldn't find it in the main cache, check the offline cache
|
||||
|
||||
storagePolicy = nsICache::STORE_OFFLINE;
|
||||
rv = gHttpHandler->GetCacheSession(storagePolicy,
|
||||
getter_AddRefs(session));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = session->OpenCacheEntry(cacheKey, accessRequested, PR_FALSE,
|
||||
getter_AddRefs(mCacheEntry));
|
||||
}
|
||||
|
||||
if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
|
||||
// access to the cache entry has been denied (because the cache entry
|
||||
// is probably in use by another channel).
|
||||
@@ -1305,6 +1351,66 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::OpenOfflineCacheEntryForWriting()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
LOG(("nsHttpChannel::OpenOfflineCacheEntryForWriting [this=%x]", this));
|
||||
|
||||
// make sure we're not abusing this function
|
||||
NS_PRECONDITION(!mOfflineCacheEntry, "cache entry already open");
|
||||
|
||||
PRBool offline = gIOService->IsOffline();
|
||||
if (offline) {
|
||||
// only put things in the offline cache while online
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mRequestHead.Method() != nsHttp::Get) {
|
||||
// only cache complete documents offline
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mRequestHead.PeekHeader(nsHttp::Range)) {
|
||||
// we don't support caching for byte range requests initiated
|
||||
// by our clients or via nsIResumableChannel.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (RequestIsConditional()) {
|
||||
// don't use the cache if our consumer is making a conditional request
|
||||
// (see bug 331825).
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCAutoString cacheKey;
|
||||
GenerateCacheKey(cacheKey);
|
||||
|
||||
nsCOMPtr<nsICacheSession> session;
|
||||
rv = gHttpHandler->GetCacheSession(nsICache::STORE_OFFLINE,
|
||||
getter_AddRefs(session));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = session->OpenCacheEntry(cacheKey, nsICache::ACCESS_READ_WRITE,
|
||||
PR_FALSE, getter_AddRefs(mOfflineCacheEntry));
|
||||
|
||||
if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
|
||||
// access to the cache entry has been denied (because the cache entry
|
||||
// is probably in use by another channel). Either the cache is being
|
||||
// read from (we're offline) or it's being updated elsewhere.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mOfflineCacheEntry->GetAccessGranted(&mOfflineCacheAccess);
|
||||
LOG(("got offline cache entry [access=%x]\n", mOfflineCacheAccess));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::GenerateCacheKey(nsACString &cacheKey)
|
||||
{
|
||||
@@ -1597,6 +1703,48 @@ nsHttpChannel::CheckCache()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ShouldUpdateOfflineCacheEntry(PRBool *shouldCacheForOfflineUse)
|
||||
{
|
||||
*shouldCacheForOfflineUse = PR_FALSE;
|
||||
|
||||
if (!mOfflineCacheEntry) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// if we're updating the cache entry, update the offline cache entry too
|
||||
if (mCacheEntry && (mCacheAccess & nsICache::ACCESS_WRITE)) {
|
||||
*shouldCacheForOfflineUse = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// if there's nothing in the offline cache, add it
|
||||
if (mOfflineCacheEntry && (mOfflineCacheAccess == nsICache::ACCESS_WRITE)) {
|
||||
*shouldCacheForOfflineUse = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// if the document is newer than the offline entry, update it
|
||||
PRUint32 docLastModifiedTime;
|
||||
nsresult rv = mResponseHead->GetLastModifiedValue(&docLastModifiedTime);
|
||||
if (NS_FAILED(rv)) {
|
||||
*shouldCacheForOfflineUse = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32 offlineLastModifiedTime;
|
||||
rv = mOfflineCacheEntry->GetLastModified(&offlineLastModifiedTime);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (docLastModifiedTime > offlineLastModifiedTime) {
|
||||
*shouldCacheForOfflineUse = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If the data in the cache hasn't expired, then there's no need to
|
||||
// talk with the server, not even to do an if-modified-since. This
|
||||
// method creates a stream from the cache, synthesizing all the various
|
||||
@@ -1641,8 +1789,18 @@ nsHttpChannel::ReadFromCache()
|
||||
|
||||
// have we been configured to skip reading from the cache?
|
||||
if ((mLoadFlags & LOAD_ONLY_IF_MODIFIED) && !mCachedContentIsPartial) {
|
||||
LOG(("skipping read from cache based on LOAD_ONLY_IF_MODIFIED load flag\n"));
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncNotModified);
|
||||
// if offline caching has been requested and the offline cache needs
|
||||
// updating, complete the call even if the main cache entry is
|
||||
// up-to-date
|
||||
PRBool shouldUpdateOffline;
|
||||
if (!mCacheForOfflineUse ||
|
||||
NS_FAILED(ShouldUpdateOfflineCacheEntry(&shouldUpdateOffline)) ||
|
||||
!shouldUpdateOffline) {
|
||||
|
||||
LOG(("skipping read from cache based on LOAD_ONLY_IF_MODIFIED "
|
||||
"load flag\n"));
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncNotModified);
|
||||
}
|
||||
}
|
||||
|
||||
// open input stream for reading...
|
||||
@@ -1697,6 +1855,24 @@ nsHttpChannel::CloseCacheEntry()
|
||||
mInitedCacheEntry = PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsHttpChannel::CloseOfflineCacheEntry()
|
||||
{
|
||||
if (!mOfflineCacheEntry)
|
||||
return;
|
||||
|
||||
LOG(("nsHttpChannel::CloseOfflineCacheEntry [this=%x]", this));
|
||||
|
||||
if (NS_FAILED(mStatus)) {
|
||||
mOfflineCacheEntry->Doom();
|
||||
}
|
||||
|
||||
mOfflineCacheEntry = 0;
|
||||
mOfflineCacheAccess = 0;
|
||||
}
|
||||
|
||||
|
||||
// Initialize the cache entry for writing.
|
||||
// - finalize storage policy
|
||||
// - store security info
|
||||
@@ -1731,21 +1907,52 @@ nsHttpChannel::InitCacheEntry()
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// Store secure data in memory only
|
||||
if (mSecurityInfo)
|
||||
mCacheEntry->SetSecurityInfo(mSecurityInfo);
|
||||
|
||||
// Set the expiration time for this cache entry
|
||||
rv = UpdateExpirationTime();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = AddCacheEntryHeaders(mCacheEntry);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mInitedCacheEntry = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::InitOfflineCacheEntry()
|
||||
{
|
||||
if (!mOfflineCacheEntry) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mResponseHead->NoStore()) {
|
||||
CloseOfflineCacheEntry();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return AddCacheEntryHeaders(mOfflineCacheEntry);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::AddCacheEntryHeaders(nsICacheEntryDescriptor *entry)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Store secure data in memory only
|
||||
if (mSecurityInfo)
|
||||
entry->SetSecurityInfo(mSecurityInfo);
|
||||
|
||||
// Store the HTTP request method with the cache entry so we can distinguish
|
||||
// for example GET and HEAD responses.
|
||||
rv = mCacheEntry->SetMetaDataElement("request-method", mRequestHead.Method().get());
|
||||
rv = entry->SetMetaDataElement("request-method",
|
||||
mRequestHead.Method().get());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Store the HTTP authorization scheme used if any...
|
||||
rv = StoreAuthorizationMetaData();
|
||||
rv = StoreAuthorizationMetaData(entry);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Iterate over the headers listed in the Vary response header, and
|
||||
@@ -1773,7 +1980,7 @@ nsHttpChannel::InitCacheEntry()
|
||||
if (requestVal) {
|
||||
// build cache meta data key and set meta data element...
|
||||
metaKey = prefix + nsDependentCString(token);
|
||||
mCacheEntry->SetMetaDataElement(metaKey.get(), requestVal);
|
||||
entry->SetMetaDataElement(metaKey.get(), requestVal);
|
||||
}
|
||||
}
|
||||
token = nsCRT::strtok(val, NS_HTTP_HEADER_SEPS, &val);
|
||||
@@ -1786,22 +1993,20 @@ nsHttpChannel::InitCacheEntry()
|
||||
// the meta data.
|
||||
nsCAutoString head;
|
||||
mResponseHead->Flatten(head, PR_TRUE);
|
||||
rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = entry->SetMetaDataElement("response-head", head.get());
|
||||
|
||||
mInitedCacheEntry = PR_TRUE;
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::StoreAuthorizationMetaData()
|
||||
nsHttpChannel::StoreAuthorizationMetaData(nsICacheEntryDescriptor *entry)
|
||||
{
|
||||
// Not applicable to proxy authorization...
|
||||
const char *val = mRequestHead.PeekHeader(nsHttp::Authorization);
|
||||
if (val) {
|
||||
// eg. [Basic realm="wally world"]
|
||||
nsCAutoString buf(Substring(val, strchr(val, ' ')));
|
||||
return mCacheEntry->SetMetaDataElement("auth", buf.get());
|
||||
return entry->SetMetaDataElement("auth", buf.get());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1857,6 +2062,33 @@ nsHttpChannel::InstallCacheListener(PRUint32 offset)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::InstallOfflineCacheListener()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
LOG(("Preparing to write data into the offline cache [uri=%s]\n",
|
||||
mSpec.get()));
|
||||
|
||||
NS_ASSERTION(mOfflineCacheEntry, "no offline cache entry");
|
||||
NS_ASSERTION(mListener, "no listener");
|
||||
|
||||
nsCOMPtr<nsIOutputStream> out;
|
||||
rv = mOfflineCacheEntry->OpenOutputStream(0, getter_AddRefs(out));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIStreamListenerTee> tee =
|
||||
do_CreateInstance(kStreamListenerTeeCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = tee->Init(mListener, out);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mListener = tee;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel <redirect>
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -4059,6 +4291,9 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
|
||||
if (mCacheEntry)
|
||||
CloseCacheEntry();
|
||||
|
||||
if (mOfflineCacheEntry)
|
||||
CloseOfflineCacheEntry();
|
||||
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->RemoveRequest(this, nsnull, status);
|
||||
|
||||
@@ -4257,6 +4492,23 @@ nsHttpChannel::SetCacheAsFile(PRBool value)
|
||||
return mCacheEntry->SetStoragePolicy(policy);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::GetCacheForOfflineUse(PRBool *value)
|
||||
{
|
||||
*value = mCacheForOfflineUse;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::SetCacheForOfflineUse(PRBool value)
|
||||
{
|
||||
mCacheForOfflineUse = value;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::GetCacheFile(nsIFile **cacheFile)
|
||||
{
|
||||
|
||||
@@ -173,15 +173,21 @@ private:
|
||||
|
||||
// cache specific methods
|
||||
nsresult OpenCacheEntry(PRBool offline, PRBool *delayed);
|
||||
nsresult OpenOfflineCacheEntryForWriting();
|
||||
nsresult GenerateCacheKey(nsACString &key);
|
||||
nsresult UpdateExpirationTime();
|
||||
nsresult CheckCache();
|
||||
nsresult ShouldUpdateOfflineCacheEntry(PRBool *shouldCacheForOfflineUse);
|
||||
nsresult ReadFromCache();
|
||||
void CloseCacheEntry();
|
||||
void CloseOfflineCacheEntry();
|
||||
nsresult InitCacheEntry();
|
||||
nsresult StoreAuthorizationMetaData();
|
||||
nsresult InitOfflineCacheEntry();
|
||||
nsresult AddCacheEntryHeaders(nsICacheEntryDescriptor *entry);
|
||||
nsresult StoreAuthorizationMetaData(nsICacheEntryDescriptor *entry);
|
||||
nsresult FinalizeCacheEntry();
|
||||
nsresult InstallCacheListener(PRUint32 offset = 0);
|
||||
nsresult InstallOfflineCacheListener();
|
||||
|
||||
// byte range request specific methods
|
||||
nsresult SetupByteRangeRequest(PRUint32 partialLen);
|
||||
@@ -247,6 +253,9 @@ private:
|
||||
PRUint32 mPostID;
|
||||
PRUint32 mRequestTime;
|
||||
|
||||
nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry;
|
||||
nsCacheAccessMode mOfflineCacheAccess;
|
||||
|
||||
// auth specific data
|
||||
nsISupports *mProxyAuthContinuationState;
|
||||
nsCString mProxyAuthType;
|
||||
@@ -276,6 +285,7 @@ private:
|
||||
PRUint32 mSuppressDefensiveAuth : 1;
|
||||
PRUint32 mResuming : 1;
|
||||
PRUint32 mInitedCacheEntry : 1;
|
||||
PRUint32 mCacheForOfflineUse : 1;
|
||||
|
||||
class nsContentEncodings : public nsIUTF8StringEnumerator
|
||||
{
|
||||
|
||||
@@ -428,10 +428,21 @@ nsHttpHandler::GetCacheSession(nsCacheStoragePolicy storagePolicy,
|
||||
|
||||
rv = mCacheSession_MEM->SetDoomEntriesIfExpired(PR_FALSE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = serv->CreateSession("HTTP-offline",
|
||||
nsICache::STORE_OFFLINE,
|
||||
nsICache::STREAM_BASED,
|
||||
getter_AddRefs(mCacheSession_OFFLINE));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mCacheSession_OFFLINE->SetDoomEntriesIfExpired(PR_FALSE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (storagePolicy == nsICache::STORE_IN_MEMORY)
|
||||
NS_ADDREF(*result = mCacheSession_MEM);
|
||||
else if (storagePolicy == nsICache::STORE_OFFLINE)
|
||||
NS_ADDREF(*result = mCacheSession_OFFLINE);
|
||||
else
|
||||
NS_ADDREF(*result = mCacheSession_ANY);
|
||||
|
||||
|
||||
@@ -269,6 +269,7 @@ private:
|
||||
// cache support
|
||||
nsCOMPtr<nsICacheSession> mCacheSession_ANY;
|
||||
nsCOMPtr<nsICacheSession> mCacheSession_MEM;
|
||||
nsCOMPtr<nsICacheSession> mCacheSession_OFFLINE;
|
||||
PRUint32 mLastUniqueID;
|
||||
PRUint32 mSessionStartTime;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
interface nsIURI;
|
||||
|
||||
[scriptable, uuid(933cb52a-2864-4a40-8678-a2d0851b0ef4)]
|
||||
[scriptable, uuid(ae241be6-3cb6-47ec-9e38-2d89bc22042a)]
|
||||
interface nsIPrefetchService : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -51,5 +51,17 @@ interface nsIPrefetchService : nsISupports
|
||||
*/
|
||||
void prefetchURI(in nsIURI aURI, in nsIURI aReferrerURI, in boolean aExplicit);
|
||||
|
||||
/**
|
||||
* Enqueue a request to prefetch the specified URI, making sure it's in the
|
||||
* offline cache.
|
||||
*
|
||||
* @param aURI the URI of the document to prefetch
|
||||
* @param aReferrerURI the URI of the referring page
|
||||
* @param aExplicit the link element has an explicit offline link type
|
||||
*/
|
||||
void prefetchURIForOfflineUse(in nsIURI aURI,
|
||||
in nsIURI aReferrerURI,
|
||||
in boolean aExplicit);
|
||||
|
||||
// XXX do we need a way to cancel prefetch requests?
|
||||
};
|
||||
|
||||
@@ -144,34 +144,44 @@ nsPrefetchListener::OnStartRequest(nsIRequest *aRequest,
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsICachingChannel> cachingChannel(do_QueryInterface(aRequest, &rv));
|
||||
nsCOMPtr<nsICachingChannel> cachingChannel =
|
||||
do_QueryInterface(aRequest, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// no need to prefetch a document that is already in the cache
|
||||
PRBool fromCache;
|
||||
if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) && fromCache) {
|
||||
LOG(("document is already in the cache; canceling prefetch\n"));
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// no need to prefetch a document that must be requested fresh each
|
||||
// and every time.
|
||||
//
|
||||
nsCOMPtr<nsISupports> cacheToken;
|
||||
cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
|
||||
if (!cacheToken)
|
||||
return NS_ERROR_ABORT; // bail, no cache entry
|
||||
|
||||
nsCOMPtr<nsICacheEntryInfo> entryInfo(do_QueryInterface(cacheToken, &rv));
|
||||
PRBool cacheForOfflineUse;
|
||||
rv = cachingChannel->GetCacheForOfflineUse(&cacheForOfflineUse);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 expTime;
|
||||
if (NS_SUCCEEDED(entryInfo->GetExpirationTime(&expTime))) {
|
||||
if (NowInSeconds() >= expTime) {
|
||||
LOG(("document cannot be reused from cache; canceling prefetch\n"));
|
||||
if (!cacheForOfflineUse) {
|
||||
// no need to prefetch a document that is already in the cache
|
||||
PRBool fromCache;
|
||||
if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) &&
|
||||
fromCache) {
|
||||
LOG(("document is already in the cache; canceling prefetch\n"));
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// no need to prefetch a document that must be requested fresh each
|
||||
// and every time.
|
||||
//
|
||||
nsCOMPtr<nsISupports> cacheToken;
|
||||
cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
|
||||
if (!cacheToken)
|
||||
return NS_ERROR_ABORT; // bail, no cache entry
|
||||
|
||||
nsCOMPtr<nsICacheEntryInfo> entryInfo =
|
||||
do_QueryInterface(cacheToken, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 expTime;
|
||||
if (NS_SUCCEEDED(entryInfo->GetExpirationTime(&expTime))) {
|
||||
if (NowInSeconds() >= expTime) {
|
||||
LOG(("document cannot be reused from cache; "
|
||||
"canceling prefetch\n"));
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -230,11 +240,26 @@ nsPrefetchListener::OnChannelRedirect(nsIChannel *aOldChannel,
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PRBool offline;
|
||||
nsCOMPtr<nsICachingChannel> oldCachingChannel =
|
||||
do_QueryInterface(aOldChannel);
|
||||
if (NS_SUCCEEDED(oldCachingChannel->GetCacheForOfflineUse(&offline)) &&
|
||||
offline) {
|
||||
nsCOMPtr<nsICachingChannel> newCachingChannel =
|
||||
do_QueryInterface(aOldChannel);
|
||||
if (newCachingChannel)
|
||||
newCachingChannel->SetCacheForOfflineUse(PR_TRUE);
|
||||
}
|
||||
|
||||
PRBool match;
|
||||
rv = newURI->SchemeIs("http", &match);
|
||||
if (NS_FAILED(rv) || !match) {
|
||||
LOG(("rejected: URL is not of type http\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
if (!offline ||
|
||||
NS_FAILED(newURI->SchemeIs("https", &match)) ||
|
||||
!match) {
|
||||
LOG(("rejected: URL is not of type http\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP request headers are not automatically forwarded to the new channel.
|
||||
@@ -242,7 +267,10 @@ nsPrefetchListener::OnChannelRedirect(nsIChannel *aOldChannel,
|
||||
NS_ENSURE_STATE(httpChannel);
|
||||
|
||||
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
|
||||
NS_LITERAL_CSTRING("prefetch"), PR_FALSE);
|
||||
offline ?
|
||||
NS_LITERAL_CSTRING("offline-resource") :
|
||||
NS_LITERAL_CSTRING("prefetch"),
|
||||
PR_FALSE);
|
||||
|
||||
mService->UpdateCurrentChannel(aNewChannel);
|
||||
return NS_OK;
|
||||
@@ -264,7 +292,7 @@ nsPrefetchService::~nsPrefetchService()
|
||||
{
|
||||
// cannot reach destructor if prefetch in progress (listener owns reference
|
||||
// to this service)
|
||||
EmptyQueue();
|
||||
EmptyQueue(PR_TRUE);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -314,7 +342,9 @@ nsPrefetchService::ProcessNextURI()
|
||||
if (!listener) return;
|
||||
|
||||
do {
|
||||
rv = DequeueURI(getter_AddRefs(uri), getter_AddRefs(referrer));
|
||||
PRBool offline;
|
||||
rv = DequeueURI(getter_AddRefs(uri), getter_AddRefs(referrer),
|
||||
&offline);
|
||||
if (NS_FAILED(rv)) break;
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
@@ -335,12 +365,26 @@ nsPrefetchService::ProcessNextURI()
|
||||
if (NS_FAILED(rv)) continue;
|
||||
|
||||
// configure HTTP specific stuff
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mCurrentChannel));
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel =
|
||||
do_QueryInterface(mCurrentChannel);
|
||||
if (httpChannel) {
|
||||
httpChannel->SetReferrer(referrer);
|
||||
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
|
||||
NS_LITERAL_CSTRING("prefetch"),
|
||||
PR_FALSE);
|
||||
httpChannel->SetRequestHeader(
|
||||
NS_LITERAL_CSTRING("X-Moz"),
|
||||
offline ?
|
||||
NS_LITERAL_CSTRING("offline-resource") :
|
||||
NS_LITERAL_CSTRING("prefetch"),
|
||||
PR_FALSE);
|
||||
}
|
||||
|
||||
if (offline) {
|
||||
nsCOMPtr<nsICachingChannel> cachingChannel =
|
||||
do_QueryInterface(mCurrentChannel);
|
||||
if (cachingChannel) {
|
||||
if (NS_FAILED(cachingChannel->SetCacheForOfflineUse(PR_TRUE))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rv = mCurrentChannel->AsyncOpen(listener, nsnull);
|
||||
@@ -371,9 +415,11 @@ nsPrefetchService::RemoveProgressListener()
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPrefetchService::EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI)
|
||||
nsPrefetchService::EnqueueURI(nsIURI *aURI,
|
||||
nsIURI *aReferrerURI,
|
||||
PRBool aOffline)
|
||||
{
|
||||
nsPrefetchNode *node = new nsPrefetchNode(aURI, aReferrerURI);
|
||||
nsPrefetchNode *node = new nsPrefetchNode(aURI, aReferrerURI, aOffline);
|
||||
if (!node)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
@@ -390,7 +436,9 @@ nsPrefetchService::EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPrefetchService::DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI)
|
||||
nsPrefetchService::DequeueURI(nsIURI **aURI,
|
||||
nsIURI **aReferrerURI,
|
||||
PRBool *aOffline)
|
||||
{
|
||||
if (!mQueueHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
@@ -398,6 +446,7 @@ nsPrefetchService::DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI)
|
||||
// remove from the head
|
||||
NS_ADDREF(*aURI = mQueueHead->mURI);
|
||||
NS_ADDREF(*aReferrerURI = mQueueHead->mReferrerURI);
|
||||
*aOffline = mQueueHead->mOffline;
|
||||
|
||||
nsPrefetchNode *node = mQueueHead;
|
||||
mQueueHead = mQueueHead->mNext;
|
||||
@@ -410,16 +459,25 @@ nsPrefetchService::DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI)
|
||||
}
|
||||
|
||||
void
|
||||
nsPrefetchService::EmptyQueue()
|
||||
nsPrefetchService::EmptyQueue(PRBool includeOffline)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> uri, referrer;
|
||||
nsPrefetchNode *prev = 0;
|
||||
nsPrefetchNode *node = mQueueHead;
|
||||
|
||||
do {
|
||||
rv = DequeueURI(getter_AddRefs(uri),
|
||||
getter_AddRefs(referrer));
|
||||
while (node) {
|
||||
nsPrefetchNode *next = node->mNext;
|
||||
if (includeOffline || !node->mOffline) {
|
||||
if (prev)
|
||||
prev->mNext = next;
|
||||
else
|
||||
mQueueHead = next;
|
||||
delete node;
|
||||
}
|
||||
else
|
||||
prev = node;
|
||||
|
||||
node = next;
|
||||
}
|
||||
while (NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -453,9 +511,27 @@ nsPrefetchService::StopPrefetching()
|
||||
if (!mCurrentChannel)
|
||||
return;
|
||||
|
||||
// if it's an offline prefetch, requeue it for when prefetching starts
|
||||
// again
|
||||
nsCOMPtr<nsICachingChannel> cachingChannel =
|
||||
do_QueryInterface(mCurrentChannel);
|
||||
PRBool offline;
|
||||
if (cachingChannel &&
|
||||
NS_SUCCEEDED(cachingChannel->GetCacheForOfflineUse(&offline)) &&
|
||||
offline) {
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel =
|
||||
do_QueryInterface(mCurrentChannel);
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsCOMPtr<nsIURI> referrerURI;
|
||||
if (NS_SUCCEEDED(mCurrentChannel->GetURI(getter_AddRefs(uri))) &&
|
||||
NS_SUCCEEDED(httpChannel->GetReferrer(getter_AddRefs(referrerURI)))) {
|
||||
EnqueueURI(uri, referrerURI, PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentChannel->Cancel(NS_BINDING_ABORTED);
|
||||
mCurrentChannel = nsnull;
|
||||
EmptyQueue();
|
||||
EmptyQueue(PR_FALSE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -469,11 +545,14 @@ NS_IMPL_ISUPPORTS4(nsPrefetchService,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsPrefetchService::nsIPretetchService
|
||||
// nsPrefetchService::nsIPrefetchService
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrefetchService::PrefetchURI(nsIURI *aURI, nsIURI *aReferrerURI, PRBool aExplicit)
|
||||
nsresult
|
||||
nsPrefetchService::Prefetch(nsIURI *aURI,
|
||||
nsIURI *aReferrerURI,
|
||||
PRBool aExplicit,
|
||||
PRBool aOffline)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
@@ -507,8 +586,15 @@ nsPrefetchService::PrefetchURI(nsIURI *aURI, nsIURI *aReferrerURI, PRBool aExpli
|
||||
PRBool match;
|
||||
rv = aURI->SchemeIs("http", &match);
|
||||
if (NS_FAILED(rv) || !match) {
|
||||
LOG(("rejected: URL is not of type http\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
if (aOffline) {
|
||||
// Offline https urls can be prefetched
|
||||
rv = aURI->SchemeIs("https", &match);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) || !match) {
|
||||
LOG(("rejected: URL is not of type http\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -516,8 +602,15 @@ nsPrefetchService::PrefetchURI(nsIURI *aURI, nsIURI *aReferrerURI, PRBool aExpli
|
||||
//
|
||||
rv = aReferrerURI->SchemeIs("http", &match);
|
||||
if (NS_FAILED(rv) || !match) {
|
||||
LOG(("rejected: referrer URL is not of type http\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
if (aOffline) {
|
||||
// Offline https urls can be prefetched
|
||||
rv = aURI->SchemeIs("https", &match);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) || !match) {
|
||||
LOG(("rejected: referrer URL is not of type http\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
// skip URLs that contain query strings, except URLs for which prefetching
|
||||
@@ -542,8 +635,24 @@ nsPrefetchService::PrefetchURI(nsIURI *aURI, nsIURI *aReferrerURI, PRBool aExpli
|
||||
if (currentURI) {
|
||||
PRBool equals;
|
||||
if (NS_SUCCEEDED(currentURI->Equals(aURI, &equals)) && equals) {
|
||||
LOG(("rejected: URL is already being prefetched\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
if (aOffline) {
|
||||
// We may still need to put it on the queue if the channel
|
||||
// isn't fetching to the offline cache
|
||||
nsCOMPtr<nsICachingChannel> cachingChannel =
|
||||
do_QueryInterface(mCurrentChannel, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRBool offline;
|
||||
rv = cachingChannel->GetCacheForOfflineUse(&offline);
|
||||
if (NS_SUCCEEDED(rv) && offline) {
|
||||
LOG(("rejected: URL is already being prefetched\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG(("rejected: URL is already being prefetched\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -555,12 +664,32 @@ nsPrefetchService::PrefetchURI(nsIURI *aURI, nsIURI *aReferrerURI, PRBool aExpli
|
||||
for (; node; node = node->mNext) {
|
||||
PRBool equals;
|
||||
if (NS_SUCCEEDED(node->mURI->Equals(aURI, &equals)) && equals) {
|
||||
if (aOffline) {
|
||||
// make sure the node is placed in the offline cache
|
||||
node->mOffline = PR_TRUE;
|
||||
}
|
||||
LOG(("rejected: URL is already on prefetch queue\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
return EnqueueURI(aURI, aReferrerURI);
|
||||
return EnqueueURI(aURI, aReferrerURI, aOffline);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrefetchService::PrefetchURI(nsIURI *aURI,
|
||||
nsIURI *aReferrerURI,
|
||||
PRBool aExplicit)
|
||||
{
|
||||
return Prefetch(aURI, aReferrerURI, aExplicit, PR_FALSE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrefetchService::PrefetchURIForOfflineUse(nsIURI *aURI,
|
||||
nsIURI *aReferrerURI,
|
||||
PRBool aExplicit)
|
||||
{
|
||||
return Prefetch(aURI, aReferrerURI, aExplicit, PR_TRUE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -78,11 +78,16 @@ public:
|
||||
private:
|
||||
~nsPrefetchService();
|
||||
|
||||
nsresult Prefetch(nsIURI *aURI,
|
||||
nsIURI *aReferrerURI,
|
||||
PRBool aExplicit,
|
||||
PRBool aOffline);
|
||||
|
||||
void AddProgressListener();
|
||||
void RemoveProgressListener();
|
||||
nsresult EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI);
|
||||
nsresult DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI);
|
||||
void EmptyQueue();
|
||||
nsresult EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI, PRBool aOffline);
|
||||
nsresult DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI, PRBool *aOffline);
|
||||
void EmptyQueue(PRBool includeOffline);
|
||||
void StartPrefetching();
|
||||
void StopPrefetching();
|
||||
|
||||
@@ -127,15 +132,18 @@ class nsPrefetchNode
|
||||
{
|
||||
public:
|
||||
nsPrefetchNode(nsIURI *aURI,
|
||||
nsIURI *aReferrerURI)
|
||||
nsIURI *aReferrerURI,
|
||||
PRBool aOffline)
|
||||
: mNext(nsnull)
|
||||
, mURI(aURI)
|
||||
, mReferrerURI(aReferrerURI)
|
||||
, mOffline(aOffline)
|
||||
{ }
|
||||
|
||||
nsPrefetchNode *mNext;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIURI> mReferrerURI;
|
||||
PRBool mOffline;
|
||||
};
|
||||
|
||||
#endif // !nsPrefetchService_h__
|
||||
|
||||
Reference in New Issue
Block a user