--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5403,24 +5403,18 @@ var OfflineApps = {
getService(Ci.nsIPermissionManager);
pm.add(aURI, "offline-app",
Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
},
// XXX: duplicated in preferences/advanced.js
_getOfflineAppUsage: function (host)
{
- 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);
- var usage = cacheSession.getDomainUsage(host);
-
+ // XXX Bug 442810: include offline cache usage.
+ var usage = 0;
var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIDOMStorageManager);
usage += storageManager.getUsage(host);
return usage;
},
_checkUsage: function(aURI) {
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -211,23 +211,18 @@ var gAdvancedPane = {
document.documentElement.openWindow("Browser:Permissions",
"chrome://browser/content/preferences/permissions.xul",
"", params);
},
// XXX: duplicated in browser.js
_getOfflineAppUsage: function (host)
{
- 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);
- var usage = cacheSession.getDomainUsage(host);
+ // XXX Bug 442710: include offline cache usage.
+ var usage = 0;
var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIDOMStorageManager);
usage += storageManager.getUsage(host);
return usage;
},
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -66,16 +66,18 @@
#include "nsIContentViewer.h"
#include "nsIAtom.h"
#include "nsGkAtoms.h"
#include "nsIDOMWindowInternal.h"
#include "nsIPrincipal.h"
#include "nsIScriptGlobalObject.h"
#include "nsNetCID.h"
#include "nsIOfflineCacheUpdate.h"
+#include "nsIApplicationCache.h"
+#include "nsIApplicationCacheContainer.h"
#include "nsIScriptSecurityManager.h"
#include "nsIDOMLoadStatus.h"
#include "nsICookieService.h"
#include "nsIPrompt.h"
#include "nsServiceManagerUtils.h"
#include "nsContentUtils.h"
#include "nsParserUtils.h"
#include "nsCRT.h"
@@ -876,16 +878,34 @@ nsContentSink::ProcessOfflineManifest(ns
return;
}
// Only update if the document has permission to use offline APIs.
if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
return;
}
+ // XXX: at this point in the spec there is an algorithm for
+ // confirming whether the cache that was selected at load time was
+ // the proper application cache for this document. This will
+ // be implemented in a separate patch; For now just assume that we
+ // chose an acceptable application cache.
+
+ nsCOMPtr<nsIApplicationCacheContainer> channelContainer =
+ do_QueryInterface(mDocument->GetChannel());
+
+ nsCOMPtr<nsIApplicationCacheContainer> docContainer =
+ do_QueryInterface(mDocument);
+
+ if (channelContainer && docContainer) {
+ nsCOMPtr<nsIApplicationCache> appCache;
+ channelContainer->GetApplicationCache(getter_AddRefs(appCache));
+ docContainer->SetApplicationCache(appCache);
+ }
+
nsCOMPtr<nsIURI> manifestURI;
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(manifestURI),
manifestSpec, mDocument,
mDocumentURI);
if (!manifestURI) {
return;
}
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -799,51 +799,17 @@ nsContentUtils::GetOfflineAppManifest(ns
nsContentUtils::NewURIWithDocumentCharset(aURI, manifestSpec,
topDoc, topDoc->GetBaseURI());
}
/* static */
PRBool
nsContentUtils::OfflineAppAllowed(nsIURI *aURI)
{
- nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
- if (!innerURI)
- return PR_FALSE;
-
- // only http and https applications can use offline APIs.
- PRBool match;
- nsresult rv = innerURI->SchemeIs("http", &match);
- NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
- if (!match) {
- rv = innerURI->SchemeIs("https", &match);
- NS_ENSURE_SUCCESS(rv, PR_FALSE);
- if (!match) {
- return PR_FALSE;
- }
- }
-
- nsCOMPtr<nsIPermissionManager> permissionManager =
- do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
- if (!permissionManager) {
- return PR_FALSE;
- }
-
- PRUint32 perm;
- permissionManager->TestExactPermission(innerURI, "offline-app", &perm);
-
- if (perm == nsIPermissionManager::UNKNOWN_ACTION) {
- return GetBoolPref("offline-apps.allow_by_default");
- }
-
- if (perm == nsIPermissionManager::DENY_ACTION) {
- return PR_FALSE;
- }
-
- return PR_TRUE;
+ return NS_OfflineAppAllowed(aURI, sPrefBranch);
}
// static
void
nsContentUtils::Shutdown()
{
sInitialized = PR_FALSE;
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1138,16 +1138,17 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNode)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsPIDOMEventTarget)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOM3Node)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOM3Document)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsISupportsWeakReference)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNodeSelector)
+ NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
// nsNodeSH::PreCreate() depends on the identity pointer being the
// same as nsINode (which nsIDocument inherits), so if you change
// the below line, make sure nsNodeSH::PreCreate() still does the
// right thing!
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument, nsISupports, nsIDocument)
NS_INTERFACE_TABLE_END
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument)
if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
@@ -1949,16 +1950,32 @@ nsDocument::GetPrincipal()
void
nsDocument::SetPrincipal(nsIPrincipal *aNewPrincipal)
{
mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
}
NS_IMETHODIMP
+nsDocument::GetApplicationCache(nsIApplicationCache **aApplicationCache)
+{
+ NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocument::SetApplicationCache(nsIApplicationCache *aApplicationCache)
+{
+ mApplicationCache = aApplicationCache;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsDocument::GetContentType(nsAString& aContentType)
{
CopyUTF8toUTF16(mContentType, aContentType);
return NS_OK;
}
void
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -88,16 +88,18 @@
#include "nsIRequest.h"
#include "nsILoadGroup.h"
#include "nsTObserverArray.h"
#include "nsStubMutationObserver.h"
#include "nsIChannel.h"
#include "nsCycleCollectionParticipant.h"
#include "nsContentList.h"
#include "nsGkAtoms.h"
+#include "nsIApplicationCache.h"
+#include "nsIApplicationCacheContainer.h"
// Put these here so all document impls get them automatically
#include "nsHTMLStyleSheet.h"
#include "nsIHTMLCSSStyleSheet.h"
#include "nsStyleSet.h"
#include "nsXMLEventsManager.h"
#include "pldhash.h"
@@ -403,16 +405,17 @@ class nsDocument : public nsIDocument,
public nsIDOM3Document,
public nsSupportsWeakReference,
public nsIDOMEventTarget,
public nsIDOM3EventTarget,
public nsIDOMNSEventTarget,
public nsIScriptObjectPrincipal,
public nsIRadioGroupContainer,
public nsIDOMNodeSelector,
+ public nsIApplicationCacheContainer,
public nsStubMutationObserver
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup);
virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
nsIPrincipal* aPrincipal);
@@ -747,16 +750,19 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
// nsIScriptObjectPrincipal
virtual nsIPrincipal* GetPrincipal();
+ // nsIApplicationCacheContainer
+ NS_DECL_NSIAPPLICATIONCACHECONTAINER
+
virtual nsresult Init();
virtual nsresult AddXMLEventsContent(nsIContent * aXMLEventsElement);
virtual nsresult CreateElem(nsIAtom *aName, nsIAtom *aPrefix,
PRInt32 aNamespaceID,
PRBool aDocumentDefaultType,
nsIContent **aResult);
@@ -1016,16 +1022,20 @@ protected:
nsCOMPtr<nsIScriptEventManager> mScriptEventManager;
nsString mBaseTarget;
// Our update nesting level
PRUint32 mUpdateNestLevel;
+ // The application cache that this document is associated with, if
+ // any. This can change during the lifetime of the document.
+ nsCOMPtr<nsIApplicationCache> mApplicationCache;
+
private:
friend class nsUnblockOnloadEvent;
void PostUnblockOnloadEvent();
void DoUnblockOnload();
/**
* See if aDocument is a child of this. If so, return the frame element in
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -138,16 +138,19 @@
#include "nsIHistoryEntry.h"
#include "nsISHistoryListener.h"
#include "nsIWindowWatcher.h"
#include "nsIPromptFactory.h"
#include "nsIObserver.h"
#include "nsINestedURI.h"
#include "nsITransportSecurityInfo.h"
#include "nsINSSErrorsService.h"
+#include "nsIApplicationCache.h"
+#include "nsIApplicationCacheContainer.h"
+#include "nsIPermissionManager.h"
// Editor-related
#include "nsIEditingSession.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMDocument.h"
#include "nsICachingChannel.h"
#include "nsICacheVisitor.h"
@@ -453,16 +456,32 @@ NS_IMETHODIMP nsDocShell::GetInterface(c
NS_SUCCEEDED(EnsureScriptEnvironment())) {
return mScriptGlobal->QueryInterface(aIID, aSink);
}
else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
NS_SUCCEEDED(EnsureContentViewer())) {
mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
return *aSink ? NS_OK : NS_NOINTERFACE;
}
+ else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer)) &&
+ NS_SUCCEEDED(EnsureContentViewer())) {
+ *aSink = nsnull;
+
+ // Return the toplevel document as an
+ // nsIApplicationCacheContainer.
+
+ nsCOMPtr<nsIDocShellTreeItem> rootItem;
+ GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
+ nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(rootItem);
+ NS_ASSERTION(domDoc, "Should have a document.");
+ if (!domDoc)
+ return NS_ERROR_NO_INTERFACE;
+
+ return domDoc->QueryInterface(aIID, aSink);
+ }
else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
NS_SUCCEEDED(EnsureScriptEnvironment())) {
nsresult rv;
nsCOMPtr<nsIWindowWatcher> wwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(mScriptGlobal));
@@ -7270,16 +7289,25 @@ nsDocShell::DoURILoad(nsIURI * aURI,
uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
if (aFirstParty) {
// tag first party URL loads
loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
+
+ // Toplevel document loads in domains with the offline-app
+ // permission should check for an associated application
+ // cache.
+ nsCOMPtr<nsIDocShellTreeItem> root;
+ GetSameTypeRootTreeItem(getter_AddRefs(root));
+ if (root == this && NS_OfflineAppAllowed(aURI)) {
+ loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE;
+ }
}
if (mLoadType == LOAD_ERROR_PAGE) {
// Error pages are LOAD_BACKGROUND
loadFlags |= nsIChannel::LOAD_BACKGROUND;
}
// open a channel for the url
--- a/dom/src/offline/Makefile.in
+++ b/dom/src/offline/Makefile.in
@@ -54,16 +54,17 @@ REQUIRES = xpcom \
thebes \
js \
layout \
locale \
necko \
nkcache \
pref \
prefetch \
+ docshell \
widget \
xpconnect \
$(NULL)
CPPSRCS = \
nsDOMOfflineResourceList.cpp \
$(NULL)
--- a/dom/src/offline/nsDOMOfflineResourceList.cpp
+++ b/dom/src/offline/nsDOMOfflineResourceList.cpp
@@ -40,26 +40,26 @@
#include "nsDOMClassInfo.h"
#include "nsDOMError.h"
#include "nsIPrefetchService.h"
#include "nsCPrefetchService.h"
#include "nsNetUtil.h"
#include "nsNetCID.h"
#include "nsICacheSession.h"
#include "nsICacheService.h"
-#include "nsIOfflineCacheSession.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsIDOMLoadStatus.h"
#include "nsAutoPtr.h"
#include "nsContentUtils.h"
#include "nsIJSContextStack.h"
#include "nsEventDispatcher.h"
#include "nsIPrivateDOMEvent.h"
#include "nsIObserverService.h"
#include "nsIScriptGlobalObject.h"
+#include "nsIWebNavigation.h"
// Event names
#define CHECKING_STR "checking"
#define ERROR_STR "error"
#define NOUPDATE_STR "noupdate"
#define DOWNLOADING_STR "downloading"
#define PROGRESS_STR "progress"
@@ -68,29 +68,28 @@
// To prevent abuse of the resource list for data storage, the number
// of offline urls and their length are limited.
static const char kMaxEntriesPref[] = "offline.max_site_resources";
#define DEFAULT_MAX_ENTRIES 100
#define MAX_URI_LENGTH 2048
-static nsCAutoString gCachedAsciiHost;
+static nsCAutoString gCachedManifestSpec;
static char **gCachedKeys = nsnull;
static PRUint32 gCachedKeysCount = 0;
//
// nsDOMOfflineResourceList
//
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMOfflineResourceList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMOfflineResourceList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWindow)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCacheSession)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCacheUpdate)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCheckingListeners)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mErrorListeners)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mNoUpdateListeners)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mDownloadingListeners)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mProgressListeners)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCachedListeners)
@@ -109,17 +108,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPendingEvents[i].listener);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPendingEvents[i].listeners);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMOfflineResourceList)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow)
- NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCacheSession)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCacheUpdate)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mCheckingListeners)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mErrorListeners)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mNoUpdateListeners)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mDownloadingListeners)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mProgressListeners)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mCachedListeners)
@@ -176,46 +174,30 @@ nsDOMOfflineResourceList::Init()
if (mInitialized) {
return NS_OK;
}
if (!mManifestURI) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
+ mManifestURI->GetAsciiSpec(mManifestSpec);
+
nsresult rv = nsContentUtils::GetSecurityManager()->
CheckSameOriginURI(mManifestURI, mDocumentURI, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
// Dynamically-managed resources are stored as a separate ownership list
// from the manifest.
- rv = mManifestURI->GetAsciiSpec(mDynamicOwnerSpec);
- NS_ENSURE_SUCCESS(rv, rv);
-
- mDynamicOwnerSpec.Append("#dynamic");
-
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(mDocumentURI);
if (!innerURI)
return NS_ERROR_FAILURE;
- rv = innerURI->GetAsciiHost(mAsciiHost);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsCOMPtr<nsICacheService> serv = do_GetService(NS_CACHESERVICE_CONTRACTID,
- &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsCOMPtr<nsICacheSession> session;
- rv = serv->CreateSession("HTTP-offline",
- nsICache::STORE_OFFLINE,
- nsICache::STREAM_BASED,
- getter_AddRefs(session));
- NS_ENSURE_SUCCESS(rv, rv);
-
- mCacheSession = do_QueryInterface(session, &rv);
+ mApplicationCacheService =
+ do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Check for in-progress cache updates
nsCOMPtr<nsIOfflineCacheUpdateService> cacheUpdateService =
do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 numUpdates;
@@ -314,16 +296,21 @@ nsDOMOfflineResourceList::Add(const nsAS
{
nsresult rv = Init();
NS_ENSURE_SUCCESS(rv, rv);
if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
+ nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
+ if (!appCache) {
+ return NS_ERROR_DOM_INVALID_STATE_ERR;
+ }
+
if (aURI.Length() > MAX_URI_LENGTH) return NS_ERROR_DOM_BAD_URI;
// this will fail if the URI is not absolute
nsCOMPtr<nsIURI> requestedURI;
rv = NS_NewURI(getter_AddRefs(requestedURI), aURI);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString scheme;
@@ -369,59 +356,79 @@ nsDOMOfflineResourceList::Remove(const n
{
nsresult rv = Init();
NS_ENSURE_SUCCESS(rv, rv);
if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
+ nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
+ if (!appCache) {
+ return NS_ERROR_DOM_INVALID_STATE_ERR;
+ }
+
nsCAutoString key;
rv = GetCacheKey(aURI, key);
NS_ENSURE_SUCCESS(rv, rv);
ClearCachedKeys();
- rv = mCacheSession->RemoveOwnedKey(mAsciiHost, mDynamicOwnerSpec, key);
- NS_ENSURE_SUCCESS(rv, rv);
+ // XXX: This is a race condition. remove() is specced to remove
+ // from the currently associated application cache, but if this
+ // happens during an update (or after an update, if we haven't
+ // swapped yet), that remove() will be lost when the next update is
+ // finished. Need to bring this issue up.
- rv = mCacheSession->EvictUnownedEntries();
+ rv = appCache->UnmarkEntry(key, nsIApplicationCache::ITEM_DYNAMIC);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMOfflineResourceList::GetStatus(PRUint16 *aStatus)
{
nsresult rv = Init();
- // It is OK to check the status without a manifest attribute (you'll
- // just get "uncached").
- if (rv == NS_ERROR_DOM_INVALID_STATE_ERR && !mManifestURI) {
+ // Init may fail with INVALID_STATE_ERR if there is no manifest URI.
+ // The status attribute should not throw that exception, convert it
+ // to an UNCACHED.
+ if (rv == NS_ERROR_DOM_INVALID_STATE_ERR ||
+ !nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
*aStatus = nsIDOMOfflineResourceList::UNCACHED;
return NS_OK;
}
NS_ENSURE_SUCCESS(rv, rv);
+ // If there is an update in process, use its status.
if (mCacheUpdate) {
- return mCacheUpdate->GetStatus(aStatus);
+ rv = mCacheUpdate->GetStatus(aStatus);
+ if (NS_SUCCEEDED(rv) && *aStatus != nsIDOMOfflineResourceList::IDLE) {
+ return NS_OK;
+ }
}
- // XXX: the spec allows either UNCACHED or IDLE, depending on whether
- // the application is associated with a specific offline cache. Until
- // we have versioned application caches, the best approximation is
- // probably IDLE if the offline-app permission is set, and UNCACHED
- // otherwise.
+ // If this object is not associated with a cache, return UNCACHED
+ nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
+ if (!appCache) {
+ *aStatus = nsIDOMOfflineResourceList::UNCACHED;
+ return NS_OK;
+ }
- if (nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
+ nsCOMPtr<nsIApplicationCache> activeCache;
+ rv = mApplicationCacheService->GetActiveCache(mManifestSpec,
+ getter_AddRefs(activeCache));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (appCache == activeCache) {
*aStatus = nsIDOMOfflineResourceList::IDLE;
} else {
- *aStatus = nsIDOMOfflineResourceList::UNCACHED;
+ *aStatus = nsIDOMOfflineResourceList::UPDATEREADY;
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMOfflineResourceList::Update()
{
@@ -449,17 +456,45 @@ nsDOMOfflineResourceList::SwapCache()
{
nsresult rv = Init();
NS_ENSURE_SUCCESS(rv, rv);
if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
- return NS_ERROR_NOT_IMPLEMENTED;
+ if (!mToplevel) {
+ return NS_ERROR_DOM_INVALID_STATE_ERR;
+ }
+
+ nsCOMPtr<nsIApplicationCacheService> serv =
+ do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIApplicationCache> currentAppCache = GetDocumentAppCache();
+
+ nsCOMPtr<nsIApplicationCache> newAppCache;
+ rv = serv->GetActiveCache(mManifestSpec, getter_AddRefs(newAppCache));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!newAppCache || newAppCache == currentAppCache) {
+ return NS_ERROR_DOM_INVALID_STATE_ERR;
+ }
+
+ ClearCachedKeys();
+
+ nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
+ GetDocumentAppCacheContainer();
+
+ if (appCacheContainer) {
+ rv = appCacheContainer->SetApplicationCache(newAppCache);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
}
//
// nsDOMOfflineResourceList::nsIDOMEventTarget
//
NS_IMETHODIMP
nsDOMOfflineResourceList::GetOnchecking(nsIDOMEventListener **aOnchecking)
@@ -939,30 +974,35 @@ nsDOMOfflineResourceList::UpdateAdded(ns
nsresult
nsDOMOfflineResourceList::UpdateCompleted(nsIOfflineCacheUpdate *aUpdate)
{
if (aUpdate != mCacheUpdate) {
// This isn't the update we're watching.
return NS_OK;
}
+ PRBool partial;
+ mCacheUpdate->GetPartial(&partial);
+ PRBool isUpgrade;
+ mCacheUpdate->GetIsUpgrade(&isUpgrade);
+
PRBool succeeded;
nsresult rv = mCacheUpdate->GetSucceeded(&succeeded);
mCacheUpdate->RemoveObserver(this);
mCacheUpdate = nsnull;
- if (NS_SUCCEEDED(rv) && succeeded) {
- // XXX: the spec requires a "cached" event to be sent if this is a
- // first-time cache attempt, and "updateready" if this page was loaded
- // from an existing application cache. Since we don't have versioned
- // application caches yet, basically each update acts like a first-time
- // update, so we'll always fire "cached" for now.
- SendEvent(NS_LITERAL_STRING(CACHED_STR),
- mOnCachedListener, mCachedListeners);
+ if (NS_SUCCEEDED(rv) && succeeded && !partial) {
+ if (isUpgrade) {
+ SendEvent(NS_LITERAL_STRING(UPDATEREADY_STR),
+ mOnUpdateReadyListener, mUpdateReadyListeners);
+ } else {
+ SendEvent(NS_LITERAL_STRING(CACHED_STR),
+ mOnCachedListener, mCachedListeners);
+ }
}
return NS_OK;
}
nsresult
nsDOMOfflineResourceList::GetCacheKey(nsIURI *aURI, nsCString &aKey)
{
@@ -976,39 +1016,79 @@ nsDOMOfflineResourceList::GetCacheKey(ns
if (FindCharInReadable('#', specStart, specEnd)) {
aKey.BeginReading(specEnd);
aKey = Substring(specEnd, specStart);
}
return NS_OK;
}
+already_AddRefed<nsIApplicationCacheContainer>
+nsDOMOfflineResourceList::GetDocumentAppCacheContainer()
+{
+ nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mWindow);
+ if (!window) {
+ return nsnull;
+ }
+
+ nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(window);
+ if (!webnav) {
+ return nsnull;
+ }
+
+ nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
+ do_GetInterface(webnav);
+ return appCacheContainer.forget();
+}
+
+already_AddRefed<nsIApplicationCache>
+nsDOMOfflineResourceList::GetDocumentAppCache()
+{
+ nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
+ GetDocumentAppCacheContainer();
+
+ if (appCacheContainer) {
+ nsCOMPtr<nsIApplicationCache> applicationCache;
+ appCacheContainer->GetApplicationCache(
+ getter_AddRefs(applicationCache));
+ return applicationCache.forget();
+ }
+
+ return nsnull;
+}
+
nsresult
nsDOMOfflineResourceList::CacheKeys()
{
- if (gCachedKeys && mAsciiHost == gCachedAsciiHost)
+ if (gCachedKeys && mManifestSpec == gCachedManifestSpec)
return NS_OK;
ClearCachedKeys();
- nsresult rv = mCacheSession->GetOwnedKeys(mAsciiHost, mDynamicOwnerSpec,
- &gCachedKeysCount, &gCachedKeys);
+ nsCOMPtr<nsIApplicationCache> appCache;
+ mApplicationCacheService->GetActiveCache(mManifestSpec,
+ getter_AddRefs(appCache));
+
+ if (!appCache) {
+ return NS_ERROR_DOM_INVALID_STATE_ERR;
+ }
+
+ nsresult rv = appCache->GatherEntries(nsIApplicationCache::ITEM_DYNAMIC,
+ &gCachedKeysCount, &gCachedKeys);
if (NS_SUCCEEDED(rv))
- gCachedAsciiHost = mAsciiHost;
+ gCachedManifestSpec = mManifestSpec;
return rv;
}
void
nsDOMOfflineResourceList::ClearCachedKeys()
{
if (gCachedKeys) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(gCachedKeysCount, gCachedKeys);
gCachedKeys = nsnull;
gCachedKeysCount = 0;
}
- gCachedAsciiHost = "";
+ gCachedManifestSpec = "";
}
-
-
--- a/dom/src/offline/nsDOMOfflineResourceList.h
+++ b/dom/src/offline/nsDOMOfflineResourceList.h
@@ -36,17 +36,19 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMOfflineResourceList_h___
#define nsDOMOfflineResourceList_h___
#include "nscore.h"
#include "nsIDOMOfflineResourceList.h"
-#include "nsIOfflineCacheSession.h"
+#include "nsIApplicationCache.h"
+#include "nsIApplicationCacheContainer.h"
+#include "nsIApplicationCacheService.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsTArray.h"
#include "nsString.h"
#include "nsIURI.h"
#include "nsCOMPtr.h"
#include "nsWeakReference.h"
#include "nsCOMArray.h"
#include "nsIDOMEventListener.h"
@@ -92,31 +94,36 @@ private:
nsresult SendEvent(const nsAString &aEventName,
nsIDOMEventListener *aListener,
const nsCOMArray<nsIDOMEventListener> &aListeners);
nsresult UpdateAdded(nsIOfflineCacheUpdate *aUpdate);
nsresult UpdateCompleted(nsIOfflineCacheUpdate *aUpdate);
+ already_AddRefed<nsIApplicationCacheContainer> GetDocumentAppCacheContainer();
+ already_AddRefed<nsIApplicationCache> GetDocumentAppCache();
+
nsresult GetCacheKey(const nsAString &aURI, nsCString &aKey);
nsresult GetCacheKey(nsIURI *aURI, nsCString &aKey);
nsresult CacheKeys();
void ClearCachedKeys();
PRBool mInitialized;
PRBool mToplevel;
+
nsCOMPtr<nsIURI> mManifestURI;
+ // AsciiSpec of mManifestURI
+ nsCString mManifestSpec;
+
nsCOMPtr<nsIURI> mDocumentURI;
nsCOMPtr<nsIWeakReference> mWindow;
- nsCOMPtr<nsIOfflineCacheSession> mCacheSession;
+ nsCOMPtr<nsIApplicationCacheService> mApplicationCacheService;
nsCOMPtr<nsIOfflineCacheUpdate> mCacheUpdate;
- nsCAutoString mAsciiHost;
- nsCAutoString mDynamicOwnerSpec;
nsCOMArray<nsIDOMEventListener> mCheckingListeners;
nsCOMArray<nsIDOMEventListener> mErrorListeners;
nsCOMArray<nsIDOMEventListener> mNoUpdateListeners;
nsCOMArray<nsIDOMEventListener> mDownloadingListeners;
nsCOMArray<nsIDOMEventListener> mProgressListeners;
nsCOMArray<nsIDOMEventListener> mCachedListeners;
nsCOMArray<nsIDOMEventListener> mUpdateReadyListeners;
--- a/dom/tests/mochitest/ajax/offline/offlineTests.js
+++ b/dom/tests/mochitest/ajax/offline/offlineTests.js
@@ -46,24 +46,19 @@ fetch: function(callback)
if (this.urls.length == 0) {
callback(this.contents);
return;
}
var url = this.urls.shift();
var self = this;
- var cacheService = Cc["@mozilla.org/network/cache-service;1"]
- .getService(Ci.nsICacheService);
- var cacheSession = cacheService.createSession("HTTP-offline",
- Ci.nsICache.STORE_OFFLINE,
- true);
+ var cacheSession = OfflineTest.getActiveSession();
cacheSession.asyncOpenCacheEntry(url, Ci.nsICache.ACCESS_READ, this);
}
-
};
var OfflineTest = {
_slaveWindow: null,
// The window where test results should be sent.
_masterWindow: null,
@@ -162,57 +157,37 @@ is: function(a, b, name)
isnot: function(a, b, name)
{
return this._masterWindow.SimpleTest.isnot(a, b, name);
},
clear: function()
{
- // Clear the ownership list
- var cacheService = Cc["@mozilla.org/network/cache-service;1"]
- .getService(Ci.nsICacheService);
- var cacheSession = cacheService.createSession("HTTP-offline",
- Ci.nsICache.STORE_OFFLINE,
- true)
- .QueryInterface(Ci.nsIOfflineCacheSession);
-
- // Get the asciiHost from the page URL
- var locationURI = Cc["@mozilla.org/network/standard-url;1"]
- .createInstance(Ci.nsIURI);
- locationURI.spec = window.location.href;
- var asciiHost = locationURI.asciiHost;
-
- // Clear manifest-owned urls
- cacheSession.setOwnedKeys(asciiHost,
- this.getManifestUrl() + "#manifest", 0, []);
-
- // Clear dynamically-owned urls
- cacheSession.setOwnedKeys(asciiHost,
- this.getManifestUrl() + "#dynamic", 0, []);
-
- cacheSession.evictUnownedEntries();
+ // XXX: maybe we should just wipe out the entire disk cache.
+ var appCacheService = Cc["@mozilla.org/network/application-cache-service;1"]
+ .getService(Ci.nsIApplicationCacheService);
+ var applicationCache = this.getActiveCache();
+ if (applicationCache) {
+ applicationCache.discard();
+ }
},
failEvent: function(e)
{
OfflineTest.ok(false, "Unexpected event: " + e.type);
},
// The offline API as specified has no way to watch the load of a resource
// added with applicationCache.add().
waitForAdd: function(url, onFinished) {
// Check every half second for ten seconds.
var numChecks = 20;
var waitFunc = function() {
- var cacheService = Cc["@mozilla.org/network/cache-service;1"]
- .getService(Ci.nsICacheService);
- var cacheSession = cacheService.createSession("HTTP-offline",
- Ci.nsICache.STORE_OFFLINE,
- true);
+ var cacheSession = OfflineTest.getActiveSession();
var entry;
try {
var entry = cacheSession.openCacheEntry(url, Ci.nsICache.ACCESS_READ, true);
} catch (e) {
}
if (entry) {
entry.close();
@@ -231,48 +206,74 @@ waitForAdd: function(url, onFinished) {
setTimeout(this.priv(waitFunc), 500);
},
getManifestUrl: function()
{
return window.top.document.documentElement.getAttribute("manifest");
},
+getActiveCache: function()
+{
+ // Note that this is the current active cache in the cache stack, not the
+ // one associated with this window.
+ var serv = Cc["@mozilla.org/network/application-cache-service;1"]
+ .getService(Ci.nsIApplicationCacheService);
+ return serv.getActiveCache(this.getManifestUrl());
+},
+
+getActiveSession: function()
+{
+ var cache = this.getActiveCache();
+ if (!cache) return null;
+
+ var cacheService = Cc["@mozilla.org/network/cache-service;1"]
+ .getService(Ci.nsICacheService);
+ return cacheService.createSession(cache.clientID,
+ Ci.nsICache.STORE_OFFLINE,
+ true);
+},
+
priv: function(func)
{
var self = this;
return function() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
func(arguments);
}
},
checkCache: function(url, expectEntry)
{
- var cacheService = Cc["@mozilla.org/network/cache-service;1"]
- .getService(Ci.nsICacheService);
- var cacheSession = cacheService.createSession("HTTP-offline",
- Ci.nsICache.STORE_OFFLINE,
- true);
+ var cacheSession = this.getActiveSession();
+ if (!cacheSession) {
+ if (expectEntry) {
+ this.ok(false, url + " should exist in the offline cache");
+ } else {
+ this.ok(true, url + " should not exist in the offline cache");
+ }
+ return;
+ }
+
try {
var entry = cacheSession.openCacheEntry(url, Ci.nsICache.ACCESS_READ, false);
if (expectEntry) {
this.ok(true, url + " should exist in the offline cache");
} else {
this.ok(false, url + " should not exist in the offline cache");
}
entry.close();
} catch (e) {
if (e.result == NS_ERROR_CACHE_KEY_NOT_FOUND) {
if (expectEntry) {
this.ok(false, url + " should exist in the offline cache");
} else {
this.ok(true, url + " should not exist in the offline cache");
}
- } else if (e.result == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
+ } else if (e.result == NS_ERROR_CACHE_KEY_WAIT_FOR_VALIDATION) {
// There was a cache key that we couldn't access yet, that's good enough.
if (expectEntry) {
this.ok(true, url + " should exist in the offline cache");
} else {
this.ok(false, url + " should not exist in the offline cache");
}
} else {
throw e;
--- a/dom/tests/mochitest/ajax/offline/test_changingManifest.html
+++ b/dom/tests/mochitest/ajax/offline/test_changingManifest.html
@@ -46,18 +46,19 @@ function manifestUpdated()
OfflineTest.ok(gGotDownloading, "Should get a downloading event");
// Get the initial contents of the first two files.
fetcher = new OfflineCacheContents([g1SecUrl, g1HourUrl]);
fetcher.fetch(function(contents) {
gCacheContents = contents;
// Now make sure applicationCache.update() does what we expect.
- applicationCache.oncached = OfflineTest.priv(manifestUpdatedAgain);
+ applicationCache.onupdateready = OfflineTest.priv(manifestUpdatedAgain);
applicationCache.onnoupdate = failAndFinish;
+ applicationCache.oncached = failAndFinish;
gGotChecking = false;
gGotDownloading = false;
// The changing versions give out a new version each second,
// make sure it has time to grab a new version, and for the
// 1-second cache timeout to pass.
window.setTimeout("applicationCache.update()", 5000);
--- a/dom/tests/mochitest/ajax/offline/test_simpleManifest.html
+++ b/dom/tests/mochitest/ajax/offline/test_simpleManifest.html
@@ -31,36 +31,16 @@ function addFinished()
// We're done
OfflineTest.teardown();
OfflineTest.finish();
}
-function secondUpdate()
-{
- OfflineTest.ok(gGotChecking, "Should get a checking event");
- OfflineTest.ok(gGotDownloading, "Should get a downloading event");
-
- // The document that requested the manifest should be in the cache
- OfflineTest.checkCache(window.location.href, true);
-
- OfflineTest.checkCache("http://localhost:8888/tests/SimpleTest/SimpleTest.js", true);
- OfflineTest.checkCache("http://localhost:8888/MochiKit/packed.js", true);
- OfflineTest.checkCache("http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", true);
-
- // Now add a file using the applicationCache API
- applicationCache.add("http://localhost:8888/tests/SimpleTest/EventUtils.js");
-
- // Wait for the add() to be downloaded
- OfflineTest.waitForAdd("http://localhost:8888/tests/SimpleTest/EventUtils.js",
- OfflineTest.priv(addFinished));
-}
-
function manifestUpdated()
{
OfflineTest.ok(gGotChecking, "Should get a checking event");
OfflineTest.ok(gGotDownloading, "Should get a downloading event");
// The manifest itself should be in the cache
OfflineTest.checkCache("http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest", true);
@@ -71,36 +51,28 @@ function manifestUpdated()
OfflineTest.checkCache("http://localhost:8888/tests/SimpleTest/SimpleTest.js", true);
OfflineTest.checkCache("http://localhost:8888/MochiKit/packed.js", true);
OfflineTest.checkCache("http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", true);
// The bad entries from the manifest should not be in the cache
OfflineTest.checkCache("https://localhost:8888/MochiKit/packed.js", false);
OfflineTest.checkCache("bad:/uri/invalid", false);
- // Remove items from the cache.
- OfflineTest.clear();
+ applicationCache.swapCache();
- // Make sure OfflineTest.clear() properly removed the items
+ // XXX: make sure that the previous version went away after the swapCache().
- OfflineTest.checkCache("http://localhost:8888/tests/SimpleTest/SimpleTest.js", false);
- OfflineTest.checkCache("http://localhost:8888/MochiKit/packed.js", false);
- OfflineTest.checkCache("http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", false);
- OfflineTest.checkCache("http://localhost:8888/tests/SimpleTest/EventUtils.js",
- false);
+ // Now add a file using the applicationCache API
+ applicationCache.add("http://localhost:8888/tests/SimpleTest/EventUtils.js");
- // Now make sure applicationCache.update() does what we expect.
- applicationCache.oncached = OfflineTest.priv(secondUpdate);
-
- gGotChecking = false;
- gGotDownloading = false;
- applicationCache.update();
+ // Wait for the add() to be downloaded
+ OfflineTest.waitForAdd("http://localhost:8888/tests/SimpleTest/EventUtils.js",
+ OfflineTest.priv(addFinished));
}
-
if (OfflineTest.setup()) {
OfflineTest.ok(applicationCache instanceof EventTarget,
"applicationCache should be an event target");
applicationCache.onerror = OfflineTest.failEvent;
applicationCache.addEventListener("checking", function() {
OfflineTest.is(applicationCache.status, 2, "CHECKING state while checking");
--- a/netwerk/base/public/Makefile.in
+++ b/netwerk/base/public/Makefile.in
@@ -56,16 +56,19 @@ SDK_XPIDLSRCS = \
nsIURI.idl \
nsIURL.idl \
nsIFileURL.idl \
nsIUploadChannel.idl \
nsIUnicharStreamListener.idl \
$(NULL)
XPIDLSRCS = \
+ nsIApplicationCache.idl \
+ nsIApplicationCacheContainer.idl \
+ nsIApplicationCacheService.idl \
nsIAuthInformation.idl \
nsIAuthPrompt.idl \
nsIAuthPrompt2.idl \
nsIAuthPromptAdapterFactory.idl \
nsIAuthPromptCallback.idl \
nsIAsyncStreamCopier.idl \
nsISafeOutputStream.idl \
nsIBufferedStreams.idl \
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIApplicationCache.idl
@@ -0,0 +1,143 @@
+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is nsIApplicationCache.idl.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dave Camp <dcamp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+/**
+ * Application caches store resources for offline use. Each
+ * application cache has a unique client ID for use with
+ * nsICacheService::openSession() to access the cache's entries.
+ *
+ * Each entry in the application cache can be marked with a set of
+ * types, as discussed in the WHAT-WG offline applications
+ * specification.
+ *
+ * All application caches with the same group ID belong to a cache
+ * group. Each group has one "active" cache that will service future
+ * loads. Inactive caches will be removed from the cache when they are
+ * no longer referenced.
+ */
+[scriptable, uuid(a9cfbeef-8f8d-49c3-b899-303390383ae9)]
+interface nsIApplicationCache : nsISupports
+{
+ /**
+ * Entries in an application cache can be marked as one or more of
+ * the following types.
+ */
+
+ /* This item is the application manifest. */
+ const unsigned long ITEM_MANIFEST = 1 << 0;
+
+ /* This item was explicitly listed in the application manifest. */
+ const unsigned long ITEM_EXPLICIT = 1 << 1;
+
+ /* This item was navigated in a toplevel browsing context, and
+ * named this cache's group as its manifest. */
+ const unsigned long ITEM_IMPLICIT = 1 << 2;
+
+ /* This item was added by the dynamic scripting API */
+ const unsigned long ITEM_DYNAMIC = 1 << 3;
+
+ /* This item was listed in the application manifest, but named a
+ * different cache group as its manifest. */
+ const unsigned long ITEM_FOREIGN = 1 << 4;
+
+ /* This item was listed as a fallback entry. */
+ const unsigned long ITEM_FALLBACK = 1 << 5;
+
+ /* This item matched an opportunistic cache namespace and was
+ * cached accordingly. */
+ const unsigned long ITEM_OPPORTUNISTIC = 1 << 6;
+
+ /**
+ * The group ID for this cache group. This is the URI of the
+ * manifest file.
+ **/
+ readonly attribute ACString groupID;
+
+ /**
+ * The client ID for this application cache. Clients can open a
+ * session with nsICacheService::createSession() using this client
+ * ID and a storage policy of STORE_OFFLINE to access this cache.
+ */
+ readonly attribute ACString clientID;
+
+ /**
+ * TRUE if the cache is the active cache for this group.
+ */
+ readonly attribute boolean active;
+
+ /**
+ * Makes this cache the active application cache for this group.
+ * Future loads associated with this group will come from this
+ * cache. Other caches from this cache group will be deactivated.
+ */
+ void activate();
+
+ /**
+ * Discard this application cache. Removes all cached resources
+ * for this cache. If this is the active application cache for the
+ * group, the group will be removed.
+ */
+ void discard();
+
+ /**
+ * Adds item types to a given entry.
+ */
+ void markEntry(in ACString key, in unsigned long typeBits);
+
+ /**
+ * Removes types from a given entry. If the resulting entry has
+ * no types left, the entry is removed.
+ */
+ void unmarkEntry(in ACString key, in unsigned long typeBits);
+
+ /**
+ * Gets the types for a given entry.
+ */
+ unsigned long getTypes(in ACString key);
+
+ /**
+ * Returns any entries in the application cache whose type matches
+ * one or more of the bits in typeBits.
+ */
+ void gatherEntries(in PRUint32 typeBits,
+ out unsigned long count,
+ [array, size_is(count)] out string keys);
+};
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIApplicationCacheContainer.idl
@@ -0,0 +1,52 @@
+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is nsIApplicationCache.idl.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dave Camp <dcamp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIApplicationCache;
+
+/**
+ * Interface used by objects that can be associated with an
+ * application cache.
+ */
+[scriptable, uuid(bbb80700-1f7f-4258-aff4-1743cc5a7d23)]
+interface nsIApplicationCacheContainer : nsISupports
+{
+ attribute nsIApplicationCache applicationCache;
+};
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIApplicationCacheService.idl
@@ -0,0 +1,71 @@
+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is nsIApplicationCache.idl.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dave Camp <dcamp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIApplicationCache;
+
+/**
+ * The application cache service manages the set of application cache
+ * groups.
+ */
+[scriptable, uuid(3f411c68-0d17-420d-839a-6355eea877b9)]
+interface nsIApplicationCacheService : nsISupports
+{
+ /**
+ * Create a new, empty application cache for the given cache
+ * group.
+ */
+ nsIApplicationCache createApplicationCache(in ACString group);
+
+ /**
+ * Get an application cache object for the given client ID.
+ */
+ nsIApplicationCache getApplicationCache(in ACString clientID);
+
+ /**
+ * Get the currently active cache object for a cache group.
+ */
+ nsIApplicationCache getActiveCache(in ACString group);
+
+ /**
+ * Try to find the best application cache to serve a resource.
+ */
+ nsIApplicationCache chooseApplicationCache(in ACString key);
+};
--- a/netwerk/base/public/nsINetUtil.idl
+++ b/netwerk/base/public/nsINetUtil.idl
@@ -36,16 +36,17 @@
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIURI;
+interface nsIPrefBranch;
/**
* nsINetUtil provides various network-related utility methods.
*/
[scriptable, uuid(57322c6f-f4ec-4e46-8253-b74be220de16)]
interface nsINetUtil : nsISupports
{
/**
@@ -215,8 +216,30 @@ interface nsINetUtil : nsISupports
* cases when parseContentType would claim to have a charset, if the type
* that won out does not have a charset parameter specified.
*/
boolean extractCharsetFromContentType(in AUTF8String aTypeHeader,
out AUTF8String aCharset,
out long aCharsetStart,
out long aCharsetEnd);
};
+
+/**
+ * nsINetUtil methods added in mozilla 1.9.1.
+ *
+ * XXX bug 451255: Merge this up in to nsINetUtil as soon as possible.
+ */
+[scriptable, uuid(da76ab60-2ec5-4649-84c4-4954a08f6d37)]
+interface nsINetUtil_MOZILLA_1_9_1 : nsISupports
+{
+ /**
+ * Checks whether a document at the given URI should have access
+ * to the offline cache.
+ * @param aURI
+ * The URI to check
+ * @param aPrefBranch
+ * The pref branch to use to check the
+ * offline-apps.allow_by_default pref. If not specified,
+ * the pref service will be used.
+ */
+ boolean OfflineAppAllowed(in nsIURI aURI,
+ in nsIPrefBranch aPrefBranch);
+};
--- a/netwerk/base/public/nsNetUtil.h
+++ b/netwerk/base/public/nsNetUtil.h
@@ -1436,9 +1436,33 @@ NS_GetFinalChannelURI(nsIChannel* channe
if (loadFlags & nsIChannel::LOAD_REPLACE) {
return channel->GetURI(uri);
}
return channel->GetOriginalURI(uri);
}
+/**
+ * Checks whether a document at the given URI should have access
+ * to the offline cache.
+ * @param uri
+ * The URI to check
+ * @param prefBranch
+ * The pref branch to use to check the
+ * offline-apps.allow_by_default pref. If not specified,
+ * the pref service will be used.
+ */
+inline PRBool
+NS_OfflineAppAllowed(nsIURI *aURI, nsIPrefBranch *aPrefBranch = nsnull)
+{
+ nsresult rv;
+ nsCOMPtr<nsINetUtil_MOZILLA_1_9_1> util = do_GetIOService(&rv);
+ NS_ENSURE_SUCCESS(rv, PR_FALSE);
+
+ PRBool allowed;
+ rv = util->OfflineAppAllowed(aURI, aPrefBranch, &allowed);
+ NS_ENSURE_SUCCESS(rv, PR_FALSE);
+
+ return allowed;
+}
+
#endif // !nsNetUtil_h__
--- a/netwerk/base/src/nsIOService.cpp
+++ b/netwerk/base/src/nsIOService.cpp
@@ -65,16 +65,17 @@
#include "nsEscape.h"
#include "nsNetCID.h"
#include "nsIRecyclingAllocator.h"
#include "nsISocketTransport.h"
#include "nsCRT.h"
#include "nsINestedURI.h"
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
+#include "nsIPermissionManager.h"
#if defined(XP_WIN)
#include "nsNativeConnectionHelper.h"
#endif
#define PORT_PREF_PREFIX "network.security.ports."
#define PORT_PREF(x) PORT_PREF_PREFIX x
#define AUTODIAL_PREF "network.autodial-helper.enabled"
@@ -273,22 +274,23 @@ nsIOService::GetInstance() {
return nsnull;
}
return gIOService;
}
NS_ADDREF(gIOService);
return gIOService;
}
-NS_IMPL_THREADSAFE_ISUPPORTS5(nsIOService,
+NS_IMPL_THREADSAFE_ISUPPORTS6(nsIOService,
nsIIOService,
nsIIOService2,
nsINetUtil,
nsIObserver,
- nsISupportsWeakReference)
+ nsISupportsWeakReference,
+ nsINetUtil_MOZILLA_1_9_1)
////////////////////////////////////////////////////////////////////////////////
nsresult
nsIOService::OnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
PRUint32 flags)
{
nsCOMPtr<nsIChannelEventSink> sink =
@@ -978,8 +980,63 @@ nsIOService::ExtractCharsetFromContentTy
net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset,
aCharsetStart, aCharsetEnd);
if (*aHadCharset && *aCharsetStart == *aCharsetEnd) {
*aHadCharset = PR_FALSE;
}
return NS_OK;
}
+NS_IMETHODIMP
+nsIOService::OfflineAppAllowed(nsIURI *aURI,
+ nsIPrefBranch *aPrefBranch,
+ PRBool *aAllowed)
+{
+ *aAllowed = PR_FALSE;
+
+ nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
+ if (!innerURI)
+ return NS_OK;
+
+ // only http and https applications can use offline APIs.
+ PRBool match;
+ nsresult rv = innerURI->SchemeIs("http", &match);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!match) {
+ rv = innerURI->SchemeIs("https", &match);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!match) {
+ return NS_OK;
+ }
+ }
+
+ nsCOMPtr<nsIPermissionManager> permissionManager =
+ do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+ if (!permissionManager) {
+ return NS_OK;
+ }
+
+ PRUint32 perm;
+ permissionManager->TestExactPermission(innerURI, "offline-app", &perm);
+
+ if (perm == nsIPermissionManager::UNKNOWN_ACTION) {
+ nsCOMPtr<nsIPrefBranch> branch = aPrefBranch;
+ if (!branch) {
+ branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
+ }
+ if (branch) {
+ rv = branch->GetBoolPref("offline-apps.allow_by_default", aAllowed);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+ }
+
+ if (perm == nsIPermissionManager::DENY_ACTION) {
+ return NS_OK;
+ }
+
+ *aAllowed = PR_TRUE;
+
+ return NS_OK;
+}
+
--- a/netwerk/base/src/nsIOService.h
+++ b/netwerk/base/src/nsIOService.h
@@ -72,24 +72,26 @@ static const char gScheme[][sizeof("reso
{"chrome", "file", "http", "jar", "resource"};
class nsIPrefBranch;
class nsIPrefBranch2;
class nsIOService : public nsIIOService2
, public nsIObserver
, public nsINetUtil
+ , public nsINetUtil_MOZILLA_1_9_1
, public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIIOSERVICE
NS_DECL_NSIIOSERVICE2
NS_DECL_NSIOBSERVER
NS_DECL_NSINETUTIL
+ NS_DECL_NSINETUTIL_MOZILLA_1_9_1
// Gets the singleton instance of the IO Service, creating it as needed
// Returns nsnull on out of memory or failure to initialize.
// Returns an addrefed pointer.
static nsIOService* GetInstance();
NS_HIDDEN_(nsresult) Init();
NS_HIDDEN_(nsresult) NewURI(const char* aSpec, nsIURI* aBaseURI,
--- a/netwerk/build/Makefile.in
+++ b/netwerk/build/Makefile.in
@@ -108,16 +108,21 @@ endif
ifdef NECKO_COOKIES
SHARED_LIBRARY_LIBS += \
../cookie/src/$(LIB_PREFIX)neckocookie_s.$(LIB_SUFFIX) \
$(NULL)
LOCAL_INCLUDES += -I$(srcdir)/../cookie/src
endif
+ifdef MOZ_STORAGE
+REQUIRES += storage
+DEFINES += -DNECKO_OFFLINE_CACHE
+endif
+
EXTRA_DSO_LDOPTS = \
$(LIBS_DIR) \
$(EXTRA_DSO_LIBS) \
$(MOZ_UNICHARUTIL_LIBS) \
$(MOZ_COMPONENT_LIBS) \
$(ZLIB_LIBS) \
$(NULL)
--- a/netwerk/build/nsNetCID.h
+++ b/netwerk/build/nsNetCID.h
@@ -460,16 +460,28 @@
#define NS_CACHESERVICE_CID \
{ /* 6c84aec9-29a5-4264-8fbc-bee8f922ea67 */ \
0x6c84aec9, \
0x29a5, \
0x4264, \
{0x8f, 0xbc, 0xbe, 0xe8, 0xf9, 0x22, 0xea, 0x67} \
}
+// service implementing nsIApplicationCacheService.
+#define NS_APPLICATIONCACHESERVICE_CLASSNAME \
+ "nsApplicationCacheService"
+#define NS_APPLICATIONCACHESERVICE_CONTRACTID \
+ "@mozilla.org/network/application-cache-service;1"
+#define NS_APPLICATIONCACHESERVICE_CID \
+{ /* 02bf7a2a-39d8-4a23-a50c-2cbb085ab7a5 */ \
+ 0x02bf7a2a, \
+ 0x39d8, \
+ 0x4a23, \
+ {0xa5, 0x0c, 0x2c, 0xbb, 0x08, 0x5a, 0xb7, 0xa5} \
+}
/******************************************************************************
* netwerk/protocol/http/ classes
*/
#define NS_HTTPPROTOCOLHANDLER_CID \
{ /* 4f47e42e-4d23-4dd3-bfda-eb29255e9ea3 */ \
0x4f47e42e, \
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -51,16 +51,17 @@
#include "nsLoadGroup.h"
#include "nsStreamLoader.h"
#include "nsUnicharStreamLoader.h"
#include "nsFileStreams.h"
#include "nsBufferedStreams.h"
#include "nsMIMEInputStream.h"
#include "nsSOCKSSocketProvider.h"
#include "nsCacheService.h"
+#include "nsDiskCacheDeviceSQL.h"
#include "nsMimeTypes.h"
#include "nsNetStrings.h"
#include "nsNetCID.h"
#if defined(XP_MACOSX)
#define BUILD_APPLEFILE_DECODER 1
#else
@@ -182,17 +183,21 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsSafeAbo
// about
#ifdef NS_BUILD_REFCNT_LOGGING
#include "nsAboutBloat.h"
#endif
#include "nsAboutCache.h"
#include "nsAboutCacheEntry.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAboutCacheEntry)
#endif
-
+
+#ifdef NECKO_OFFLINE_CACHE
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsOfflineCacheDevice, nsOfflineCacheDevice::GetInstance)
+#endif
+
#ifdef NECKO_PROTOCOL_file
// file
#include "nsFileProtocolHandler.h"
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsFileProtocolHandler, Init)
#endif
#ifdef NECKO_PROTOCOL_ftp
// ftp
@@ -1040,16 +1045,24 @@ static const nsModuleComponentInfo gNetM
},
{ NS_CACHESERVICE_CLASSNAME,
NS_CACHESERVICE_CID,
NS_CACHESERVICE_CONTRACTID,
nsCacheService::Create
},
+#ifdef NECKO_OFFLINE_CACHE
+ { NS_APPLICATIONCACHESERVICE_CLASSNAME,
+ NS_APPLICATIONCACHESERVICE_CID,
+ NS_APPLICATIONCACHESERVICE_CONTRACTID,
+ nsOfflineCacheDeviceConstructor
+ },
+#endif
+
#ifdef NECKO_COOKIES
{ NS_COOKIEMANAGER_CLASSNAME,
NS_COOKIEMANAGER_CID,
NS_COOKIEMANAGER_CONTRACTID,
nsCookieServiceConstructor
},
{ NS_COOKIESERVICE_CLASSNAME,
--- a/netwerk/cache/public/Makefile.in
+++ b/netwerk/cache/public/Makefile.in
@@ -48,14 +48,13 @@ include $(DEPTH)/config/autoconf.mk
XPIDLSRCS = \
nsICache.idl \
nsICacheEntryDescriptor.idl \
nsICacheListener.idl \
nsICacheService.idl \
nsICacheSession.idl \
nsICacheVisitor.idl \
- nsIOfflineCacheSession.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk
DEFINES += -DIMPL_NS_NET
--- a/netwerk/cache/public/nsICacheService.idl
+++ b/netwerk/cache/public/nsICacheService.idl
@@ -81,21 +81,17 @@ interface nsICacheService : nsISupports
void visitEntries(in nsICacheVisitor visitor);
/**
* Evicts all entries in all devices implied by the storage policy.
*/
void evictEntries(in nsCacheStoragePolicy storagePolicy);
/**
- * Return a unique, temporary cache client ID.
- *
- * This is used by the offline cache. The offline cache lets clients
- * accumulate entries in a temporary client and merge them in as a group
- * using nsIOfflineCacheSession.mergeTemporaryClient().
+ * This method is deprecated and will throw NS_ERROR_NOT_IMPLEMENTED.
*/
ACString createTemporaryClientID(in nsCacheStoragePolicy storagePolicy);
};
%{C++
/**
* Observer service notification that is sent when
* nsICacheService::evictEntries() or nsICacheSession::evictEntries()
deleted file mode 100644
--- a/netwerk/cache/public/nsIOfflineCacheSession.idl
+++ /dev/null
@@ -1,233 +0,0 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is nsIOfflineCacheSession.idl.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Dave Camp <dcamp@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsISupports.idl"
-#include "nsICache.idl"
-
-/**
- * The offline cache is meant to reliably store resources for
- * offline use. The expected semantics are:
- *
- * a) Once populated, the cache will not evict an application resource
- * unless explicitly asked.
- *
- * b) Resources no longer in use by the application should be evicted.
- *
- * c) If the cache fills up, new entries should be rejected rather
- * than throwing out old ones.
- *
- * The offline cache uses domains to concretely represent an
- * application. It maintains a list of resources to be pinned for
- * each domain. This list is separate from actual cache
- * population - the caller is still responsible for placing items
- * in the cache, and ownership can be declared without a
- * corresponding entry.
- *
- * A key can optionally be associated with a specific URI within
- * the domain.
- */
-
-[scriptable, uuid(3a33e268-4175-4440-a933-89d461c86c5f)]
-interface nsIOfflineCacheSession : nsISupports
-{
- /**
- * Gets the list of owner domains in the cache.
- *
- * @param count
- * The number of domains returned
- * @param uris
- * The domains that own resources in the cache
- */
- void getOwnerDomains(out unsigned long count,
- [array, size_is(count)]out string domains);
-
- /**
- * Gets the list of owner URIs associated with a domain.
- *
- * @param ownerAsciiDomain
- * The domain to query
- * !! IMPORTANT !! : This must be ascii encoded host - nsIURI.asciiHost
- * @param count
- * The number of uris returned
- * @param uris
- * The uris in this domain that own resources
- */
- void getOwnerURIs(in ACString ownerAsciiDomain,
- out unsigned long count,
- [array, size_is(count)]out string uris);
-
- /**
- * Sets the resources owned by a given domain/URI pair.
- *
- * Setting a list will remove any resources previously owned by this
- * domain/URI pair.
- *
- * A key can be added while there is no associated entry. When
- * an entry is created with this key, it will be owned by the
- * domain/URI pair.
- *
- * @param ownerAsciiDomain
- * The domain that owns the resources
- * !! IMPORTANT !! : This must be ascii encoded host - nsIURI.asciiHost
- * @param ownerAsciiKey
- * The specific key that owns the resources. You may use
- * ascii encoded URI spec of the owner - nsIURI.asciiSpec.
- * This can be empty if none specifically owns the resources.
- * @param count
- * The number of keys in keys.
- * @param keys
- * The keys that the domain/URI pair own. This can be empty to
- * clear ownership for the domain/URI pair.
- */
- void setOwnedKeys(in ACString ownerAsciiDomain,
- in ACString ownerAsciiKey,
- in unsigned long count,
- [array, size_is(count)]in string keys);
-
- /**
- * Gets the list of resources owned by a given domain/URI pair.
- *
- * @param ownerAsciiDomain
- * The domain that owns the resources
- * !! IMPORTANT !! : This must be ascii encoded host - nsIURI.asciiHost
- * @param ownerAsciiKey
- * The specific key that owns the resources. You may use
- * ascii encoded URI spec of the owner - nsIURI.asciiSpec.
- * This can be empty if none specifically owns the resources.
- * @param count
- * The number of keys in keys.
- * @param keys
- * The keys that the domain/URI pair own.
- */
- void getOwnedKeys(in ACString ownerAsciiDomain,
- in ACString ownerAsciiKey,
- out unsigned long count,
- [array, size_is(count)]out string keys);
-
- /**
- * Adds an owned key to a domain/URI pair.
- *
- * A key can be added while there is no associated entry. When
- * an entry is created with this key, it will be owned by the
- * domain/URI pair.
- *
- * @param ownerAsciiDomain
- * The domain that owns the resources
- * !! IMPORTANT !! : This must be ascii encoded host - nsIURI.asciiHost
- * @param ownerAsciiKey
- * The specific key that owns the resources. You may use
- * ascii encoded URI spec of the owner - nsIURI.asciiSpec.
- * This can be empty if none specifically owns the resources.
- * @param key
- * The key to add.
- */
- void addOwnedKey(in ACString ownerAsciiDomain,
- in ACString ownerAsciiKey,
- in ACString key);
-
- /**
- * Removes an owned key from a domain/URI pair.
- *
- * If the key does not exist, an NS_ERROR_NOT_AVAILABLE exception
- * will be thrown.
- *
- * @param ownerAsciiDomain
- * The domain that owns the resources
- * !! IMPORTANT !! : This must be ascii encoded host - nsIURI.asciiHost
- * @param ownerAsciiKey
- * The specific key that owns the resources. You may use
- * ascii encoded URI spec of the owner - nsIURI.asciiSpec.
- * This can be empty if none specifically owns the resources.
- * @param key The key to remove.
- */
- void removeOwnedKey(in ACString ownerAsciiDomain,
- in ACString ownerAsciiKey,
- in ACString key);
-
- /**
- * Checks whether a key is owned by a given domain/URI pair.
- *
- * @param ownerAsciiDomain
- * The domain that owns the resources
- * !! IMPORTANT !! : This must be ascii encoded host - nsIURI.asciiHost
- * @param ownerAsciiKey
- * The specific key that owns the resources. You may use
- * ascii encoded URI spec of the owner - nsIURI.asciiSpec.
- * This can be empty if none specifically owns the resources.
- * @param key The key to check
- */
- boolean keyIsOwned(in ACString ownerAsciiDomain,
- in ACString ownerAsciiKey,
- in ACString key);
-
- /**
- * Remove all keys owned by a domain, including keys owned by
- * a specific URI.
- *
- * @param ownerAsciiDomain
- * The domain for which keys should be removed
- * !! IMPORTANT !! : This must be ascii encoded host - nsIURI.asciiHost
- */
- void clearKeysOwnedByDomain(in ACString ownerAsciiDomain);
-
- /**
- * Get the number of bytes used in the cache by a domain.
- *
- * @param domain The domain to check.
- */
- unsigned long getDomainUsage(in ACString ownerDomain);
-
- /**
- * Evict all entries that are not owned by a domain.
- */
- void evictUnownedEntries();
-
- /**
- * Merge the items from a temporary clientID in to this client. This lets
- * offline cache updates accumulate in a temporary client and be moved
- * in all at once.
- *
- * Entries in the temporary client will replace any entries in this client
- * with the same cache key.
- *
- * Ownership lists for a given domain/URI pair from the temporary client
- * will replace ownership lists for the same domain/URI pair.
- */
- void mergeTemporaryClientID(in ACString temporaryClientID);
-};
--- a/netwerk/cache/src/nsCacheService.cpp
+++ b/netwerk/cache/src/nsCacheService.cpp
@@ -658,18 +658,17 @@ nsCacheService::Shutdown()
mMemoryDevice = nsnull;
#ifdef NECKO_DISK_CACHE
delete mDiskDevice;
mDiskDevice = nsnull;
#endif // !NECKO_DISK_CACHE
#ifdef NECKO_OFFLINE_CACHE
- delete mOfflineDevice;
- mOfflineDevice = nsnull;
+ NS_IF_RELEASE(mOfflineDevice);
#endif // !NECKO_OFFLINE_CACHE
#if defined(NECKO_DISK_CACHE) && defined(PR_LOGGING)
LogCacheStatistics();
#endif
}
}
@@ -824,255 +823,16 @@ nsCacheService::IsStorageEnabledForPolic
if (gService->mEnableOfflineDevice &&
storagePolicy == nsICache::STORE_OFFLINE) {
return PR_TRUE;
}
return PR_FALSE;
}
-
-nsresult nsCacheService::GetOfflineOwnerDomains(nsCacheSession * session,
- PRUint32 * count,
- char *** domains)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->GetOwnerDomains(session->ClientID()->get(),
- count, domains);
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-
-nsresult nsCacheService::GetOfflineOwnerURIs(nsCacheSession * session,
- const nsACString & ownerDomain,
- PRUint32 * count,
- char *** uris)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->GetOwnerURIs(session->ClientID()->get(),
- ownerDomain, count, uris);
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-nsresult
-nsCacheService::SetOfflineOwnedKeys(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- PRUint32 count,
- const char ** keys)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->SetOwnedKeys(session->ClientID()->get(),
- ownerDomain,
- ownerURI,
- count,
- keys);
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-nsresult nsCacheService::GetOfflineOwnedKeys(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- PRUint32 * count,
- char *** keys)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->GetOwnedKeys(session->ClientID()->get(),
- ownerDomain,
- ownerURI,
- count,
- keys);
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-nsresult nsCacheService::AddOfflineOwnedKey(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- const nsACString & key)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->AddOwnedKey(session->ClientID()->get(),
- ownerDomain,
- ownerURI,
- key);
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-nsresult nsCacheService::RemoveOfflineOwnedKey(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- const nsACString & key)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->RemoveOwnedKey(session->ClientID()->get(),
- ownerDomain,
- ownerURI,
- key);
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-nsresult nsCacheService::OfflineKeyIsOwned(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- const nsACString & key,
- PRBool *isOwned)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->KeyIsOwned(session->ClientID()->get(),
- ownerDomain,
- ownerURI,
- key,
- isOwned);
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-nsresult nsCacheService::ClearOfflineKeysOwnedByDomain(nsCacheSession * session,
- const nsACString & domain)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->ClearKeysOwnedByDomain(session->ClientID()->get(),
- domain);
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-nsresult nsCacheService::GetOfflineDomainUsage(nsCacheSession * session,
- const nsACString & domain,
- PRUint32 * usage)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->GetDomainUsage(session->ClientID()->get(),
- domain,
- usage);
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-nsresult nsCacheService::EvictUnownedOfflineEntries(nsCacheSession * session)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->EvictUnownedEntries(session->ClientID()->get());
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-nsresult nsCacheService::MergeTemporaryClientID(nsCacheSession * session,
- const nsACString & clientID)
-{
-#ifdef NECKO_OFFLINE_CACHE
- if (session->StoragePolicy() != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->MergeTemporaryClientID
- (session->ClientID()->get(), PromiseFlatCString(clientID).get());
-#else // !NECKO_OFFLINE_CACHE
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor)
{
NS_ENSURE_ARG_POINTER(visitor);
nsCacheServiceAutoLock lock;
if (!(mEnableDiskDevice || mEnableMemoryDevice))
return NS_ERROR_NOT_AVAILABLE;
@@ -1119,30 +879,17 @@ NS_IMETHODIMP nsCacheService::VisitEntri
NS_IMETHODIMP nsCacheService::EvictEntries(nsCacheStoragePolicy storagePolicy)
{
return EvictEntriesForClient(nsnull, storagePolicy);
}
NS_IMETHODIMP nsCacheService::CreateTemporaryClientID(nsCacheStoragePolicy storagePolicy,
nsACString &clientID)
{
-#ifdef NECKO_OFFLINE_CACHE
- // Only the offline cache device supports temporary clients
- if (storagePolicy != nsICache::STORE_OFFLINE)
- return NS_ERROR_NOT_AVAILABLE;
-
- if (!gService->mOfflineDevice) {
- nsresult rv = gService->CreateOfflineDevice();
- if (NS_FAILED(rv)) return rv;
- }
-
- return gService->mOfflineDevice->CreateTemporaryClientID(clientID);
-#else // !NECKO_OFFLINE_CACHE
return NS_ERROR_NOT_IMPLEMENTED;
-#endif
}
/**
* Internal Methods
*/
nsresult
nsCacheService::CreateDiskDevice()
{
@@ -1183,29 +930,30 @@ nsCacheService::CreateOfflineDevice()
CACHE_LOG_ALWAYS(("Creating offline device"));
if (!mEnableOfflineDevice) return NS_ERROR_NOT_AVAILABLE;
if (mOfflineDevice) return NS_OK;
mOfflineDevice = new nsOfflineCacheDevice;
if (!mOfflineDevice) return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(mOfflineDevice);
+
// set the preferences
mOfflineDevice->SetCacheParentDirectory(
mObserver->OfflineCacheParentDirectory());
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;
+ NS_RELEASE(mOfflineDevice);
}
return rv;
#else // !NECKO_DISK_CACHE
NS_NOTREACHED("nsCacheService::CreateOfflineDevice");
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
--- a/netwerk/cache/src/nsCacheService.h
+++ b/netwerk/cache/src/nsCacheService.h
@@ -92,64 +92,16 @@ public:
nsICacheListener * listener,
nsICacheEntryDescriptor ** result);
static nsresult EvictEntriesForSession(nsCacheSession * session);
static nsresult IsStorageEnabledForPolicy(nsCacheStoragePolicy storagePolicy,
PRBool * result);
-
- static nsresult GetOfflineOwnerDomains(nsCacheSession * session,
- PRUint32 * count,
- char *** domains);
- static nsresult GetOfflineOwnerURIs(nsCacheSession * session,
- const nsACString & ownerDomain,
- PRUint32 * count,
- char *** uris);
-
- static nsresult SetOfflineOwnedKeys(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerUri,
- PRUint32 count,
- const char ** keys);
-
- static nsresult GetOfflineOwnedKeys(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- PRUint32 * count,
- char *** keys);
-
- static nsresult AddOfflineOwnedKey(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- const nsACString & key);
-
- static nsresult RemoveOfflineOwnedKey(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- const nsACString & key);
-
- static nsresult OfflineKeyIsOwned(nsCacheSession * session,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- const nsACString & key,
- PRBool * isOwned);
-
- static nsresult ClearOfflineKeysOwnedByDomain(nsCacheSession * session,
- const nsACString & domain);
- static nsresult GetOfflineDomainUsage(nsCacheSession * session,
- const nsACString & domain,
- PRUint32 * usage);
-
- static nsresult EvictUnownedOfflineEntries(nsCacheSession * session);
-
- static nsresult MergeTemporaryClientID(nsCacheSession * session,
- const nsACString & fromClientID);
-
/**
* Methods called by nsCacheEntryDescriptor
*/
static void CloseDescriptor(nsCacheEntryDescriptor * descriptor);
static nsresult GetFileForEntry(nsCacheEntry * entry,
nsIFile ** result);
@@ -203,16 +155,17 @@ public:
static void SetOfflineCacheCapacity(PRInt32 capacity);
static void SetMemoryCache();
nsresult Init();
void Shutdown();
private:
friend class nsCacheServiceAutoLock;
+ friend class nsOfflineCacheDevice;
/**
* Internal Methods
*/
static void Lock();
static void Unlock();
--- a/netwerk/cache/src/nsCacheSession.cpp
+++ b/netwerk/cache/src/nsCacheSession.cpp
@@ -39,25 +39,17 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCacheSession.h"
#include "nsCacheService.h"
#include "nsCRT.h"
-NS_IMPL_ADDREF(nsCacheSession)
-NS_IMPL_RELEASE(nsCacheSession)
-
-NS_INTERFACE_MAP_BEGIN(nsCacheSession)
- NS_INTERFACE_MAP_ENTRY(nsICacheSession)
- NS_INTERFACE_MAP_ENTRY_CONDITIONAL(
- nsIOfflineCacheSession, (StoragePolicy() == nsICache::STORE_OFFLINE))
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICacheSession)
-NS_INTERFACE_MAP_END
+NS_IMPL_ISUPPORTS1(nsCacheSession, nsICacheSession)
nsCacheSession::nsCacheSession(const char * clientID,
nsCacheStoragePolicy storagePolicy,
PRBool streamBased)
: mClientID(clientID),
mInfo(0)
{
SetStoragePolicy(storagePolicy);
@@ -130,80 +122,8 @@ NS_IMETHODIMP nsCacheSession::EvictEntri
}
NS_IMETHODIMP nsCacheSession::IsStorageEnabled(PRBool *result)
{
return nsCacheService::IsStorageEnabledForPolicy(StoragePolicy(), result);
}
-
-NS_IMETHODIMP nsCacheSession::GetOwnerDomains(PRUint32 * count,
- char *** domains)
-{
- return nsCacheService::GetOfflineOwnerDomains(this, count, domains);
-}
-
-NS_IMETHODIMP nsCacheSession::GetOwnerURIs(const nsACString & domain,
- PRUint32 * count,
- char *** uris)
-{
- return nsCacheService::GetOfflineOwnerURIs(this, domain, count, uris);
-}
-
-NS_IMETHODIMP nsCacheSession::SetOwnedKeys(const nsACString & domain,
- const nsACString & uri,
- PRUint32 count,
- const char ** keys)
-{
- return nsCacheService::SetOfflineOwnedKeys(this, domain, uri, count, keys);
-}
-
-NS_IMETHODIMP nsCacheSession::GetOwnedKeys(const nsACString & domain,
- const nsACString & uri,
- PRUint32 * count,
- char *** keys)
-{
- return nsCacheService::GetOfflineOwnedKeys(this, domain, uri, count, keys);
-}
-
-NS_IMETHODIMP nsCacheSession::AddOwnedKey(const nsACString & domain,
- const nsACString & uri,
- const nsACString & key)
-{
- return nsCacheService::AddOfflineOwnedKey(this, domain, uri, key);
-}
-
-NS_IMETHODIMP nsCacheSession::RemoveOwnedKey(const nsACString & domain,
- const nsACString & uri,
- const nsACString & key)
-{
- return nsCacheService::RemoveOfflineOwnedKey(this, domain, uri, key);
-}
-
-NS_IMETHODIMP nsCacheSession::KeyIsOwned(const nsACString & domain,
- const nsACString & uri,
- const nsACString & key,
- PRBool * isOwned)
-{
- return nsCacheService::OfflineKeyIsOwned(this, domain, uri, key, isOwned);
-}
-
-NS_IMETHODIMP nsCacheSession::ClearKeysOwnedByDomain(const nsACString & domain)
-{
- return nsCacheService::ClearOfflineKeysOwnedByDomain(this, domain);
-}
-
-NS_IMETHODIMP nsCacheSession::GetDomainUsage(const nsACString & domain,
- PRUint32 *usage)
-{
- return nsCacheService::GetOfflineDomainUsage(this, domain, usage);
-}
-
-NS_IMETHODIMP nsCacheSession::EvictUnownedEntries()
-{
- return nsCacheService::EvictUnownedOfflineEntries(this);
-}
-
-NS_IMETHODIMP nsCacheSession::MergeTemporaryClientID(const nsACString& fromClientID)
-{
- return nsCacheService::MergeTemporaryClientID(this, fromClientID);
-}
--- a/netwerk/cache/src/nsCacheSession.h
+++ b/netwerk/cache/src/nsCacheSession.h
@@ -41,26 +41,23 @@
* ***** END LICENSE BLOCK ***** */
#ifndef _nsCacheSession_h_
#define _nsCacheSession_h_
#include "nspr.h"
#include "nsError.h"
#include "nsICacheSession.h"
-#include "nsIOfflineCacheSession.h"
#include "nsString.h"
class nsCacheSession : public nsICacheSession
- , public nsIOfflineCacheSession
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICACHESESSION
- NS_DECL_NSIOFFLINECACHESESSION
nsCacheSession(const char * clientID, nsCacheStoragePolicy storagePolicy, PRBool streamBased);
virtual ~nsCacheSession();
nsCString * ClientID() { return &mClientID; }
enum SessionInfo {
eStoragePolicyMask = 0x000000FF,
--- a/netwerk/cache/src/nsDiskCacheDeviceSQL.cpp
+++ b/netwerk/cache/src/nsDiskCacheDeviceSQL.cpp
@@ -38,30 +38,32 @@
#include "nsCache.h"
#include "nsDiskCache.h"
#include "nsDiskCacheDeviceSQL.h"
#include "nsCacheService.h"
#include "nsNetUtil.h"
#include "nsAutoPtr.h"
+#include "nsEscape.h"
#include "nsString.h"
#include "nsPrintfCString.h"
#include "nsCRT.h"
#include "nsIVariant.h"
#include "mozIStorageService.h"
#include "mozIStorageStatement.h"
#include "mozIStorageFunction.h"
#include "mozStorageHelper.h"
#include "nsICacheVisitor.h"
#include "nsISeekableStream.h"
static const char OFFLINE_CACHE_DEVICE_ID[] = { "offline" };
+static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
#define LOG(args) CACHE_LOG_DEBUG(args)
static PRUint32 gNextTemporaryClientID = 0;
/*****************************************************************************
* helpers
*/
@@ -536,19 +538,153 @@ NS_IMETHODIMP
nsOfflineCacheEntryInfo::GetDataSize(PRUint32 *aDataSize)
{
*aDataSize = mRec->dataSize;
return NS_OK;
}
/******************************************************************************
+ * nsApplicationCache
+ */
+
+class nsApplicationCache : public nsIApplicationCache
+ , public nsSupportsWeakReference
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIAPPLICATIONCACHE
+
+ nsApplicationCache(nsOfflineCacheDevice *device,
+ const nsACString &group,
+ const nsACString &clientID);
+
+ virtual ~nsApplicationCache();
+
+ void MarkInvalid() { mValid = PR_FALSE; }
+
+private:
+ nsRefPtr<nsOfflineCacheDevice> mDevice;
+ nsCString mGroup;
+ nsCString mClientID;
+ PRBool mValid;
+};
+
+NS_IMPL_ISUPPORTS2(nsApplicationCache,
+ nsIApplicationCache,
+ nsISupportsWeakReference)
+
+nsApplicationCache::nsApplicationCache(nsOfflineCacheDevice *device,
+ const nsACString &group,
+ const nsACString &clientID)
+ : mDevice(device)
+ , mGroup(group)
+ , mClientID(clientID)
+ , mValid(PR_TRUE)
+{
+}
+
+nsApplicationCache::~nsApplicationCache()
+{
+ mDevice->mCaches.Remove(mClientID);
+
+ // If this isn't an active cache anymore, it can be destroyed.
+ if (mValid && !mDevice->IsActiveCache(mGroup, mClientID))
+ Discard();
+}
+
+NS_IMETHODIMP
+nsApplicationCache::GetGroupID(nsACString &out)
+{
+ out = mGroup;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsApplicationCache::GetClientID(nsACString &out)
+{
+ out = mClientID;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsApplicationCache::GetActive(PRBool *out)
+{
+ *out = mDevice->IsActiveCache(mGroup, mClientID);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsApplicationCache::Activate()
+{
+ NS_ENSURE_TRUE(mValid, NS_ERROR_NOT_AVAILABLE);
+
+ mDevice->ActivateCache(mGroup, mClientID);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsApplicationCache::Discard()
+{
+ NS_ENSURE_TRUE(mValid, NS_ERROR_NOT_AVAILABLE);
+
+ mValid = PR_FALSE;
+
+ if (mDevice->IsActiveCache(mGroup, mClientID))
+ {
+ mDevice->DeactivateGroup(mGroup);
+ }
+
+ return mDevice->EvictEntries(mClientID.get());
+}
+
+NS_IMETHODIMP
+nsApplicationCache::MarkEntry(const nsACString &key,
+ PRUint32 typeBits)
+{
+ NS_ENSURE_TRUE(mValid, NS_ERROR_NOT_AVAILABLE);
+
+ return mDevice->MarkEntry(mClientID, key, typeBits);
+}
+
+
+NS_IMETHODIMP
+nsApplicationCache::UnmarkEntry(const nsACString &key,
+ PRUint32 typeBits)
+{
+ NS_ENSURE_TRUE(mValid, NS_ERROR_NOT_AVAILABLE);
+
+ return mDevice->UnmarkEntry(mClientID, key, typeBits);
+}
+
+NS_IMETHODIMP
+nsApplicationCache::GetTypes(const nsACString &key,
+ PRUint32 *typeBits)
+{
+ NS_ENSURE_TRUE(mValid, NS_ERROR_NOT_AVAILABLE);
+
+ return mDevice->GetTypes(mClientID, key, typeBits);
+}
+
+NS_IMETHODIMP
+nsApplicationCache::GatherEntries(PRUint32 typeBits,
+ PRUint32 * count,
+ char *** keys)
+{
+ NS_ENSURE_TRUE(mValid, NS_ERROR_NOT_AVAILABLE);
+
+ return mDevice->GatherEntries(mClientID, typeBits, count, keys);
+}
+
+/******************************************************************************
* nsOfflineCacheDevice
*/
+NS_IMPL_ISUPPORTS1(nsOfflineCacheDevice, nsIApplicationCacheService)
+
nsOfflineCacheDevice::nsOfflineCacheDevice()
: mDB(nsnull)
, mCacheCapacity(0)
, mDeltaCounter(0)
{
}
nsOfflineCacheDevice::~nsOfflineCacheDevice()
@@ -692,16 +828,33 @@ nsOfflineCacheDevice::DeleteData(nsCache
return binding->mDataFile->Remove(PR_FALSE);
}
/**
* nsCacheDevice implementation
*/
+/* static */
+nsOfflineCacheDevice *
+nsOfflineCacheDevice::GetInstance()
+{
+ nsresult rv;
+ nsCOMPtr<nsICacheService> serv = do_GetService(kCacheServiceCID, &rv);
+ NS_ENSURE_SUCCESS(rv, nsnull);
+
+ nsICacheService *iservice = static_cast<nsICacheService*>(serv.get());
+ nsCacheService *cacheService = static_cast<nsCacheService*>(iservice);
+ rv = cacheService->CreateOfflineDevice();
+ NS_ENSURE_SUCCESS(rv, nsnull);
+
+ NS_IF_ADDREF(cacheService->mOfflineDevice);
+ return cacheService->mOfflineDevice;
+}
+
nsresult
nsOfflineCacheDevice::Init()
{
NS_ENSURE_TRUE(!mDB, NS_ERROR_ALREADY_INITIALIZED);
// SetCacheParentDirectory must have been called
NS_ENSURE_TRUE(mCacheDirectory, NS_ERROR_UNEXPECTED);
@@ -730,113 +883,187 @@ nsOfflineCacheDevice::Init()
// XXX in the future we may wish to verify the schema for moz_cache
// perhaps using "PRAGMA table_info" ?
// build the table
//
// "Generation" is the data file generation number.
// "Flags" is a bit-field indicating the state of the entry.
//
- mDB->ExecuteSimpleSQL(
- NS_LITERAL_CSTRING("CREATE TABLE moz_cache (\n"
+ rv = mDB->ExecuteSimpleSQL(
+ NS_LITERAL_CSTRING("CREATE TABLE IF NOT EXISTS moz_cache (\n"
" ClientID TEXT,\n"
" Key TEXT,\n"
" MetaData BLOB,\n"
" Generation INTEGER,\n"
" Flags INTEGER,\n"
" DataSize INTEGER,\n"
" FetchCount INTEGER,\n"
" LastFetched INTEGER,\n"
" LastModified INTEGER,\n"
- " ExpirationTime INTEGER\n"
+ " ExpirationTime INTEGER,\n"
+ " ItemType INTEGER DEFAULT 0\n"
");\n"));
- // maybe the table already exists, so don't bother checking for errors.
+ NS_ENSURE_SUCCESS(rv, rv);
- // build the ownership table
+ // Databases from 1.9.0 don't have the ItemType column. Add the column
+ // here, but don't worry about failures (the column probably already exists)
mDB->ExecuteSimpleSQL(
- NS_LITERAL_CSTRING("CREATE TABLE moz_cache_owners (\n"
- " ClientID TEXT,\n"
- " Domain TEXT,\n"
- " URI TEXT,\n"
- " Key TEXT\n"
+ NS_LITERAL_CSTRING("ALTER TABLE moz_cache ADD ItemType INTEGER DEFAULT 0"));
+
+ // Create the table for storing cache groups. All actions on
+ // moz_cache_groups use the GroupID, so use it as the primary key.
+ rv = mDB->ExecuteSimpleSQL(
+ NS_LITERAL_CSTRING("CREATE TABLE IF NOT EXISTS moz_cache_groups (\n"
+ " GroupID TEXT PRIMARY KEY,\n"
+ " ActiveClientID TEXT\n"
");\n"));
- // maybe the table already exists, so don't bother checking for errors.
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Databases from 1.9.0 have a moz_cache_index that should be dropped
+ rv = mDB->ExecuteSimpleSQL(
+ NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_cache_index"));
+ NS_ENSURE_SUCCESS(rv, rv);
- mDB->ExecuteSimpleSQL(
- NS_LITERAL_CSTRING("CREATE UNIQUE INDEX moz_cache_index"
- " ON moz_cache (ClientID, Key);"));
- // maybe the index already exists, so don't bother checking for errors.
+ // Key/ClientID pairs should be unique in the database. All queries
+ // against moz_cache use the Key (which is also the most unique), so
+ // use it as the primary key for this index.
+ rv = mDB->ExecuteSimpleSQL(
+ NS_LITERAL_CSTRING("CREATE UNIQUE INDEX IF NOT EXISTS "
+ " moz_cache_key_clientid_index"
+ " ON moz_cache (Key, ClientID);"));
+ NS_ENSURE_SUCCESS(rv, rv);
mEvictionFunction = new nsOfflineCacheEvictionFunction(this);
if (!mEvictionFunction) return NS_ERROR_OUT_OF_MEMORY;
rv = mDB->CreateFunction(NS_LITERAL_CSTRING("cache_eviction_observer"), 2, mEvictionFunction);
NS_ENSURE_SUCCESS(rv, rv);
// create all (most) of our statements up front
struct StatementSql {
nsCOMPtr<mozIStorageStatement> &statement;
const char *sql;
StatementSql (nsCOMPtr<mozIStorageStatement> &aStatement, const char *aSql):
statement (aStatement), sql (aSql) {}
} prepared[] = {
StatementSql ( mStatement_CacheSize, "SELECT Sum(DataSize) from moz_cache;" ),
- StatementSql ( mStatement_DomainSize, "SELECT Sum(moz_cache.DataSize) FROM moz_cache INNER JOIN moz_cache_owners ON moz_cache.ClientID=moz_cache_owners.ClientID AND moz_cache.Key = moz_cache_owners.Key WHERE moz_cache.ClientID=? AND moz_cache_owners.Domain=?;" ),
+ // XXX bug 442810: Restore the ability to monitor individual cache usage
+ StatementSql ( mStatement_DomainSize, "SELECT 0;"),
StatementSql ( mStatement_EntryCount, "SELECT count(*) from moz_cache;" ),
StatementSql ( mStatement_UpdateEntry, "UPDATE moz_cache SET MetaData = ?, Flags = ?, DataSize = ?, FetchCount = ?, LastFetched = ?, LastModified = ?, ExpirationTime = ? WHERE ClientID = ? AND Key = ?;" ),
StatementSql ( mStatement_UpdateEntrySize, "UPDATE moz_cache SET DataSize = ? WHERE ClientID = ? AND Key = ?;" ),
StatementSql ( mStatement_UpdateEntryFlags, "UPDATE moz_cache SET Flags = ? WHERE ClientID = ? AND Key = ?;" ),
StatementSql ( mStatement_DeleteEntry, "DELETE FROM moz_cache WHERE ClientID = ? AND Key = ?;" ),
StatementSql ( mStatement_FindEntry, "SELECT MetaData, Generation, Flags, DataSize, FetchCount, LastFetched, LastModified, ExpirationTime FROM moz_cache WHERE ClientID = ? AND Key = ?;" ),
StatementSql ( mStatement_BindEntry, "INSERT INTO moz_cache (ClientID, Key, MetaData, Generation, Flags, DataSize, FetchCount, LastFetched, LastModified, ExpirationTime) VALUES(?,?,?,?,?,?,?,?,?,?);" ),
- StatementSql ( mStatement_ClearOwnership, "DELETE FROM moz_cache_owners WHERE ClientId = ? AND Domain = ? AND URI = ?;" ),
- StatementSql ( mStatement_RemoveOwnership, "DELETE FROM moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ? AND Key = ?;" ),
- StatementSql ( mStatement_ClearDomain, "DELETE FROM moz_cache_owners WHERE ClientID = ? AND Domain = ?;" ),
- StatementSql ( mStatement_AddOwnership, "INSERT INTO moz_cache_owners (ClientID, Domain, URI, Key) VALUES (?, ?, ?, ?);" ),
- StatementSql ( mStatement_CheckOwnership, "SELECT Key From moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ? AND Key = ?;" ),
- StatementSql ( mStatement_ListOwned, "SELECT Key FROM moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ?;" ),
- StatementSql ( mStatement_ListOwners, "SELECT DISTINCT Domain, URI FROM moz_cache_owners WHERE ClientID = ?;"),
- StatementSql ( mStatement_ListOwnerDomains, "SELECT DISTINCT Domain FROM moz_cache_owners WHERE ClientID = ?;"),
- StatementSql ( mStatement_ListOwnerURIs, "SELECT DISTINCT URI FROM moz_cache_owners WHERE ClientID = ? AND Domain = ?;"),
- StatementSql ( mStatement_DeleteConflicts, "DELETE FROM moz_cache WHERE rowid IN (SELECT old.rowid FROM moz_cache AS old, moz_cache AS new WHERE old.Key = new.Key AND old.ClientID = ? AND new.ClientID = ?)"),
- StatementSql ( mStatement_DeleteUnowned, "DELETE FROM moz_cache WHERE rowid IN (SELECT moz_cache.rowid FROM moz_cache LEFT OUTER JOIN moz_cache_owners ON (moz_cache.ClientID = moz_cache_owners.ClientID AND moz_cache.Key = moz_cache_owners.Key) WHERE moz_cache.ClientID = ? AND moz_cache_owners.Domain ISNULL);" ),
- StatementSql ( mStatement_SwapClientID, "UPDATE OR REPLACE moz_cache SET ClientID = ? WHERE ClientID = ?;")
+
+ StatementSql ( mStatement_MarkEntry, "UPDATE moz_cache SET ItemType = (ItemType | ?) WHERE ClientID = ? AND Key = ?;" ),
+ StatementSql ( mStatement_UnmarkEntry, "UPDATE moz_cache SET ItemType = (ItemType & ~?) WHERE ClientID = ? AND Key = ?;" ),
+ StatementSql ( mStatement_GetTypes, "SELECT ItemType FROM moz_cache WHERE ClientID = ? AND Key = ?;"),
+ StatementSql ( mStatement_CleanupUnmarked, "DELETE FROM moz_cache WHERE ClientID = ? AND Key = ? AND ItemType = 0;" ),
+ StatementSql ( mStatement_GatherEntries, "SELECT Key FROM moz_cache WHERE ClientID = ? AND (ItemType & ?) > 0;" ),
+
+ StatementSql ( mStatement_ActivateClient, "INSERT OR REPLACE INTO moz_cache_groups (GroupID, ActiveClientID) VALUES (?, ?);" ),
+ StatementSql ( mStatement_DeactivateGroup, "DELETE FROM moz_cache_groups WHERE GroupID = ?;" ),
+ StatementSql ( mStatement_FindClient, "SELECT ClientID FROM moz_cache WHERE Key = ? ORDER BY LastFetched DESC, LastModified DESC;")
};
- for (PRUint32 i=0; i<NS_ARRAY_LENGTH(prepared); ++i)
+ for (PRUint32 i = 0; NS_SUCCEEDED(rv) && i < NS_ARRAY_LENGTH(prepared); ++i)
{
- rv |= mDB->CreateStatement(nsDependentCString(prepared[i].sql),
- getter_AddRefs(prepared[i].statement));
+ LOG(("Creating statement: %s\n", prepared[i].sql));
+
+ rv = mDB->CreateStatement(nsDependentCString(prepared[i].sql),
+ getter_AddRefs(prepared[i].statement));
+ NS_ENSURE_SUCCESS(rv, rv);
}
- NS_ENSURE_SUCCESS(rv, rv);
// Clear up any dangling active flags
rv = mDB->ExecuteSimpleSQL(
NS_LITERAL_CSTRING("UPDATE moz_cache"
" SET Flags=(Flags & ~1)"
" WHERE (Flags & 1);"));
NS_ENSURE_SUCCESS(rv, rv);
- // Clear up dangling temporary sessions
- EvictionObserver evictionObserver(mDB, mEvictionFunction);
+ rv = InitActiveCaches();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+nsresult
+nsOfflineCacheDevice::InitActiveCaches()
+{
+ NS_ENSURE_TRUE(mCaches.Init(), NS_ERROR_OUT_OF_MEMORY);
+ NS_ENSURE_TRUE(mActiveCachesByGroup.Init(), NS_ERROR_OUT_OF_MEMORY);
- rv = mDB->ExecuteSimpleSQL(
- NS_LITERAL_CSTRING("DELETE FROM moz_cache"
- " WHERE (ClientID GLOB \"TempClient*\")"));
+ nsresult rv = mActiveCaches.Init(5);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<mozIStorageStatement> statement;
+ rv =
+ mDB->CreateStatement(NS_LITERAL_CSTRING("SELECT GroupID, ActiveClientID"
+ " FROM moz_cache_groups"),
+ getter_AddRefs(statement));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRBool hasRows;
+ rv = statement->ExecuteStep(&hasRows);
NS_ENSURE_SUCCESS(rv, rv);
- evictionObserver.Apply();
+ while (hasRows)
+ {
+ nsCAutoString group;
+ statement->GetUTF8String(0, group);
+ nsCString clientID;
+ statement->GetUTF8String(1, clientID);
+
+ mActiveCaches.Put(clientID);
+ mActiveCachesByGroup.Put(group, new nsCString(clientID));
+
+ rv = statement->ExecuteStep(&hasRows);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
return NS_OK;
}
+/* static */
+PLDHashOperator
+nsOfflineCacheDevice::ShutdownApplicationCache(const nsACString &key,
+ nsIWeakReference *weakRef,
+ void *ctx)
+{
+ nsCOMPtr<nsIApplicationCache> obj = do_QueryReferent(weakRef);
+ if (obj)
+ {
+ nsApplicationCache *appCache = static_cast<nsApplicationCache*>(obj.get());
+ appCache->MarkInvalid();
+ }
+
+ return PL_DHASH_NEXT;
+}
+
nsresult
nsOfflineCacheDevice::Shutdown()
{
NS_ENSURE_TRUE(mDB, NS_ERROR_NOT_INITIALIZED);
+ if (mCaches.IsInitialized())
+ mCaches.EnumerateRead(ShutdownApplicationCache, this);
+
+ EvictionObserver evictionObserver(mDB, mEvictionFunction);
+
+ // Delete all rows whose clientID is not an active clientID.
+ nsresult rv = mDB->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM moz_cache WHERE rowid IN (SELECT moz_cache.rowid FROM moz_cache LEFT OUTER JOIN moz_cache_groups ON (moz_cache.ClientID = moz_cache_groups.ActiveClientID) WHERE moz_cache_groups.GroupID ISNULL)"));
+
+ if (NS_FAILED(rv))
+ NS_WARNING("Failed to clean up unused application caches.");
+ else
+ evictionObserver.Apply();
+
mDB = 0;
mEvictionFunction = 0;
return NS_OK;
}
const char *
nsOfflineCacheDevice::GetDeviceID()
@@ -1021,17 +1248,16 @@ nsOfflineCacheDevice::BindEntry(nsCacheE
rv |= statement->BindInt64Parameter(7, rec.lastFetched);
rv |= statement->BindInt64Parameter(8, rec.lastModified);
rv |= statement->BindInt64Parameter(9, rec.expirationTime);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasRows;
rv = statement->ExecuteStep(&hasRows);
NS_ENSURE_SUCCESS(rv, rv);
-
NS_ASSERTION(!hasRows, "INSERT should not result in output");
entry->SetData(binding);
return NS_OK;
}
void
nsOfflineCacheDevice::DoomEntry(nsCacheEntry *entry)
@@ -1245,41 +1471,147 @@ nsOfflineCacheDevice::EvictEntries(const
clientID ? clientID : ""));
// called to evict all entries matching the given clientID.
// need trigger to fire user defined function after a row is deleted
// so we can delete the corresponding data file.
EvictionObserver evictionObserver(mDB, mEvictionFunction);
- const char *deleteCmd;
+ nsCOMPtr<mozIStorageStatement> statement;
+ nsresult rv;
if (clientID)
{
- deleteCmd =
- PR_smprintf("DELETE FROM moz_cache WHERE ClientID=%q AND Flags=0;",
- clientID);
- if (!deleteCmd)
- return NS_ERROR_OUT_OF_MEMORY;
+ rv = mDB->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_cache WHERE ClientID=? AND Flags = 0;"),
+ getter_AddRefs(statement));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = statement->BindUTF8StringParameter(0, nsDependentCString(clientID));
+ NS_ENSURE_SUCCESS(rv, rv);
}
else
{
- deleteCmd = "DELETE FROM moz_cache WHERE Flags = 0;";
+ rv = mDB->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_cache WHERE Flags = 0;"),
+ getter_AddRefs(statement));
+ NS_ENSURE_SUCCESS(rv, rv);
}
- nsresult rv = mDB->ExecuteSimpleSQL(nsDependentCString(deleteCmd));
- if (clientID)
- PR_smprintf_free((char *) deleteCmd);
+ rv = statement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
evictionObserver.Apply();
return NS_OK;
}
nsresult
+nsOfflineCacheDevice::MarkEntry(const nsCString &clientID,
+ const nsACString &key,
+ PRUint32 typeBits)
+{
+ LOG(("nsOfflineCacheDevice::MarkEntry [cid=%s, key=%s, typeBits=%d]\n",
+ clientID.get(), PromiseFlatCString(key).get(), typeBits));
+
+ AutoResetStatement statement(mStatement_MarkEntry);
+ nsresult rv = statement->BindInt32Parameter(0, typeBits);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = statement->BindUTF8StringParameter(1, clientID);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = statement->BindUTF8StringParameter(2, key);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = statement->Execute();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+nsresult
+nsOfflineCacheDevice::UnmarkEntry(const nsCString &clientID,
+ const nsACString &key,
+ PRUint32 typeBits)
+{
+ LOG(("nsOfflineCacheDevice::UnmarkEntry [cid=%s, key=%s, typeBits=%d]\n",
+ clientID.get(), PromiseFlatCString(key).get(), typeBits));
+
+ AutoResetStatement statement(mStatement_UnmarkEntry);
+ nsresult rv = statement->BindInt32Parameter(0, typeBits);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = statement->BindUTF8StringParameter(1, clientID);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = statement->BindUTF8StringParameter(2, key);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = statement->Execute();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Remove the entry if it is now empty.
+
+ EvictionObserver evictionObserver(mDB, mEvictionFunction);
+
+ AutoResetStatement cleanupStatement(mStatement_CleanupUnmarked);
+ rv = cleanupStatement->BindUTF8StringParameter(0, clientID);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = cleanupStatement->BindUTF8StringParameter(1, key);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = cleanupStatement->Execute();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ evictionObserver.Apply();
+
+ return NS_OK;
+}
+
+nsresult
+nsOfflineCacheDevice::GetTypes(const nsCString &clientID,
+ const nsACString &key,
+ PRUint32 *typeBits)
+{
+ LOG(("nsOfflineCacheDevice::GetTypes [cid=%s, key=%s]\n",
+ clientID.get(), PromiseFlatCString(key).get()));
+
+ AutoResetStatement statement(mStatement_GetTypes);
+ nsresult rv = statement->BindUTF8StringParameter(0, clientID);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = statement->BindUTF8StringParameter(1, key);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRBool hasRows;
+ rv = statement->ExecuteStep(&hasRows);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!hasRows)
+ return NS_ERROR_CACHE_KEY_NOT_FOUND;
+
+ *typeBits = statement->AsInt32(0);
+
+ return NS_OK;
+}
+
+nsresult
+nsOfflineCacheDevice::GatherEntries(const nsCString &clientID,
+ PRUint32 typeBits,
+ PRUint32 *count,
+ char ***keys)
+{
+ LOG(("nsOfflineCacheDevice::GatherEntries [cid=%s, typeBits=%X]\n",
+ clientID.get(), typeBits));
+
+ AutoResetStatement statement(mStatement_GatherEntries);
+ nsresult rv = statement->BindUTF8StringParameter(0, clientID);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = statement->BindInt32Parameter(1, typeBits);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return RunSimpleQuery(mStatement_GatherEntries, 0, count, keys);
+}
+
+nsresult
nsOfflineCacheDevice::RunSimpleQuery(mozIStorageStatement * statement,
PRUint32 resultIndex,
PRUint32 * count,
char *** values)
{
PRBool hasRows;
nsresult rv = statement->ExecuteStep(&hasRows);
NS_ENSURE_SUCCESS(rv, rv);
@@ -1307,322 +1639,200 @@ nsOfflineCacheDevice::RunSimpleQuery(moz
}
}
*values = ret;
return NS_OK;
}
-nsresult
-nsOfflineCacheDevice::GetOwnerDomains(const char * clientID,
- PRUint32 * count,
- char *** domains)
+NS_IMETHODIMP
+nsOfflineCacheDevice::CreateApplicationCache(const nsACString &group,
+ nsIApplicationCache **out)
{
- LOG(("nsOfflineCacheDevice::GetOwnerDomains [cid=%s]\n", clientID));
-
- AutoResetStatement statement(mStatement_ListOwnerDomains);
- nsresult rv = statement->BindUTF8StringParameter(
- 0, nsDependentCString(clientID));
- NS_ENSURE_SUCCESS(rv, rv);
-
- return RunSimpleQuery(mStatement_ListOwnerDomains, 0, count, domains);
-}
-
-nsresult
-nsOfflineCacheDevice::GetOwnerURIs(const char * clientID,
- const nsACString & ownerDomain,
- PRUint32 * count,
- char *** domains)
-{
- LOG(("nsOfflineCacheDevice::GetOwnerURIs [cid=%s]\n", clientID));
-
- AutoResetStatement statement(mStatement_ListOwnerURIs);
- nsresult rv = statement->BindUTF8StringParameter(
- 0, nsDependentCString(clientID));
- rv = statement->BindUTF8StringParameter(
- 1, ownerDomain);
- NS_ENSURE_SUCCESS(rv, rv);
-
- return RunSimpleQuery(mStatement_ListOwnerURIs, 0, count, domains);
-}
+ *out = nsnull;
-nsresult
-nsOfflineCacheDevice::SetOwnedKeys(const char * clientID,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- PRUint32 count,
- const char ** keys)
-{
- LOG(("nsOfflineCacheDevice::SetOwnedKeys [cid=%s]\n", clientID));
- mozStorageTransaction transaction(mDB, PR_FALSE);
-
- nsDependentCString clientIDStr(clientID);
-
- AutoResetStatement clearStatement(mStatement_ClearOwnership);
- nsresult rv = clearStatement->BindUTF8StringParameter(
- 0, clientIDStr);
- rv |= clearStatement->BindUTF8StringParameter(1, ownerDomain);
- rv |= clearStatement->BindUTF8StringParameter(2, ownerURI);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = clearStatement->Execute();
- NS_ENSURE_SUCCESS(rv, rv);
-
- for (PRUint32 i = 0; i < count; i++)
- {
- AutoResetStatement insertStatement(mStatement_AddOwnership);
- rv = insertStatement->BindUTF8StringParameter(0, clientIDStr);
- rv |= insertStatement->BindUTF8StringParameter(1, ownerDomain);
- rv |= insertStatement->BindUTF8StringParameter(2, ownerURI);
- rv |= insertStatement->BindUTF8StringParameter(3, nsDependentCString(keys[i]));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = insertStatement->Execute();
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCString clientID;
+ // Some characters are special in the clientID. Escape the groupID
+ // before putting it in to the client key.
+ if (!NS_Escape(nsCString(group), clientID, url_Path)) {
+ return NS_ERROR_OUT_OF_MEMORY;
}
- return transaction.Commit();
-}
+ PRTime now = PR_Now();
+
+ // Include the timestamp to guarantee uniqueness across runs, and
+ // the gNextTemporaryClientID for uniqueness within a second.
+ clientID.Append(nsPrintfCString(64, "|%016lld|%d",
+ now / PR_USEC_PER_SEC,
+ gNextTemporaryClientID++));
-nsresult
-nsOfflineCacheDevice::GetOwnedKeys(const char * clientID,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- PRUint32 * count,
- char *** keys)
-{
- LOG(("nsOfflineCacheDevice::GetOwnedKeys [cid=%s]\n", clientID));
+ nsCOMPtr<nsIApplicationCache> cache = new nsApplicationCache(this,
+ group,
+ clientID);
+ if (!cache)
+ return NS_ERROR_OUT_OF_MEMORY;
- AutoResetStatement statement(mStatement_ListOwned);
- nsresult rv = statement->BindUTF8StringParameter(
- 0, nsDependentCString(clientID));
- rv |= statement->BindUTF8StringParameter(1, ownerDomain);
- rv |= statement->BindUTF8StringParameter(2, ownerURI);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(cache);
+ if (!weak)
+ return NS_ERROR_OUT_OF_MEMORY;
- return RunSimpleQuery(mStatement_ListOwned, 0, count, keys);
+ mCaches.Put(clientID, weak);
+
+ cache.swap(*out);
+
+ return NS_OK;
}
-nsresult
-nsOfflineCacheDevice::AddOwnedKey(const char * clientID,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- const nsACString & key)
+NS_IMETHODIMP
+nsOfflineCacheDevice::GetApplicationCache(const nsACString &clientID,
+ nsIApplicationCache **out)
{
- LOG(("nsOfflineCacheDevice::AddOwnedKey [cid=%s]\n", clientID));
+ *out = nsnull;
- PRBool isOwned;
- nsresult rv = KeyIsOwned(clientID, ownerDomain, ownerURI, key, &isOwned);
- NS_ENSURE_SUCCESS(rv, rv);
- if (isOwned) return NS_OK;
+ nsCOMPtr<nsIApplicationCache> cache;
- AutoResetStatement statement(mStatement_AddOwnership);
- rv = statement->BindUTF8StringParameter(0, nsDependentCString(clientID));
- rv |= statement->BindUTF8StringParameter(1, ownerDomain);
- rv |= statement->BindUTF8StringParameter(2, ownerURI);
- rv |= statement->BindUTF8StringParameter(3, key);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsWeakPtr weak;
+ if (mCaches.Get(clientID, getter_AddRefs(weak)))
+ cache = do_QueryReferent(weak);
- return statement->Execute();
-}
+ if (!cache)
+ {
+ nsCString group;
+ nsresult rv = GetGroupForCache(clientID, group);
+ NS_ENSURE_SUCCESS(rv, rv);
-nsresult
-nsOfflineCacheDevice::RemoveOwnedKey(const char * clientID,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- const nsACString & key)
-{
- LOG(("nsOfflineCacheDevice::RemoveOwnedKey [cid=%s]\n", clientID));
+ if (group.IsEmpty()) {
+ return NS_OK;
+ }
- PRBool isOwned;
- nsresult rv = KeyIsOwned(clientID, ownerDomain, ownerURI, key, &isOwned);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!isOwned) return NS_ERROR_NOT_AVAILABLE;
+ cache = new nsApplicationCache(this, group, clientID);
+ weak = do_GetWeakReference(cache);
+ if (!weak)
+ return NS_ERROR_OUT_OF_MEMORY;
- AutoResetStatement statement(mStatement_RemoveOwnership);
- rv = statement->BindUTF8StringParameter(0, nsDependentCString(clientID));
- rv |= statement->BindUTF8StringParameter(1, ownerDomain);
- rv |= statement->BindUTF8StringParameter(2, ownerURI);
- rv |= statement->BindUTF8StringParameter(3, key);
- NS_ENSURE_SUCCESS(rv, rv);
+ mCaches.Put(clientID, weak);
+ }
- return statement->Execute();
+ cache.swap(*out);
+
+ return NS_OK;
}
-nsresult
-nsOfflineCacheDevice::KeyIsOwned(const char * clientID,
- const nsACString & ownerDomain,
- const nsACString & ownerURI,
- const nsACString & key,
- PRBool * isOwned)
+NS_IMETHODIMP
+nsOfflineCacheDevice::GetActiveCache(const nsACString &group,
+ nsIApplicationCache **out)
{
- AutoResetStatement statement(mStatement_CheckOwnership);
- nsresult rv = statement->BindUTF8StringParameter(
- 0, nsDependentCString(clientID));
- rv |= statement->BindUTF8StringParameter(1, ownerDomain);
- rv |= statement->BindUTF8StringParameter(2, ownerURI);
- rv |= statement->BindUTF8StringParameter(3, key);
- NS_ENSURE_SUCCESS(rv, rv);
+ *out = nsnull;
- return statement->ExecuteStep(isOwned);
+ nsCString *clientID;
+ if (mActiveCachesByGroup.Get(group, &clientID))
+ return GetApplicationCache(*clientID, out);
+
+ return NS_OK;
}
-nsresult
-nsOfflineCacheDevice::ClearKeysOwnedByDomain(const char *clientID,
- const nsACString &domain)
+NS_IMETHODIMP
+nsOfflineCacheDevice::ChooseApplicationCache(const nsACString &key,
+ nsIApplicationCache **out)
{
- LOG(("nsOfflineCacheDevice::ClearKeysOwnedByDomain [cid=%s]\n", clientID));
-
- AutoResetStatement statement(mStatement_ClearDomain);
- nsresult rv = statement->BindUTF8StringParameter(
- 0, nsDependentCString(clientID));
- rv |= statement->BindUTF8StringParameter(1, domain);
- NS_ENSURE_SUCCESS(rv, rv);
-
- return statement->Execute();
-}
+ *out = nsnull;
-nsresult
-nsOfflineCacheDevice::GetDomainUsage(const char *clientID,
- const nsACString &domain,
- PRUint32 *usage)
-{
- LOG(("nsOfflineCacheDevice::GetDomainUsage [cid=%s]\n", clientID));
-
- *usage = 0;
-
- AutoResetStatement statement(mStatement_DomainSize);
- nsresult rv;
-
- rv = statement->BindUTF8StringParameter(0, nsDependentCString(clientID));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = statement->BindUTF8StringParameter(1, domain);
+ AutoResetStatement statement(mStatement_FindClient);
+ nsresult rv = statement->BindUTF8StringParameter(
+ 0, key);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasRows;
rv = statement->ExecuteStep(&hasRows);
NS_ENSURE_SUCCESS(rv, rv);
- if (!hasRows)
- return NS_OK;
-
- *usage = statement->AsInt32(0);
-
- return NS_OK;
-}
-
-nsresult
-nsOfflineCacheDevice::EvictUnownedEntries(const char *clientID)
-{
- LOG(("nsOfflineCacheDevice::EvictUnownedEntries [cid=%s]\n", clientID));
- EvictionObserver evictionObserver(mDB, mEvictionFunction);
+ while (hasRows) {
+ nsCString clientID;
+ rv = statement->GetUTF8String(0, clientID);
+ NS_ENSURE_SUCCESS(rv, rv);
- AutoResetStatement statement(mStatement_DeleteUnowned);
- nsresult rv = statement->BindUTF8StringParameter(
- 0, nsDependentCString(clientID));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = statement->Execute();
- NS_ENSURE_SUCCESS(rv, rv);
+ if (mActiveCaches.Contains(clientID))
+ return GetApplicationCache(clientID, out);
- evictionObserver.Apply();
- return NS_OK;
-}
-
-nsresult
-nsOfflineCacheDevice::CreateTemporaryClientID(nsACString &clientID)
-{
- nsCAutoString str;
- str.AssignLiteral("TempClient");
- str.AppendInt(gNextTemporaryClientID++);
-
- clientID.Assign(str);
+ rv = statement->ExecuteStep(&hasRows);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
return NS_OK;
}
nsresult
-nsOfflineCacheDevice::MergeTemporaryClientID(const char *clientID,
- const char *fromClientID)
+nsOfflineCacheDevice::ActivateCache(const nsCSubstring &group,
+ const nsCSubstring &clientID)
{
- LOG(("nsOfflineCacheDevice::MergeTemporaryClientID [cid=%s, from=%s]\n",
- clientID, fromClientID));
- mozStorageTransaction transaction(mDB, PR_FALSE);
+ AutoResetStatement statement(mStatement_ActivateClient);
+ nsresult rv = statement->BindUTF8StringParameter(0, group);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = statement->BindUTF8StringParameter(1, clientID);
+ NS_ENSURE_SUCCESS(rv, rv);
- // Move over ownerships
- AutoResetStatement listOwnersStatement(mStatement_ListOwners);
- nsresult rv = listOwnersStatement->BindUTF8StringParameter(
- 0, nsDependentCString(fromClientID));
+ rv = statement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
- // List all the owners in the new session
- nsTArray<nsCString> domainArray;
- nsTArray<nsCString> uriArray;
-
- PRBool hasRows;
- rv = listOwnersStatement->ExecuteStep(&hasRows);
- NS_ENSURE_SUCCESS(rv, rv);
- while (hasRows)
+ nsCString *active;
+ if (mActiveCachesByGroup.Get(group, &active))
{
- PRUint32 length;
- domainArray.AppendElement(
- nsDependentCString(listOwnersStatement->AsSharedUTF8String(0, &length)));
- uriArray.AppendElement(
- nsDependentCString(listOwnersStatement->AsSharedUTF8String(1, &length)));
+ mActiveCaches.Remove(*active);
+ mActiveCachesByGroup.Remove(group);
+ active = nsnull;
+ }
- rv = listOwnersStatement->ExecuteStep(&hasRows);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (!clientID.IsEmpty())
+ {
+ mActiveCaches.Put(clientID);
+ mActiveCachesByGroup.Put(group, new nsCString(clientID));
}
- // Now move over each ownership set
- for (PRUint32 i = 0; i < domainArray.Length(); i++) {
- PRUint32 count;
- char **keys;
- rv = GetOwnedKeys(fromClientID, domainArray[i], uriArray[i],
- &count, &keys);
- NS_ENSURE_SUCCESS(rv, rv);
+ return NS_OK;
+}
+
+PRBool
+nsOfflineCacheDevice::IsActiveCache(const nsCSubstring &group,
+ const nsCSubstring &clientID)
+{
+ nsCString *active = nsnull;
+ return mActiveCachesByGroup.Get(group, &active) && *active == clientID;
+}
- rv = SetOwnedKeys(clientID, domainArray[i], uriArray[i],
- count, const_cast<const char **>(keys));
- NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, keys);
- NS_ENSURE_SUCCESS(rv, rv);
+nsresult
+nsOfflineCacheDevice::DeactivateGroup(const nsCSubstring &group)
+{
+ nsCString *active = nsnull;
- // Now clear out the temporary session's copy
- rv = SetOwnedKeys(fromClientID, domainArray[i], uriArray[i], 0, 0);
- NS_ENSURE_SUCCESS(rv, rv);
+ AutoResetStatement statement(mStatement_DeactivateGroup);
+ nsresult rv = statement->BindUTF8StringParameter(
+ 0, group);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = statement->Execute();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (mActiveCachesByGroup.Get(group, &active))
+ {
+ mActiveCaches.Remove(*active);
+ mActiveCachesByGroup.Remove(group);
+ active = nsnull;
}
- EvictionObserver evictionObserver(mDB, mEvictionFunction);
-
- AutoResetStatement deleteStatement(mStatement_DeleteConflicts);
- rv = deleteStatement->BindUTF8StringParameter(
- 0, nsDependentCString(clientID));
- rv |= deleteStatement->BindUTF8StringParameter(
- 1, nsDependentCString(fromClientID));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = deleteStatement->Execute();
- NS_ENSURE_SUCCESS(rv, rv);
+ return NS_OK;
+}
- AutoResetStatement swapStatement(mStatement_SwapClientID);
- rv = swapStatement->BindUTF8StringParameter(
- 0, nsDependentCString(clientID));
- rv |= swapStatement->BindUTF8StringParameter(
- 1, nsDependentCString(fromClientID));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = swapStatement->Execute();
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = transaction.Commit();
- NS_ENSURE_SUCCESS(rv, rv);
-
- evictionObserver.Apply();
+nsresult
+nsOfflineCacheDevice::GetGroupForCache(const nsACString &clientID,
+ nsCString &out)
+{
+ out.Assign(clientID);
+ out.Truncate(out.FindChar('|'));
+ NS_UnescapeURL(out);
return NS_OK;
}
/**
* Preference accessors
*/
--- a/netwerk/cache/src/nsDiskCacheDeviceSQL.h
+++ b/netwerk/cache/src/nsDiskCacheDeviceSQL.h
@@ -34,25 +34,31 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsOfflineCacheDevice_h__
#define nsOfflineCacheDevice_h__
#include "nsCacheDevice.h"
+#include "nsIApplicationCache.h"
+#include "nsIApplicationCacheService.h"
#include "nsILocalFile.h"
#include "nsIObserver.h"
#include "mozIStorageConnection.h"
#include "mozIStorageFunction.h"
#include "nsIFile.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsVoidArray.h"
+#include "nsInterfaceHashtable.h"
+#include "nsClassHashtable.h"
+#include "nsHashSets.h"
+#include "nsWeakReference.h"
class nsOfflineCacheDevice;
class nsOfflineCacheEvictionFunction : public mozIStorageFunction {
public:
NS_DECL_ISUPPORTS
NS_DECL_MOZISTORAGEFUNCTION
@@ -65,26 +71,32 @@ public:
private:
nsOfflineCacheDevice *mDevice;
nsCOMArray<nsIFile> mItems;
};
class nsOfflineCacheDevice : public nsCacheDevice
+ , public nsIApplicationCacheService
{
public:
nsOfflineCacheDevice();
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIAPPLICATIONCACHESERVICE
+
/**
* nsCacheDevice methods
*/
virtual ~nsOfflineCacheDevice();
+ static nsOfflineCacheDevice *GetInstance();
+
virtual nsresult Init();
virtual nsresult Shutdown();
virtual const char * GetDeviceID(void);
virtual nsCacheEntry * FindEntry(nsCString * key, PRBool *collision);
virtual nsresult DeactivateEntry(nsCacheEntry * entry);
virtual nsresult BindEntry(nsCacheEntry * entry);
virtual void DoomEntry( nsCacheEntry * entry );
@@ -138,46 +150,69 @@ public:
nsresult KeyIsOwned(const char * clientID,
const nsACString & ownerDomain,
const nsACString & ownerURI,
const nsACString & key,
PRBool * isOwned);
nsresult ClearKeysOwnedByDomain(const char *clientID,
const nsACString &ownerDomain);
- nsresult GetDomainUsage(const char *clientID,
- const nsACString &ownerDomain,
- PRUint32 *usage);
nsresult EvictUnownedEntries(const char *clientID);
- nsresult CreateTemporaryClientID(nsACString &clientID);
- nsresult MergeTemporaryClientID(const char *clientID,
- const char *fromClientID);
-
+ nsresult ActivateCache(const nsCSubstring &group,
+ const nsCSubstring &clientID);
+ PRBool IsActiveCache(const nsCSubstring &group,
+ const nsCSubstring &clientID);
+ nsresult DeactivateGroup(const nsCSubstring &group);
+ nsresult GetGroupForCache(const nsCSubstring &clientID,
+ nsCString &out);
/**
* Preference accessors
*/
void SetCacheParentDirectory(nsILocalFile * parentDir);
void SetCapacity(PRUint32 capacity);
nsILocalFile * CacheDirectory() { return mCacheDirectory; }
PRUint32 CacheCapacity() { return mCacheCapacity; }
PRUint32 CacheSize();
PRUint32 EntryCount();
private:
+ friend class nsApplicationCache;
+
+ static PLDHashOperator ShutdownApplicationCache(const nsACString &key,
+ nsIWeakReference *weakRef,
+ void *ctx);
+
PRBool Initialized() { return mDB != nsnull; }
+
+ nsresult InitActiveCaches();
nsresult UpdateEntry(nsCacheEntry *entry);
nsresult UpdateEntrySize(nsCacheEntry *entry, PRUint32 newSize);
nsresult DeleteEntry(nsCacheEntry *entry, PRBool deleteData);
nsresult DeleteData(nsCacheEntry *entry);
nsresult EnableEvictionObserver();
nsresult DisableEvictionObserver();
+
+ nsresult MarkEntry(const nsCString &clientID,
+ const nsACString &key,
+ PRUint32 typeBits);
+ nsresult UnmarkEntry(const nsCString &clientID,
+ const nsACString &key,
+ PRUint32 typeBits);
+ nsresult GetTypes(const nsCString &clientID,
+ const nsACString &key,
+ PRUint32 *typeBits);
+ nsresult GatherEntries(const nsCString &clientID,
+ PRUint32 typeBits,
+ PRUint32 *count,
+ char *** values);
+
nsresult RunSimpleQuery(mozIStorageStatement *statment,
PRUint32 resultIndex,
PRUint32 * count,
char *** values);
nsCOMPtr<mozIStorageConnection> mDB;
nsRefPtr<nsOfflineCacheEvictionFunction> mEvictionFunction;
@@ -185,27 +220,28 @@ private:
nsCOMPtr<mozIStorageStatement> mStatement_DomainSize;
nsCOMPtr<mozIStorageStatement> mStatement_EntryCount;
nsCOMPtr<mozIStorageStatement> mStatement_UpdateEntry;
nsCOMPtr<mozIStorageStatement> mStatement_UpdateEntrySize;
nsCOMPtr<mozIStorageStatement> mStatement_UpdateEntryFlags;
nsCOMPtr<mozIStorageStatement> mStatement_DeleteEntry;
nsCOMPtr<mozIStorageStatement> mStatement_FindEntry;
nsCOMPtr<mozIStorageStatement> mStatement_BindEntry;
- nsCOMPtr<mozIStorageStatement> mStatement_ClearOwnership;
- nsCOMPtr<mozIStorageStatement> mStatement_RemoveOwnership;
nsCOMPtr<mozIStorageStatement> mStatement_ClearDomain;
- nsCOMPtr<mozIStorageStatement> mStatement_AddOwnership;
- nsCOMPtr<mozIStorageStatement> mStatement_CheckOwnership;
- nsCOMPtr<mozIStorageStatement> mStatement_DeleteConflicts;
- nsCOMPtr<mozIStorageStatement> mStatement_DeleteUnowned;
- nsCOMPtr<mozIStorageStatement> mStatement_ListOwned;
- nsCOMPtr<mozIStorageStatement> mStatement_ListOwners;
- nsCOMPtr<mozIStorageStatement> mStatement_ListOwnerDomains;
- nsCOMPtr<mozIStorageStatement> mStatement_ListOwnerURIs;
- nsCOMPtr<mozIStorageStatement> mStatement_SwapClientID;
+ nsCOMPtr<mozIStorageStatement> mStatement_MarkEntry;
+ nsCOMPtr<mozIStorageStatement> mStatement_UnmarkEntry;
+ nsCOMPtr<mozIStorageStatement> mStatement_GetTypes;
+ nsCOMPtr<mozIStorageStatement> mStatement_CleanupUnmarked;
+ nsCOMPtr<mozIStorageStatement> mStatement_GatherEntries;
+ nsCOMPtr<mozIStorageStatement> mStatement_ActivateClient;
+ nsCOMPtr<mozIStorageStatement> mStatement_DeactivateGroup;
+ nsCOMPtr<mozIStorageStatement> mStatement_FindClient;
nsCOMPtr<nsILocalFile> mCacheDirectory;
PRUint32 mCacheCapacity;
PRInt32 mDeltaCounter;
+
+ nsInterfaceHashtable<nsCStringHashKey, nsIWeakReference> mCaches;
+ nsClassHashtable<nsCStringHashKey, nsCString> mActiveCachesByGroup;
+ nsCStringHashSet mActiveCaches;
};
#endif // nsOfflineCacheDevice_h__
--- a/netwerk/protocol/http/src/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/src/nsHttpChannel.cpp
@@ -42,16 +42,17 @@
#include "nsHttpChannel.h"
#include "nsHttpTransaction.h"
#include "nsHttpConnection.h"
#include "nsHttpHandler.h"
#include "nsHttpAuthCache.h"
#include "nsHttpResponseHead.h"
#include "nsHttp.h"
#include "nsIHttpAuthenticator.h"
+#include "nsIApplicationCacheService.h"
#include "nsIAuthInformation.h"
#include "nsIAuthPrompt2.h"
#include "nsIAuthPromptProvider.h"
#include "nsIStringBundle.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "nsIURL.h"
#include "nsIIDNService.h"
@@ -1366,36 +1367,71 @@ nsHttpChannel::OpenCacheEntry(PRBool off
return NS_ERROR_NOT_AVAILABLE;
accessRequested = nsICache::ACCESS_READ;
}
else if (BYPASS_LOCAL_CACHE(mLoadFlags))
accessRequested = nsICache::ACCESS_WRITE; // replace cache entry
else
accessRequested = nsICache::ACCESS_READ_WRITE; // normal browsing
+ if (!mApplicationCache) {
+ // Pick up an application cache from the load group if available
+ nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer;
+ GetCallback(appCacheContainer);
+
+ if (appCacheContainer) {
+ appCacheContainer->GetApplicationCache(getter_AddRefs(mApplicationCache));
+ }
+
+ if ((mLoadFlags & LOAD_CHECK_OFFLINE_CACHE) && !mApplicationCache) {
+ // We're supposed to load from an application cache, but
+ // one was not supplied by the load group. Ask the
+ // application cache service to choose one for us.
+ nsCOMPtr<nsIApplicationCacheService> appCacheService =
+ do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID);
+ if (appCacheService) {
+ nsresult rv = appCacheService->ChooseApplicationCache
+ (cacheKey, getter_AddRefs(mApplicationCache));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+ }
+
nsCOMPtr<nsICacheSession> session;
- if (mLoadFlags & LOAD_CHECK_OFFLINE_CACHE) {
- // when LOAD_CHECK_OFFLINE_CACHE set prefer the offline cache
- rv = gHttpHandler->GetCacheSession(nsICache::STORE_OFFLINE,
- 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.
+
+ // If we have an application cache, we check it first.
+ if (mApplicationCache) {
+ nsCAutoString appCacheClientID;
+ mApplicationCache->GetClientID(appCacheClientID);
+
+ nsCOMPtr<nsICacheService> serv =
+ do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = serv->CreateSession(appCacheClientID.get(),
+ nsICache::STORE_OFFLINE,
+ nsICache::STREAM_BASED,
+ getter_AddRefs(session));
+ NS_ENSURE_SUCCESS(rv, 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.
//
- // we need open in ACCESS_READ only because we don't want to overwrite
- // the offline cache entry non-atomically so ACCESS_READ
- // will prevent us from writing to the HTTP-offline cache as a
- // normal cache entry.
- rv = session->OpenCacheEntry(cacheKey, nsICache::ACCESS_READ, PR_FALSE,
+ // we need open in ACCESS_READ only because we don't want to
+ // overwrite the offline cache entry non-atomically so
+ // ACCESS_READ will prevent us from writing to the
+ // HTTP-offline cache as a normal cache entry. XXX: this
+ // needs to be checked.
+ rv = session->OpenCacheEntry(cacheKey,
+ nsICache::ACCESS_READ, PR_FALSE,
getter_AddRefs(mCacheEntry));
}
- if (!(mLoadFlags & LOAD_CHECK_OFFLINE_CACHE) ||
+ if (!mApplicationCache ||
(NS_FAILED(rv) && rv != NS_ERROR_CACHE_WAIT_FOR_VALIDATION))
{
rv = gHttpHandler->GetCacheSession(storagePolicy,
getter_AddRefs(session));
if (NS_FAILED(rv)) return rv;
rv = session->OpenCacheEntry(cacheKey, accessRequested, PR_FALSE,
getter_AddRefs(mCacheEntry));
@@ -1452,30 +1488,28 @@ nsHttpChannel::OpenOfflineCacheEntryForW
// don't use the cache if our consumer is making a conditional request
// (see bug 331825).
return NS_OK;
}
nsCAutoString cacheKey;
GenerateCacheKey(cacheKey);
+ NS_ENSURE_TRUE(!mOfflineCacheClientID.IsEmpty(),
+ NS_ERROR_NOT_AVAILABLE);
+
nsCOMPtr<nsICacheSession> session;
- if (!mOfflineCacheClientID.IsEmpty()) {
- nsCOMPtr<nsICacheService> serv =
- do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
- if (NS_FAILED(rv)) return rv;
-
- rv = serv->CreateSession(mOfflineCacheClientID.get(),
- nsICache::STORE_OFFLINE,
- nsICache::STREAM_BASED,
- getter_AddRefs(session));
- } else {
- rv = gHttpHandler->GetCacheSession(nsICache::STORE_OFFLINE,
- getter_AddRefs(session));
- }
+ nsCOMPtr<nsICacheService> serv =
+ do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) return rv;
+
+ rv = serv->CreateSession(mOfflineCacheClientID.get(),
+ nsICache::STORE_OFFLINE,
+ nsICache::STREAM_BASED,
+ 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
@@ -3382,16 +3416,17 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
NS_INTERFACE_MAP_ENTRY(nsICacheListener)
NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyCallback)
NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
+ NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
//-----------------------------------------------------------------------------
// nsHttpChannel::nsIRequest
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsHttpChannel::GetName(nsACString &aName)
@@ -4872,16 +4907,34 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnec
rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority);
if (NS_FAILED(rv)) return rv;
return mTransactionPump->AsyncRead(this, nsnull);
}
//-----------------------------------------------------------------------------
+// nsHttpChannel::nsIApplicationCacheContainer
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+nsHttpChannel::GetApplicationCache(nsIApplicationCache **out)
+{
+ NS_IF_ADDREF(*out = mApplicationCache);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHttpChannel::SetApplicationCache(nsIApplicationCache *appCache)
+{
+ mApplicationCache = appCache;
+ return NS_OK;
+}
+
+
+//-----------------------------------------------------------------------------
// nsHttpChannel::nsContentEncodings <public>
//-----------------------------------------------------------------------------
nsHttpChannel::nsContentEncodings::nsContentEncodings(nsIHttpChannel* aChannel,
const char* aEncodingHeader) :
mEncodingHeader(aEncodingHeader), mChannel(aChannel), mReady(PR_FALSE)
{
mCurEnd = aEncodingHeader + strlen(aEncodingHeader);
--- a/netwerk/protocol/http/src/nsHttpChannel.h
+++ b/netwerk/protocol/http/src/nsHttpChannel.h
@@ -61,18 +61,21 @@
#include "nsIIOService.h"
#include "nsIURI.h"
#include "nsILoadGroup.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIInputStream.h"
#include "nsIProgressEventSink.h"
#include "nsICachingChannel.h"
+#include "nsICacheSession.h"
#include "nsICacheEntryDescriptor.h"
#include "nsICacheListener.h"
+#include "nsIApplicationCache.h"
+#include "nsIApplicationCacheContainer.h"
#include "nsIEncodedChannel.h"
#include "nsITransport.h"
#include "nsIUploadChannel.h"
#include "nsIStringEnumerator.h"
#include "nsIOutputStream.h"
#include "nsIAsyncInputStream.h"
#include "nsIPrompt.h"
#include "nsIResumableChannel.h"
@@ -98,16 +101,17 @@ class nsHttpChannel : public nsHashPrope
, public nsIUploadChannel
, public nsICacheListener
, public nsIEncodedChannel
, public nsITransportEventSink
, public nsIResumableChannel
, public nsISupportsPriority
, public nsIProtocolProxyCallback
, public nsIProxiedChannel
+ , public nsIApplicationCacheContainer
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIREQUEST
NS_DECL_NSICHANNEL
NS_DECL_NSIHTTPCHANNEL
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
@@ -116,16 +120,17 @@ public:
NS_DECL_NSICACHELISTENER
NS_DECL_NSIENCODEDCHANNEL
NS_DECL_NSIHTTPCHANNELINTERNAL
NS_DECL_NSITRANSPORTEVENTSINK
NS_DECL_NSIRESUMABLECHANNEL
NS_DECL_NSISUPPORTSPRIORITY
NS_DECL_NSIPROTOCOLPROXYCALLBACK
NS_DECL_NSIPROXIEDCHANNEL
+ NS_DECL_NSIAPPLICATIONCACHECONTAINER
nsHttpChannel();
virtual ~nsHttpChannel();
nsresult Init(nsIURI *uri,
PRUint8 capabilities,
nsProxyInfo* proxyInfo);
@@ -258,16 +263,18 @@ private:
nsCacheAccessMode mCacheAccess;
PRUint32 mPostID;
PRUint32 mRequestTime;
nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry;
nsCacheAccessMode mOfflineCacheAccess;
nsCString mOfflineCacheClientID;
+ nsCOMPtr<nsIApplicationCache> mApplicationCache;
+
// auth specific data
nsISupports *mProxyAuthContinuationState;
nsCString mProxyAuthType;
nsISupports *mAuthContinuationState;
nsCString mAuthType;
nsHttpAuthIdentity mIdent;
nsHttpAuthIdentity mProxyIdent;
--- a/uriloader/prefetch/nsIOfflineCacheUpdate.idl
+++ b/uriloader/prefetch/nsIOfflineCacheUpdate.idl
@@ -110,31 +110,37 @@ interface nsIOfflineCacheUpdateObserver
* Each update object maintains a list of nsIDOMLoadStatus items for the
* resources it is updating. The list of these items will be available
* after the object is scheduled.
*
* One update object will be updating at a time. The active object will
* load its items one by one, sending itemCompleted() to any registered
* observers.
*/
-[scriptable, uuid(7dc06ede-1098-4384-b95e-65525ab254c9)]
+[scriptable, uuid(4b206247-82ee-46cf-a8b7-f7284e753bc2)]
interface nsIOfflineCacheUpdate : nsISupports {
/**
* Fetch the status of the running update. This will return a value
* defined in nsIDOMOfflineResourceList.
*/
readonly attribute unsigned short status;
/**
* TRUE if the update is being used to add specific resources.
* FALSE if the complete cache update process is happening.
*/
readonly attribute boolean partial;
/**
+ * TRUE if this is an upgrade attempt, FALSE if it is a new cache
+ * attempt.
+ */
+ readonly attribute boolean isUpgrade;
+
+ /**
* The domain being updated, and the domain that will own any URIs added
* with this update.
*/
readonly attribute ACString updateDomain;
/**
* The manifest for the offline application being updated.
*/
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -35,24 +35,26 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsOfflineCacheUpdate.h"
#include "nsCPrefetchService.h"
#include "nsCURILoader.h"
+#include "nsIApplicationCacheContainer.h"
+#include "nsIApplicationCacheService.h"
#include "nsICache.h"
#include "nsICacheService.h"
#include "nsICacheSession.h"
#include "nsICachingChannel.h"
#include "nsIDOMWindow.h"
#include "nsIDOMOfflineResourceList.h"
#include "nsIObserverService.h"
-#include "nsIOfflineCacheSession.h"
+#include "nsIURL.h"
#include "nsIWebProgress.h"
#include "nsICryptoHash.h"
#include "nsICacheEntryDescriptor.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
@@ -99,40 +101,65 @@ NS_IMPL_ISUPPORTS6(nsOfflineCacheUpdateI
//-----------------------------------------------------------------------------
// nsOfflineCacheUpdateItem <public>
//-----------------------------------------------------------------------------
nsOfflineCacheUpdateItem::nsOfflineCacheUpdateItem(nsOfflineCacheUpdate *aUpdate,
nsIURI *aURI,
nsIURI *aReferrerURI,
- const nsACString &aClientID)
+ nsIApplicationCache *aPreviousApplicationCache,
+ const nsACString &aClientID,
+ PRUint32 type)
: mURI(aURI)
, mReferrerURI(aReferrerURI)
+ , mPreviousApplicationCache(aPreviousApplicationCache)
, mClientID(aClientID)
+ , mItemType(type)
, mUpdate(aUpdate)
, mChannel(nsnull)
, mState(nsIDOMLoadStatus::UNINITIALIZED)
, mBytesRead(0)
{
}
nsOfflineCacheUpdateItem::~nsOfflineCacheUpdateItem()
{
}
nsresult
nsOfflineCacheUpdateItem::OpenChannel()
{
- nsresult rv = NS_NewChannel(getter_AddRefs(mChannel),
- mURI,
- nsnull, nsnull, this,
- nsIRequest::LOAD_BACKGROUND |
- nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
- nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE);
+#if defined(PR_LOGGING)
+ if (LOG_ENABLED()) {
+ nsCAutoString spec;
+ mURI->GetSpec(spec);
+ LOG(("%p: Opening channel for %s", this, spec.get()));
+ }
+#endif
+
+ nsresult rv = nsOfflineCacheUpdate::GetCacheKey(mURI, mCacheKey);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = NS_NewChannel(getter_AddRefs(mChannel),
+ mURI,
+ nsnull, nsnull, this,
+ nsIRequest::LOAD_BACKGROUND |
+ nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
+ nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
+ do_QueryInterface(mChannel, &rv);
+
+ // Support for nsIApplicationCacheContainer is required.
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Use the existing application cache as the cache to check.
+ rv = appCacheContainer->SetApplicationCache(mPreviousApplicationCache);
NS_ENSURE_SUCCESS(rv, rv);
// configure HTTP specific stuff
nsCOMPtr<nsIHttpChannel> httpChannel =
do_QueryInterface(mChannel);
if (httpChannel) {
httpChannel->SetReferrer(mReferrerURI);
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
@@ -387,18 +414,21 @@ nsOfflineCacheUpdateItem::GetStatus(PRUi
//-----------------------------------------------------------------------------
// nsOfflineManifestItem <public>
//-----------------------------------------------------------------------------
nsOfflineManifestItem::nsOfflineManifestItem(nsOfflineCacheUpdate *aUpdate,
nsIURI *aURI,
nsIURI *aReferrerURI,
+ nsIApplicationCache *aPreviousApplicationCache,
const nsACString &aClientID)
- : nsOfflineCacheUpdateItem(aUpdate, aURI, aReferrerURI, aClientID)
+ : nsOfflineCacheUpdateItem(aUpdate, aURI, aReferrerURI,
+ aPreviousApplicationCache, aClientID,
+ nsIApplicationCache::ITEM_MANIFEST)
, mParserState(PARSE_INIT)
, mNeedsUpdate(PR_TRUE)
, mManifestHashInitialized(PR_FALSE)
{
}
nsOfflineManifestItem::~nsOfflineManifestItem()
{
@@ -752,30 +782,52 @@ nsOfflineCacheUpdate::nsOfflineCacheUpda
{
}
nsOfflineCacheUpdate::~nsOfflineCacheUpdate()
{
LOG(("nsOfflineCacheUpdate::~nsOfflineCacheUpdate [%p]", this));
}
+/* static */
+nsresult
+nsOfflineCacheUpdate::GetCacheKey(nsIURI *aURI, nsACString &aKey)
+{
+ aKey.Truncate();
+
+ nsCOMPtr<nsIURI> newURI;
+ nsresult rv = aURI->Clone(getter_AddRefs(newURI));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIURL> newURL;
+ newURL = do_QueryInterface(newURI);
+ if (newURL) {
+ newURL->SetRef(EmptyCString());
+ }
+
+ rv = newURI->GetAsciiSpec(aKey);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
nsresult
nsOfflineCacheUpdate::Init(PRBool aPartialUpdate,
nsIURI *aManifestURI,
nsIURI *aDocumentURI)
{
nsresult rv;
// Make sure the service has been initialized
nsOfflineCacheUpdateService* service =
nsOfflineCacheUpdateService::EnsureService();
if (!service)
return NS_ERROR_FAILURE;
- LOG(("nsOfflineCacheUpdate::Init [%p]", this));
+ LOG(("nsOfflineCacheUpdate::Init [%p, %d]", this, aPartialUpdate));
mPartialUpdate = aPartialUpdate;
// Only http and https applications are supported.
PRBool match;
rv = aManifestURI->SchemeIs("http", &match);
NS_ENSURE_SUCCESS(rv, rv);
@@ -788,68 +840,41 @@ nsOfflineCacheUpdate::Init(PRBool aParti
mManifestURI = aManifestURI;
rv = mManifestURI->GetAsciiHost(mUpdateDomain);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString manifestSpec;
- rv = mManifestURI->GetAsciiSpec(manifestSpec);
+ rv = GetCacheKey(mManifestURI, manifestSpec);
NS_ENSURE_SUCCESS(rv, rv);
- PRInt32 ref = manifestSpec.FindChar('#');
- if (ref != kNotFound)
- manifestSpec.Truncate(ref);
-
- mManifestOwnerSpec = manifestSpec;
- mManifestOwnerSpec.AppendLiteral("#manifest");
-
- mDynamicOwnerSpec = manifestSpec;
- mDynamicOwnerSpec.AppendLiteral("#dynamic");
-
mDocumentURI = aDocumentURI;
- nsCOMPtr<nsICacheService> cacheService =
- do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
+ nsCOMPtr<nsIApplicationCacheService> cacheService =
+ do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsICacheSession> session;
- rv = cacheService->CreateSession("HTTP-offline",
- nsICache::STORE_OFFLINE,
- nsICache::STREAM_BASED,
- getter_AddRefs(session));
- NS_ENSURE_SUCCESS(rv, rv);
-
- mMainCacheSession = do_QueryInterface(session, &rv);
+ rv = cacheService->GetActiveCache(manifestSpec,
+ getter_AddRefs(mPreviousApplicationCache));
NS_ENSURE_SUCCESS(rv, rv);
- // Partial updates don't use temporary cache sessions
- if (aPartialUpdate) {
- mCacheSession = mMainCacheSession;
+ // Partial updates to existing application caches don't need a new cache.
+ if (aPartialUpdate && mPreviousApplicationCache) {
+ mApplicationCache = mPreviousApplicationCache;
} else {
- rv = cacheService->CreateTemporaryClientID(nsICache::STORE_OFFLINE,
- mClientID);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = cacheService->CreateSession(mClientID.get(),
- nsICache::STORE_OFFLINE,
- nsICache::STREAM_BASED,
- getter_AddRefs(session));
- NS_ENSURE_SUCCESS(rv, rv);
-
- mCacheSession = do_QueryInterface(session, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // The manifest implicitly owns itself.
- rv = mCacheSession->AddOwnedKey(mUpdateDomain, mManifestOwnerSpec,
- manifestSpec);
+ rv = cacheService->CreateApplicationCache(manifestSpec,
+ getter_AddRefs(mApplicationCache));
NS_ENSURE_SUCCESS(rv, rv);
}
+ rv = mApplicationCache->GetClientID(mClientID);
+ NS_ENSURE_SUCCESS(rv, rv);
+
mState = STATE_INITIALIZED;
return NS_OK;
}
nsresult
nsOfflineCacheUpdate::HandleManifest(PRBool *aDoUpdate)
{
@@ -866,27 +891,31 @@ nsOfflineCacheUpdate::HandleManifest(PRB
if (!mManifestItem->NeedsUpdate()) {
return NS_OK;
}
// Add items requested by the manifest.
const nsCOMArray<nsIURI> &manifestURIs = mManifestItem->GetExplicitURIs();
for (PRInt32 i = 0; i < manifestURIs.Count(); i++) {
- rv = AddURI(manifestURIs[i], mManifestOwnerSpec);
+ rv = AddURI(manifestURIs[i], nsIApplicationCache::ITEM_EXPLICIT);
NS_ENSURE_SUCCESS(rv, rv);
}
// The document that requested the manifest is implicitly included
// as part of that manifest update.
- rv = AddURI(mDocumentURI, mManifestOwnerSpec);
+ rv = AddURI(mDocumentURI, nsIApplicationCache::ITEM_IMPLICIT);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Add items previously cached implicitly
+ rv = AddExistingItems(nsIApplicationCache::ITEM_IMPLICIT);
NS_ENSURE_SUCCESS(rv, rv);
// Add items requested by the script API
- rv = AddOwnedItems(mDynamicOwnerSpec);
+ rv = AddExistingItems(nsIApplicationCache::ITEM_DYNAMIC);
NS_ENSURE_SUCCESS(rv, rv);
*aDoUpdate = PR_TRUE;
return NS_OK;
}
void
@@ -917,16 +946,25 @@ nsOfflineCacheUpdate::LoadCompleted()
if (!doUpdate) {
mSucceeded = PR_FALSE;
NotifyNoUpdate();
Finish();
return;
}
+ rv = mApplicationCache->MarkEntry(mManifestItem->mCacheKey,
+ mManifestItem->mItemType);
+ if (NS_FAILED(rv)) {
+ mSucceeded = PR_FALSE;
+ NotifyError();
+ Finish();
+ return;
+ }
+
mState = STATE_DOWNLOADING;
NotifyDownloading();
// Start fetching resources.
ProcessNextURI();
return;
}
@@ -942,16 +980,24 @@ nsOfflineCacheUpdate::LoadCompleted()
// Check for failures. 4XX and 5XX errors will cause the update to fail.
if (NS_FAILED(rv) || status == 0 || status >= 400) {
mSucceeded = PR_FALSE;
NotifyError();
Finish();
return;
}
+ rv = mApplicationCache->MarkEntry(item->mCacheKey, item->mItemType);
+ if (NS_FAILED(rv)) {
+ mSucceeded = PR_FALSE;
+ NotifyError();
+ Finish();
+ return;
+ }
+
rv = NotifyCompleted(item);
if (NS_FAILED(rv)) return;
ProcessNextURI();
}
nsresult
nsOfflineCacheUpdate::Begin()
@@ -966,17 +1012,19 @@ nsOfflineCacheUpdate::Begin()
ProcessNextURI();
return NS_OK;
}
// Start checking the manifest.
nsCOMPtr<nsIURI> uri;
mManifestItem = new nsOfflineManifestItem(this, mManifestURI,
- mDocumentURI, mClientID);
+ mDocumentURI,
+ mPreviousApplicationCache,
+ mClientID);
if (!mManifestItem) {
return NS_ERROR_OUT_OF_MEMORY;
}
mState = STATE_CHECKING;
NotifyChecking();
nsresult rv = mManifestItem->OpenChannel();
@@ -1004,35 +1052,35 @@ nsOfflineCacheUpdate::Cancel()
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsOfflineCacheUpdate <private>
//-----------------------------------------------------------------------------
nsresult
-nsOfflineCacheUpdate::AddOwnedItems(const nsACString &aOwnerURI)
+nsOfflineCacheUpdate::AddExistingItems(PRUint32 aType)
{
- PRUint32 count;
- char **keys;
- nsresult rv = mMainCacheSession->GetOwnedKeys(mUpdateDomain, aOwnerURI,
- &count, &keys);
+ if (!mPreviousApplicationCache) {
+ return NS_OK;
+ }
+
+ PRUint32 count = 0;
+ char **keys = nsnull;
+ nsresult rv = mPreviousApplicationCache->GatherEntries(aType,
+ &count, &keys);
NS_ENSURE_SUCCESS(rv, rv);
AutoFreeArray autoFree(count, keys);
for (PRUint32 i = 0; i < count; i++) {
nsCOMPtr<nsIURI> uri;
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), keys[i]))) {
- nsRefPtr<nsOfflineCacheUpdateItem> item =
- new nsOfflineCacheUpdateItem(this, uri, mDocumentURI,
- mClientID);
- if (!item) return NS_ERROR_OUT_OF_MEMORY;
-
- mItems.AppendElement(item);
+ rv = AddURI(uri, aType);
+ NS_ENSURE_SUCCESS(rv, rv);
}
}
return NS_OK;
}
nsresult
nsOfflineCacheUpdate::ProcessNextURI()
@@ -1085,16 +1133,18 @@ nsOfflineCacheUpdate::GatherObservers(ns
return NS_OK;
}
nsresult
nsOfflineCacheUpdate::NotifyError()
{
LOG(("nsOfflineCacheUpdate::NotifyError [%p]", this));
+ mState = STATE_FINISHED;
+
nsCOMArray<nsIOfflineCacheUpdateObserver> observers;
nsresult rv = GatherObservers(observers);
NS_ENSURE_SUCCESS(rv, rv);
for (PRInt32 i = 0; i < observers.Count(); i++) {
observers[i]->Error(this);
}
@@ -1117,16 +1167,18 @@ nsOfflineCacheUpdate::NotifyChecking()
return NS_OK;
}
nsresult
nsOfflineCacheUpdate::NotifyNoUpdate()
{
LOG(("nsOfflineCacheUpdate::NotifyNoUpdate [%p]", this));
+ mState = STATE_FINISHED;
+
nsCOMArray<nsIOfflineCacheUpdateObserver> observers;
nsresult rv = GatherObservers(observers);
NS_ENSURE_SUCCESS(rv, rv);
for (PRInt32 i = 0; i < observers.Count(); i++) {
observers[i]->NoUpdate(this);
}
@@ -1191,28 +1243,30 @@ nsOfflineCacheUpdate::Finish()
nsOfflineCacheUpdateService* service =
nsOfflineCacheUpdateService::EnsureService();
if (!service)
return NS_ERROR_FAILURE;
if (!mPartialUpdate) {
if (mSucceeded) {
- nsresult rv = mMainCacheSession->MergeTemporaryClientID(mClientID);
+ nsresult rv = mApplicationCache->Activate();
if (NS_FAILED(rv)) {
NotifyError();
mSucceeded = PR_FALSE;
}
}
if (!mSucceeded) {
// Update was not merged, mark all the loads as failures
for (PRUint32 i = 0; i < mItems.Length(); i++) {
mItems[i]->Cancel();
}
+
+ mApplicationCache->Discard();
}
}
return service->UpdateFinished(this);
}
//-----------------------------------------------------------------------------
// nsOfflineCacheUpdate::nsIOfflineCacheUpdate
@@ -1266,73 +1320,85 @@ nsOfflineCacheUpdate::GetSucceeded(PRBoo
{
NS_ENSURE_TRUE(mState == STATE_FINISHED, NS_ERROR_NOT_AVAILABLE);
*aSucceeded = mSucceeded;
return NS_OK;
}
+NS_IMETHODIMP
+nsOfflineCacheUpdate::GetIsUpgrade(PRBool *aIsUpgrade)
+{
+ NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
+
+ *aIsUpgrade = (mPreviousApplicationCache != nsnull);
+
+ return NS_OK;
+}
+
nsresult
-nsOfflineCacheUpdate::AddURI(nsIURI *aURI, const nsACString &aOwnerSpec)
+nsOfflineCacheUpdate::AddURI(nsIURI *aURI, PRUint32 aType)
{
NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
if (mState >= STATE_DOWNLOADING)
return NS_ERROR_NOT_AVAILABLE;
- // Manifest URIs must have the same scheme as the manifest.
+ // Resource URIs must have the same scheme as the manifest.
nsCAutoString scheme;
aURI->GetScheme(scheme);
PRBool match;
if (NS_FAILED(mManifestURI->SchemeIs(scheme.get(), &match)) || !match)
return NS_ERROR_FAILURE;
- // Save the cache key as an owned URI
- nsCAutoString spec;
- nsresult rv = aURI->GetSpec(spec);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // url fragments aren't used in cache keys
- nsCAutoString::const_iterator specStart, specEnd;
- spec.BeginReading(specStart);
- spec.EndReading(specEnd);
- if (FindCharInReadable('#', specStart, specEnd)) {
- spec.BeginReading(specEnd);
- rv = mCacheSession->AddOwnedKey(mUpdateDomain, aOwnerSpec,
- Substring(specEnd, specStart));
- NS_ENSURE_SUCCESS(rv, rv);
- } else {
- rv = mCacheSession->AddOwnedKey(mUpdateDomain, aOwnerSpec, spec);
- NS_ENSURE_SUCCESS(rv, rv);
- }
-
// Don't fetch the same URI twice.
for (PRUint32 i = 0; i < mItems.Length(); i++) {
PRBool equals;
if (NS_SUCCEEDED(mItems[i]->mURI->Equals(aURI, &equals)) && equals) {
+ // retain both types.
+ mItems[i]->mItemType |= aType;
return NS_OK;
}
}
nsRefPtr<nsOfflineCacheUpdateItem> item =
- new nsOfflineCacheUpdateItem(this, aURI, mDocumentURI, mClientID);
+ new nsOfflineCacheUpdateItem(this, aURI, mDocumentURI,
+ mPreviousApplicationCache, mClientID,
+ aType);
if (!item) return NS_ERROR_OUT_OF_MEMORY;
mItems.AppendElement(item);
mAddedItems = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsOfflineCacheUpdate::AddDynamicURI(nsIURI *aURI)
{
- return AddURI(aURI, mDynamicOwnerSpec);
+ // If this is a partial update and the resource is already in the
+ // cache, we should only mark the entry, not fetch it again.
+ if (mPartialUpdate) {
+ nsCAutoString key;
+ GetCacheKey(aURI, key);
+
+ PRUint32 types;
+ nsresult rv = mApplicationCache->GetTypes(key, &types);
+ if (NS_SUCCEEDED(rv)) {
+ if (!(types & nsIApplicationCache::ITEM_DYNAMIC)) {
+ mApplicationCache->MarkEntry
+ (key, nsIApplicationCache::ITEM_DYNAMIC);
+ }
+ return NS_OK;
+ }
+ }
+
+ return AddURI(aURI, nsIApplicationCache::ITEM_DYNAMIC);
}
NS_IMETHODIMP
nsOfflineCacheUpdate::GetCount(PRUint32 *aNumItems)
{
LOG(("nsOfflineCacheUpdate::GetNumItems [%p, num=%d]",
this, mItems.Length()));
--- a/uriloader/prefetch/nsOfflineCacheUpdate.h
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.h
@@ -47,18 +47,17 @@
#include "nsICacheService.h"
#include "nsIChannelEventSink.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNode.h"
#include "nsIDOMLoadStatus.h"
#include "nsIInterfaceRequestor.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
-#include "nsIOfflineCacheSession.h"
-#include "nsIPrefetchService.h"
+#include "nsIApplicationCache.h"
#include "nsIRequestObserver.h"
#include "nsIRunnable.h"
#include "nsIStreamListener.h"
#include "nsIURI.h"
#include "nsIWebProgressListener.h"
#include "nsClassHashtable.h"
#include "nsString.h"
#include "nsTArray.h"
@@ -82,22 +81,27 @@ public:
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIRUNNABLE
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
nsOfflineCacheUpdateItem(nsOfflineCacheUpdate *aUpdate,
nsIURI *aURI,
nsIURI *aReferrerURI,
- const nsACString &aClientID);
+ nsIApplicationCache *aPreviousApplicationCache,
+ const nsACString &aClientID,
+ PRUint32 aType);
virtual ~nsOfflineCacheUpdateItem();
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrerURI;
+ nsCOMPtr<nsIApplicationCache> mPreviousApplicationCache;
nsCString mClientID;
+ nsCString mCacheKey;
+ PRUint32 mItemType;
nsresult OpenChannel();
nsresult Cancel();
private:
nsOfflineCacheUpdate* mUpdate;
nsCOMPtr<nsIChannel> mChannel;
PRUint16 mState;
@@ -111,16 +115,17 @@ class nsOfflineManifestItem : public nsO
{
public:
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
nsOfflineManifestItem(nsOfflineCacheUpdate *aUpdate,
nsIURI *aURI,
nsIURI *aReferrerURI,
+ nsIApplicationCache *aPreviousApplicationCache,
const nsACString &aClientID);
virtual ~nsOfflineManifestItem();
nsCOMArray<nsIURI> &GetExplicitURIs() { return mExplicitURIs; }
PRBool ParseSucceeded()
{ return (mParserState != PARSE_INIT && mParserState != PARSE_ERROR); }
PRBool NeedsUpdate() { return mParserState != PARSE_INIT && mNeedsUpdate; }
@@ -172,29 +177,32 @@ class nsOfflineCacheUpdate : public nsIO
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOFFLINECACHEUPDATE
nsOfflineCacheUpdate();
~nsOfflineCacheUpdate();
+ static nsresult GetCacheKey(nsIURI *aURI, nsACString &aKey);
+
nsresult Init();
nsresult Begin();
nsresult Cancel();
void LoadCompleted();
+
private:
nsresult HandleManifest(PRBool *aDoUpdate);
- nsresult AddURI(nsIURI *aURI, const nsACString &aOwnerSpec);
+ nsresult AddURI(nsIURI *aURI, PRUint32 aItemType);
nsresult ProcessNextURI();
- nsresult AddOwnedItems(const nsACString &aOwnerURI);
+ nsresult AddExistingItems(PRUint32 aType);
nsresult GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers);
nsresult NotifyError();
nsresult NotifyChecking();
nsresult NotifyNoUpdate();
nsresult NotifyDownloading();
nsresult NotifyStarted(nsOfflineCacheUpdateItem *aItem);
nsresult NotifyCompleted(nsOfflineCacheUpdateItem *aItem);
@@ -209,24 +217,22 @@ private:
STATE_FINISHED
} mState;
PRBool mAddedItems;
PRBool mPartialUpdate;
PRBool mSucceeded;
nsCString mUpdateDomain;
nsCOMPtr<nsIURI> mManifestURI;
- nsCString mManifestOwnerSpec;
- nsCString mDynamicOwnerSpec;
nsCOMPtr<nsIURI> mDocumentURI;
nsCString mClientID;
- nsCOMPtr<nsIOfflineCacheSession> mCacheSession;
- nsCOMPtr<nsIOfflineCacheSession> mMainCacheSession;
+ nsCOMPtr<nsIApplicationCache> mApplicationCache;
+ nsCOMPtr<nsIApplicationCache> mPreviousApplicationCache;
nsCOMPtr<nsIObserverService> mObserverService;
nsRefPtr<nsOfflineManifestItem> mManifestItem;
/* Items being updated */
PRInt32 mCurrentItem;
nsTArray<nsRefPtr<nsOfflineCacheUpdateItem> > mItems;