Backed out changeset ebafb9df6ce0 (bug 442806)
authorDave Camp <dcamp@mozilla.com>
Sun, 24 Aug 2008 23:11:31 -0700
changeset 18362 e376bc87ac4ac55653d08eae143ceeff73f0c2bf
parent 18361 ebafb9df6ce0aaf17bb68508ceded54ce15114c1
child 18363 f50234e5a17bb1223e4daa2692c7b8349dbc7aa0
push idunknown
push userunknown
push dateunknown
bugs442806
milestone1.9.1a2pre
backs outebafb9df6ce0aaf17bb68508ceded54ce15114c1
Backed out changeset ebafb9df6ce0 (bug 442806)
browser/base/content/browser.js
browser/components/preferences/advanced.js
content/base/src/nsContentSink.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
docshell/base/nsDocShell.cpp
dom/src/offline/Makefile.in
dom/src/offline/nsDOMOfflineResourceList.cpp
dom/src/offline/nsDOMOfflineResourceList.h
dom/tests/mochitest/ajax/offline/offlineTests.js
dom/tests/mochitest/ajax/offline/test_changingManifest.html
dom/tests/mochitest/ajax/offline/test_simpleManifest.html
netwerk/base/public/Makefile.in
netwerk/base/public/nsIApplicationCache.idl
netwerk/base/public/nsIApplicationCacheContainer.idl
netwerk/base/public/nsIApplicationCacheService.idl
netwerk/base/public/nsINetUtil.idl
netwerk/base/public/nsNetUtil.h
netwerk/base/src/nsIOService.cpp
netwerk/base/src/nsIOService.h
netwerk/build/Makefile.in
netwerk/build/nsNetCID.h
netwerk/build/nsNetModule.cpp
netwerk/cache/public/Makefile.in
netwerk/cache/public/nsICacheService.idl
netwerk/cache/public/nsIOfflineCacheSession.idl
netwerk/cache/src/nsCacheService.cpp
netwerk/cache/src/nsCacheService.h
netwerk/cache/src/nsCacheSession.cpp
netwerk/cache/src/nsCacheSession.h
netwerk/cache/src/nsDiskCacheDeviceSQL.cpp
netwerk/cache/src/nsDiskCacheDeviceSQL.h
netwerk/protocol/http/src/nsHttpChannel.cpp
netwerk/protocol/http/src/nsHttpChannel.h
uriloader/prefetch/nsIOfflineCacheUpdate.idl
uriloader/prefetch/nsOfflineCacheUpdate.cpp
uriloader/prefetch/nsOfflineCacheUpdate.h
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5405,18 +5405,24 @@ var OfflineApps = {
              getService(Ci.nsIPermissionManager);
     pm.add(aURI, "offline-app",
            Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
   },
 
   // XXX: duplicated in preferences/advanced.js
   _getOfflineAppUsage: function (host)
   {
-    // XXX Bug 442810: include offline cache usage.
-    var usage = 0;
+    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);
+
     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,18 +211,23 @@ var gAdvancedPane = {
     document.documentElement.openWindow("Browser:Permissions",
                                         "chrome://browser/content/preferences/permissions.xul",
                                         "", params);
   },
 
   // XXX: duplicated in browser.js
   _getOfflineAppUsage: function (host)
   {
-    // XXX Bug 442710: include offline cache usage.
-    var usage = 0;
+    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);
 
     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,18 +66,16 @@
 #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"
@@ -878,34 +876,16 @@ 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,17 +799,51 @@ nsContentUtils::GetOfflineAppManifest(ns
   nsContentUtils::NewURIWithDocumentCharset(aURI, manifestSpec,
                                             topDoc, topDoc->GetBaseURI());
 }
 
 /* static */
 PRBool
 nsContentUtils::OfflineAppAllowed(nsIURI *aURI)
 {
-  return NS_OfflineAppAllowed(aURI, sPrefBranch);
+  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;
 }
 
 // static
 void
 nsContentUtils::Shutdown()
 {
   sInitialized = PR_FALSE;
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1138,17 +1138,16 @@ 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)) ||
@@ -1950,32 +1949,16 @@ 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,18 +88,16 @@
 #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"
@@ -405,17 +403,16 @@ 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);
@@ -756,19 +753,16 @@ 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);
@@ -1028,20 +1022,16 @@ 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,19 +138,16 @@
 #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"
@@ -456,32 +453,16 @@ 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));
@@ -7289,25 +7270,16 @@ 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,17 +54,16 @@ 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,28 +68,29 @@
 
 // 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 gCachedManifestSpec;
+static nsCAutoString gCachedAsciiHost;
 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)
@@ -108,16 +109,17 @@ 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)
@@ -174,30 +176,46 @@ 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;
 
-  mApplicationCacheService =
-    do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
+  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);
   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;
@@ -296,21 +314,16 @@ 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;
@@ -356,79 +369,59 @@ 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();
 
-  // 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->RemoveOwnedKey(mAsciiHost, mDynamicOwnerSpec, key);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = appCache->UnmarkEntry(key, nsIApplicationCache::ITEM_DYNAMIC);
+  rv = mCacheSession->EvictUnownedEntries();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMOfflineResourceList::GetStatus(PRUint16 *aStatus)
 {
   nsresult rv = Init();
 
-  // 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)) {
+  // 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) {
     *aStatus = nsIDOMOfflineResourceList::UNCACHED;
     return NS_OK;
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // If there is an update in process, use its status.
   if (mCacheUpdate) {
-    rv = mCacheUpdate->GetStatus(aStatus);
-    if (NS_SUCCEEDED(rv) && *aStatus != nsIDOMOfflineResourceList::IDLE) {
-      return NS_OK;
-    }
+    return mCacheUpdate->GetStatus(aStatus);
   }
 
-  // If this object is not associated with a cache, return UNCACHED
-  nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
-  if (!appCache) {
-    *aStatus = nsIDOMOfflineResourceList::UNCACHED;
-    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.
 
-  nsCOMPtr<nsIApplicationCache> activeCache;
-  rv = mApplicationCacheService->GetActiveCache(mManifestSpec,
-                                                getter_AddRefs(activeCache));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (appCache == activeCache) {
+  if (nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
     *aStatus = nsIDOMOfflineResourceList::IDLE;
   } else {
-    *aStatus = nsIDOMOfflineResourceList::UPDATEREADY;
+    *aStatus = nsIDOMOfflineResourceList::UNCACHED;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMOfflineResourceList::Update()
 {
@@ -456,45 +449,17 @@ nsDOMOfflineResourceList::SwapCache()
 {
   nsresult rv = Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  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;
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 //
 // nsDOMOfflineResourceList::nsIDOMEventTarget
 //
 
 NS_IMETHODIMP
 nsDOMOfflineResourceList::GetOnchecking(nsIDOMEventListener **aOnchecking)
@@ -974,35 +939,30 @@ 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 && !partial) {
-    if (isUpgrade) {
-      SendEvent(NS_LITERAL_STRING(UPDATEREADY_STR),
-                mOnUpdateReadyListener, mUpdateReadyListeners);
-    } else {
-      SendEvent(NS_LITERAL_STRING(CACHED_STR),
-                mOnCachedListener, mCachedListeners);
-    }
+  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);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsDOMOfflineResourceList::GetCacheKey(nsIURI *aURI, nsCString &aKey)
 {
@@ -1016,79 +976,39 @@ 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 && mManifestSpec == gCachedManifestSpec)
+  if (gCachedKeys && mAsciiHost == gCachedAsciiHost)
     return NS_OK;
 
   ClearCachedKeys();
 
-  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);
+  nsresult rv = mCacheSession->GetOwnedKeys(mAsciiHost, mDynamicOwnerSpec,
+                                            &gCachedKeysCount, &gCachedKeys);
 
   if (NS_SUCCEEDED(rv))
-    gCachedManifestSpec = mManifestSpec;
+    gCachedAsciiHost = mAsciiHost;
 
   return rv;
 }
 
 void
 nsDOMOfflineResourceList::ClearCachedKeys()
 {
   if (gCachedKeys) {
     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(gCachedKeysCount, gCachedKeys);
     gCachedKeys = nsnull;
     gCachedKeysCount = 0;
   }
 
-  gCachedManifestSpec = "";
+  gCachedAsciiHost = "";
 }
 
+
+
--- a/dom/src/offline/nsDOMOfflineResourceList.h
+++ b/dom/src/offline/nsDOMOfflineResourceList.h
@@ -36,19 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsDOMOfflineResourceList_h___
 #define nsDOMOfflineResourceList_h___
 
 #include "nscore.h"
 #include "nsIDOMOfflineResourceList.h"
-#include "nsIApplicationCache.h"
-#include "nsIApplicationCacheContainer.h"
-#include "nsIApplicationCacheService.h"
+#include "nsIOfflineCacheSession.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"
@@ -94,36 +92,31 @@ 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<nsIApplicationCacheService> mApplicationCacheService;
+  nsCOMPtr<nsIOfflineCacheSession> mCacheSession;
   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,19 +46,24 @@ fetch: function(callback)
   if (this.urls.length == 0) {
     callback(this.contents);
     return;
   }
 
   var url = this.urls.shift();
   var self = this;
 
-  var cacheSession = OfflineTest.getActiveSession();
+  var cacheService = Cc["@mozilla.org/network/cache-service;1"]
+                     .getService(Ci.nsICacheService);
+  var cacheSession = cacheService.createSession("HTTP-offline",
+                                                Ci.nsICache.STORE_OFFLINE,
+                                                true);
   cacheSession.asyncOpenCacheEntry(url, Ci.nsICache.ACCESS_READ, this);
 }
+
 };
 
 var OfflineTest = {
 
 _slaveWindow: null,
 
 // The window where test results should be sent.
 _masterWindow: null,
@@ -157,37 +162,57 @@ is: function(a, b, name)
 
 isnot: function(a, b, name)
 {
   return this._masterWindow.SimpleTest.isnot(a, b, name);
 },
 
 clear: function()
 {
-  // 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();
-  }
+  // 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();
 },
 
 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 cacheSession = OfflineTest.getActiveSession();
+    var cacheService = Cc["@mozilla.org/network/cache-service;1"]
+    .getService(Ci.nsICacheService);
+    var cacheSession = cacheService.createSession("HTTP-offline",
+                                                  Ci.nsICache.STORE_OFFLINE,
+                                                  true);
     var entry;
     try {
       var entry = cacheSession.openCacheEntry(url, Ci.nsICache.ACCESS_READ, true);
     } catch (e) {
     }
 
     if (entry) {
       entry.close();
@@ -206,74 +231,48 @@ 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 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;
-  }
-
+  var cacheService = Cc["@mozilla.org/network/cache-service;1"]
+  .getService(Ci.nsICacheService);
+  var cacheSession = cacheService.createSession("HTTP-offline",
+                                                Ci.nsICache.STORE_OFFLINE,
+                                                true);
   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_KEY_WAIT_FOR_VALIDATION) {
+    } else if (e.result == NS_ERROR_CACHE_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,19 +46,18 @@ 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.onupdateready = OfflineTest.priv(manifestUpdatedAgain);
+    applicationCache.oncached = 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,16 +31,36 @@ 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);
 
@@ -51,28 +71,36 @@ 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);
 
-  applicationCache.swapCache();
+  // Remove items from the cache.
+  OfflineTest.clear();
 
-  // XXX: make sure that the previous version went away after the swapCache().
+  // Make sure OfflineTest.clear() properly removed the items
 
-  // Now add a file using the applicationCache API
-  applicationCache.add("http://localhost:8888/tests/SimpleTest/EventUtils.js");
+  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);
 
-  // Wait for the add() to be downloaded
-  OfflineTest.waitForAdd("http://localhost:8888/tests/SimpleTest/EventUtils.js",
-                         OfflineTest.priv(addFinished));
+  // Now make sure applicationCache.update() does what we expect.
+  applicationCache.oncached = OfflineTest.priv(secondUpdate);
+
+  gGotChecking = false;
+  gGotDownloading = false;
+  applicationCache.update();
 }
 
+
 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,19 +56,16 @@ 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 \
deleted file mode 100644
--- a/netwerk/base/public/nsIApplicationCache.idl
+++ /dev/null
@@ -1,143 +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 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);
-};
deleted file mode 100644
--- a/netwerk/base/public/nsIApplicationCacheContainer.idl
+++ /dev/null
@@ -1,52 +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 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;
-};
deleted file mode 100644
--- a/netwerk/base/public/nsIApplicationCacheService.idl
+++ /dev/null
@@ -1,71 +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 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,17 +36,16 @@
  * 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
 {
   /**
@@ -216,30 +215,8 @@ 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,33 +1436,9 @@ 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,17 +65,16 @@
 #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"
@@ -274,23 +273,22 @@ nsIOService::GetInstance() {
             return nsnull;
         }
         return gIOService;
     }
     NS_ADDREF(gIOService);
     return gIOService;
 }
 
-NS_IMPL_THREADSAFE_ISUPPORTS6(nsIOService,
+NS_IMPL_THREADSAFE_ISUPPORTS5(nsIOService,
                               nsIIOService,
                               nsIIOService2,
                               nsINetUtil,
                               nsIObserver,
-                              nsISupportsWeakReference,
-                              nsINetUtil_MOZILLA_1_9_1)
+                              nsISupportsWeakReference)
 
 ////////////////////////////////////////////////////////////////////////////////
 
 nsresult
 nsIOService::OnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
                                PRUint32 flags)
 {
     nsCOMPtr<nsIChannelEventSink> sink =
@@ -980,63 +978,8 @@ 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,26 +72,24 @@ 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,21 +108,16 @@ 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,28 +460,16 @@
 #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,17 +51,16 @@
 #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
@@ -183,21 +182,17 @@ 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
@@ -1045,24 +1040,16 @@ 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,13 +48,14 @@ 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,17 +81,21 @@ interface nsICacheService : nsISupports
     void visitEntries(in nsICacheVisitor visitor);
 
     /**
      * Evicts all entries in all devices implied by the storage policy.
      */
     void evictEntries(in nsCacheStoragePolicy  storagePolicy);
 
     /**
-     * This method is deprecated and will throw NS_ERROR_NOT_IMPLEMENTED.
+     * 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().
      */
     ACString createTemporaryClientID(in nsCacheStoragePolicy storagePolicy);
 };
 
 %{C++
 /**
  * Observer service notification that is sent when
  * nsICacheService::evictEntries() or nsICacheSession::evictEntries()
new file mode 100644
--- /dev/null
+++ b/netwerk/cache/public/nsIOfflineCacheSession.idl
@@ -0,0 +1,233 @@
+/* -*- 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,17 +658,18 @@ nsCacheService::Shutdown()
         mMemoryDevice = nsnull;
 
 #ifdef NECKO_DISK_CACHE
         delete mDiskDevice;
         mDiskDevice = nsnull;
 #endif // !NECKO_DISK_CACHE
 
 #ifdef NECKO_OFFLINE_CACHE
-        NS_IF_RELEASE(mOfflineDevice);
+        delete mOfflineDevice;
+        mOfflineDevice = nsnull;
 #endif // !NECKO_OFFLINE_CACHE
 
 #if defined(NECKO_DISK_CACHE) && defined(PR_LOGGING)
         LogCacheStatistics();
 #endif
     }
 }
 
@@ -823,16 +824,255 @@ 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;
@@ -879,17 +1119,30 @@ 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()
 {
@@ -930,30 +1183,29 @@ 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;
-        NS_RELEASE(mOfflineDevice);
+        delete mOfflineDevice;
+        mOfflineDevice = nsnull;
     }
     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,16 +92,64 @@ 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);
@@ -155,17 +203,16 @@ 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,17 +39,25 @@
  * 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_ISUPPORTS1(nsCacheSession, nsICacheSession)
+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
 
 nsCacheSession::nsCacheSession(const char *         clientID,
                                nsCacheStoragePolicy storagePolicy,
                                PRBool               streamBased)
     : mClientID(clientID),
       mInfo(0)
 {
   SetStoragePolicy(storagePolicy);
@@ -122,8 +130,80 @@ 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,23 +41,26 @@
  * ***** 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,32 +38,30 @@
 
 #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
  */
@@ -538,153 +536,19 @@ 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()
@@ -828,33 +692,16 @@ 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);
 
@@ -883,187 +730,113 @@ 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.
   //
-  rv = mDB->ExecuteSimpleSQL(
-      NS_LITERAL_CSTRING("CREATE TABLE IF NOT EXISTS moz_cache (\n"
+  mDB->ExecuteSimpleSQL(
+      NS_LITERAL_CSTRING("CREATE TABLE 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"
-                         "  ItemType        INTEGER DEFAULT 0\n"
+                         "  ExpirationTime  INTEGER\n"
                          ");\n"));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // 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("ALTER TABLE moz_cache ADD ItemType INTEGER DEFAULT 0"));
+  // maybe the table already exists, so don't bother checking for errors.
 
-  // 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"
+  // build the ownership table
+  mDB->ExecuteSimpleSQL(
+      NS_LITERAL_CSTRING("CREATE TABLE moz_cache_owners (\n"
+                         " ClientID TEXT,\n"
+                         " Domain TEXT,\n"
+                         " URI TEXT,\n"
+                         " Key TEXT\n"
                          ");\n"));
-  NS_ENSURE_SUCCESS(rv, rv);
+  // maybe the table already exists, so don't bother checking for errors.
 
-  // 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);
-
-  // 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);
+  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.
 
   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;" ),
-    // XXX bug 442810: Restore the ability to monitor individual cache usage
-    StatementSql ( mStatement_DomainSize,        "SELECT 0;"),
+    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=?;" ),
     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_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;")
+    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 = ?;")
   };
-  for (PRUint32 i = 0; NS_SUCCEEDED(rv) && i < NS_ARRAY_LENGTH(prepared); ++i)
+  for (PRUint32 i=0; i<NS_ARRAY_LENGTH(prepared); ++i)
   {
-    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);
+    rv |= mDB->CreateStatement(nsDependentCString(prepared[i].sql),
+                               getter_AddRefs(prepared[i].statement));
   }
+  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);
 
-  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);
+  // Clear up dangling temporary sessions
+  EvictionObserver evictionObserver(mDB, mEvictionFunction);
 
-  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);
+  rv = mDB->ExecuteSimpleSQL(
+    NS_LITERAL_CSTRING("DELETE FROM moz_cache"
+                       " WHERE (ClientID GLOB \"TempClient*\")"));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  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);
-  }
+  evictionObserver.Apply();
 
   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()
@@ -1248,16 +1021,17 @@ 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)
@@ -1471,147 +1245,41 @@ 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);
 
-  nsCOMPtr<mozIStorageStatement> statement;
-  nsresult rv;
+  const char *deleteCmd;
   if (clientID)
   {
-    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);
+    deleteCmd =
+      PR_smprintf("DELETE FROM moz_cache WHERE ClientID=%q AND Flags=0;",
+                  clientID);
+    if (!deleteCmd)
+      return NS_ERROR_OUT_OF_MEMORY;
   }
   else
   {
-    rv = mDB->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_cache WHERE Flags = 0;"),
-                              getter_AddRefs(statement));
-    NS_ENSURE_SUCCESS(rv, rv);
+    deleteCmd = "DELETE FROM moz_cache WHERE Flags = 0;";
   }
 
-  rv = statement->Execute();
+  nsresult rv = mDB->ExecuteSimpleSQL(nsDependentCString(deleteCmd));
+  if (clientID)
+    PR_smprintf_free((char *) deleteCmd);
   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);
@@ -1639,200 +1307,322 @@ nsOfflineCacheDevice::RunSimpleQuery(moz
     }
   }
 
   *values = ret;
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsOfflineCacheDevice::CreateApplicationCache(const nsACString &group,
-                                             nsIApplicationCache **out)
+nsresult
+nsOfflineCacheDevice::GetOwnerDomains(const char * clientID,
+                                      PRUint32 * count,
+                                      char *** domains)
 {
-  *out = nsnull;
+  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);
+}
 
-  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;
+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);
   }
 
-  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++));
+  return transaction.Commit();
+}
 
-  nsCOMPtr<nsIApplicationCache> cache = new nsApplicationCache(this,
-                                                               group,
-                                                               clientID);
-  if (!cache)
-    return NS_ERROR_OUT_OF_MEMORY;
+nsresult
+nsOfflineCacheDevice::GetOwnedKeys(const char * clientID,
+                                   const nsACString & ownerDomain,
+                                   const nsACString & ownerURI,
+                                   PRUint32 * count,
+                                   char *** keys)
+{
+  LOG(("nsOfflineCacheDevice::GetOwnedKeys [cid=%s]\n", clientID));
 
-  nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(cache);
-  if (!weak)
-    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);
 
-  mCaches.Put(clientID, weak);
-
-  cache.swap(*out);
-
-  return NS_OK;
+  return RunSimpleQuery(mStatement_ListOwned, 0, count, keys);
 }
 
-NS_IMETHODIMP
-nsOfflineCacheDevice::GetApplicationCache(const nsACString &clientID,
-                                          nsIApplicationCache **out)
+nsresult
+nsOfflineCacheDevice::AddOwnedKey(const char * clientID,
+                                  const nsACString & ownerDomain,
+                                  const nsACString & ownerURI,
+                                  const nsACString & key)
 {
-  *out = nsnull;
+  LOG(("nsOfflineCacheDevice::AddOwnedKey [cid=%s]\n", clientID));
 
-  nsCOMPtr<nsIApplicationCache> cache;
+  PRBool isOwned;
+  nsresult rv = KeyIsOwned(clientID, ownerDomain, ownerURI, key, &isOwned);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (isOwned) return NS_OK;
 
-  nsWeakPtr weak;
-  if (mCaches.Get(clientID, getter_AddRefs(weak)))
-    cache = do_QueryReferent(weak);
+  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);
 
-  if (!cache)
-  {
-    nsCString group;
-    nsresult rv = GetGroupForCache(clientID, group);
-    NS_ENSURE_SUCCESS(rv, rv);
+  return statement->Execute();
+}
 
-    if (group.IsEmpty()) {
-      return NS_OK;
-    }
+nsresult
+nsOfflineCacheDevice::RemoveOwnedKey(const char * clientID,
+                                     const nsACString & ownerDomain,
+                                     const nsACString & ownerURI,
+                                     const nsACString & key)
+{
+  LOG(("nsOfflineCacheDevice::RemoveOwnedKey [cid=%s]\n", clientID));
 
-    cache = new nsApplicationCache(this, group, clientID);
-    weak = do_GetWeakReference(cache);
-    if (!weak)
-      return NS_ERROR_OUT_OF_MEMORY;
+  PRBool isOwned;
+  nsresult rv = KeyIsOwned(clientID, ownerDomain, ownerURI, key, &isOwned);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!isOwned) return NS_ERROR_NOT_AVAILABLE;
 
-    mCaches.Put(clientID, weak);
-  }
+  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);
 
-  cache.swap(*out);
-
-  return NS_OK;
+  return statement->Execute();
 }
 
-NS_IMETHODIMP
-nsOfflineCacheDevice::GetActiveCache(const nsACString &group,
-                                     nsIApplicationCache **out)
+nsresult
+nsOfflineCacheDevice::KeyIsOwned(const char * clientID,
+                                 const nsACString & ownerDomain,
+                                 const nsACString & ownerURI,
+                                 const nsACString & key,
+                                 PRBool * isOwned)
 {
-  *out = nsnull;
+  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);
 
-  nsCString *clientID;
-  if (mActiveCachesByGroup.Get(group, &clientID))
-    return GetApplicationCache(*clientID, out);
-
-  return NS_OK;
+  return statement->ExecuteStep(isOwned);
 }
 
-NS_IMETHODIMP
-nsOfflineCacheDevice::ChooseApplicationCache(const nsACString &key,
-                                             nsIApplicationCache **out)
+nsresult
+nsOfflineCacheDevice::ClearKeysOwnedByDomain(const char *clientID,
+                                             const nsACString &domain)
 {
-  *out = nsnull;
+  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();
+}
 
-  AutoResetStatement statement(mStatement_FindClient);
-  nsresult rv = statement->BindUTF8StringParameter(
-                                           0, key);
+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);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool hasRows;
   rv = statement->ExecuteStep(&hasRows);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  while (hasRows) {
-    nsCString clientID;
-    rv = statement->GetUTF8String(0, clientID);
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (!hasRows)
+      return NS_OK;
 
-    if (mActiveCaches.Contains(clientID))
-      return GetApplicationCache(clientID, out);
-
-    rv = statement->ExecuteStep(&hasRows);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
+  *usage = statement->AsInt32(0);
 
   return NS_OK;
 }
 
 nsresult
-nsOfflineCacheDevice::ActivateCache(const nsCSubstring &group,
-                                    const nsCSubstring &clientID)
+nsOfflineCacheDevice::EvictUnownedEntries(const char *clientID)
 {
-  AutoResetStatement statement(mStatement_ActivateClient);
-  nsresult rv = statement->BindUTF8StringParameter(0, group);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = statement->BindUTF8StringParameter(1, clientID);
+  LOG(("nsOfflineCacheDevice::EvictUnownedEntries [cid=%s]\n", clientID));
+  EvictionObserver evictionObserver(mDB, mEvictionFunction);
+
+  AutoResetStatement statement(mStatement_DeleteUnowned);
+  nsresult rv = statement->BindUTF8StringParameter(
+                                              0, nsDependentCString(clientID));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = statement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCString *active;
-  if (mActiveCachesByGroup.Get(group, &active))
-  {
-    mActiveCaches.Remove(*active);
-    mActiveCachesByGroup.Remove(group);
-    active = nsnull;
-  }
-
-  if (!clientID.IsEmpty())
-  {
-    mActiveCaches.Put(clientID);
-    mActiveCachesByGroup.Put(group, new nsCString(clientID));
-  }
-
+  evictionObserver.Apply();
   return NS_OK;
 }
 
-PRBool
-nsOfflineCacheDevice::IsActiveCache(const nsCSubstring &group,
-                                    const nsCSubstring &clientID)
+nsresult
+nsOfflineCacheDevice::CreateTemporaryClientID(nsACString &clientID)
 {
-  nsCString *active = nsnull;
-  return mActiveCachesByGroup.Get(group, &active) && *active == clientID;
-}
-
-nsresult
-nsOfflineCacheDevice::DeactivateGroup(const nsCSubstring &group)
-{
-  nsCString *active = nsnull;
+  nsCAutoString str;
+  str.AssignLiteral("TempClient");
+  str.AppendInt(gNextTemporaryClientID++);
 
-  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;
-  }
+  clientID.Assign(str);
 
   return NS_OK;
 }
 
 nsresult
-nsOfflineCacheDevice::GetGroupForCache(const nsACString &clientID,
-                                       nsCString &out)
+nsOfflineCacheDevice::MergeTemporaryClientID(const char *clientID,
+                                             const char *fromClientID)
 {
-  out.Assign(clientID);
-  out.Truncate(out.FindChar('|'));
-  NS_UnescapeURL(out);
+  LOG(("nsOfflineCacheDevice::MergeTemporaryClientID [cid=%s, from=%s]\n",
+       clientID, fromClientID));
+  mozStorageTransaction transaction(mDB, PR_FALSE);
+
+  // Move over ownerships
+  AutoResetStatement listOwnersStatement(mStatement_ListOwners);
+  nsresult rv = listOwnersStatement->BindUTF8StringParameter(
+                                          0, nsDependentCString(fromClientID));
+  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)
+  {
+    PRUint32 length;
+    domainArray.AppendElement(
+      nsDependentCString(listOwnersStatement->AsSharedUTF8String(0, &length)));
+    uriArray.AppendElement(
+      nsDependentCString(listOwnersStatement->AsSharedUTF8String(1, &length)));
+
+    rv = listOwnersStatement->ExecuteStep(&hasRows);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // 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);
+
+    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);
+
+    // Now clear out the temporary session's copy
+    rv = SetOwnedKeys(fromClientID, domainArray[i], uriArray[i], 0, 0);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  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);
+
+  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();
 
   return NS_OK;
 }
 
 /**
  * Preference accessors
  */
 
--- a/netwerk/cache/src/nsDiskCacheDeviceSQL.h
+++ b/netwerk/cache/src/nsDiskCacheDeviceSQL.h
@@ -34,31 +34,25 @@
  * 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
 
@@ -71,32 +65,26 @@ 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 );
@@ -150,69 +138,46 @@ 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                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);
+  nsresult                CreateTemporaryClientID(nsACString &clientID);
+  nsresult                MergeTemporaryClientID(const char *clientID,
+                                                 const char *fromClientID);
+
 
   /**
    * 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;
 
@@ -220,28 +185,27 @@ 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_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<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<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,17 +42,16 @@
 #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"
@@ -1367,71 +1366,36 @@ 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 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.
+    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.
         //
-        // 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,
+        // 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,
                                      getter_AddRefs(mCacheEntry));
     }
 
-    if (!mApplicationCache ||
+    if (!(mLoadFlags & LOAD_CHECK_OFFLINE_CACHE) ||
         (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));
@@ -1488,28 +1452,30 @@ 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;
-    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 (!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));
+    }
     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
@@ -3416,17 +3382,16 @@ 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)
@@ -4907,34 +4872,16 @@ 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,21 +61,18 @@
 #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"
@@ -101,17 +98,16 @@ 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
@@ -120,17 +116,16 @@ 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);
 
@@ -263,18 +258,16 @@ 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,37 +110,31 @@ 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(4b206247-82ee-46cf-a8b7-f7284e753bc2)]
+[scriptable, uuid(7dc06ede-1098-4384-b95e-65525ab254c9)]
 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,26 +35,24 @@
  * 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 "nsIURL.h"
+#include "nsIOfflineCacheSession.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"
@@ -101,65 +99,40 @@ NS_IMPL_ISUPPORTS6(nsOfflineCacheUpdateI
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdateItem <public>
 //-----------------------------------------------------------------------------
 
 nsOfflineCacheUpdateItem::nsOfflineCacheUpdateItem(nsOfflineCacheUpdate *aUpdate,
                                                    nsIURI *aURI,
                                                    nsIURI *aReferrerURI,
-                                                   nsIApplicationCache *aPreviousApplicationCache,
-                                                   const nsACString &aClientID,
-                                                   PRUint32 type)
+                                                   const nsACString &aClientID)
     : mURI(aURI)
     , mReferrerURI(aReferrerURI)
-    , mPreviousApplicationCache(aPreviousApplicationCache)
     , mClientID(aClientID)
-    , mItemType(type)
     , mUpdate(aUpdate)
     , mChannel(nsnull)
     , mState(nsIDOMLoadStatus::UNINITIALIZED)
     , mBytesRead(0)
 {
 }
 
 nsOfflineCacheUpdateItem::~nsOfflineCacheUpdateItem()
 {
 }
 
 nsresult
 nsOfflineCacheUpdateItem::OpenChannel()
 {
-#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);
+    nsresult 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);
 
     // configure HTTP specific stuff
     nsCOMPtr<nsIHttpChannel> httpChannel =
         do_QueryInterface(mChannel);
     if (httpChannel) {
         httpChannel->SetReferrer(mReferrerURI);
         httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
@@ -414,21 +387,18 @@ nsOfflineCacheUpdateItem::GetStatus(PRUi
 
 //-----------------------------------------------------------------------------
 // nsOfflineManifestItem <public>
 //-----------------------------------------------------------------------------
 
 nsOfflineManifestItem::nsOfflineManifestItem(nsOfflineCacheUpdate *aUpdate,
                                              nsIURI *aURI,
                                              nsIURI *aReferrerURI,
-                                             nsIApplicationCache *aPreviousApplicationCache,
                                              const nsACString &aClientID)
-    : nsOfflineCacheUpdateItem(aUpdate, aURI, aReferrerURI,
-                               aPreviousApplicationCache, aClientID,
-                               nsIApplicationCache::ITEM_MANIFEST)
+    : nsOfflineCacheUpdateItem(aUpdate, aURI, aReferrerURI, aClientID)
     , mParserState(PARSE_INIT)
     , mNeedsUpdate(PR_TRUE)
     , mManifestHashInitialized(PR_FALSE)
 {
 }
 
 nsOfflineManifestItem::~nsOfflineManifestItem()
 {
@@ -782,52 +752,30 @@ 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, %d]", this, aPartialUpdate));
+    LOG(("nsOfflineCacheUpdate::Init [%p]", this));
 
     mPartialUpdate = aPartialUpdate;
 
     // Only http and https applications are supported.
     PRBool match;
     rv = aManifestURI->SchemeIs("http", &match);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -840,41 +788,68 @@ nsOfflineCacheUpdate::Init(PRBool aParti
 
     mManifestURI = aManifestURI;
 
     rv = mManifestURI->GetAsciiHost(mUpdateDomain);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCAutoString manifestSpec;
 
-    rv = GetCacheKey(mManifestURI, manifestSpec);
+    rv = mManifestURI->GetAsciiSpec(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<nsIApplicationCacheService> cacheService =
-        do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
+    nsCOMPtr<nsICacheService> cacheService =
+        do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = cacheService->GetActiveCache(manifestSpec,
-                                      getter_AddRefs(mPreviousApplicationCache));
+    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);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // Partial updates to existing application caches don't need a new cache.
-    if (aPartialUpdate && mPreviousApplicationCache) {
-        mApplicationCache = mPreviousApplicationCache;
+    // Partial updates don't use temporary cache sessions
+    if (aPartialUpdate) {
+        mCacheSession = mMainCacheSession;
     } else {
-        rv = cacheService->CreateApplicationCache(manifestSpec,
-                                                  getter_AddRefs(mApplicationCache));
+        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);
         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)
 {
@@ -891,31 +866,27 @@ 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], nsIApplicationCache::ITEM_EXPLICIT);
+        rv = AddURI(manifestURIs[i], mManifestOwnerSpec);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // The document that requested the manifest is implicitly included
     // as part of that manifest update.
-    rv = AddURI(mDocumentURI, nsIApplicationCache::ITEM_IMPLICIT);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Add items previously cached implicitly
-    rv = AddExistingItems(nsIApplicationCache::ITEM_IMPLICIT);
+    rv = AddURI(mDocumentURI, mManifestOwnerSpec);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Add items requested by the script API
-    rv = AddExistingItems(nsIApplicationCache::ITEM_DYNAMIC);
+    rv = AddOwnedItems(mDynamicOwnerSpec);
     NS_ENSURE_SUCCESS(rv, rv);
 
     *aDoUpdate = PR_TRUE;
 
     return NS_OK;
 }
 
 void
@@ -946,25 +917,16 @@ 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;
     }
@@ -980,24 +942,16 @@ 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()
@@ -1012,19 +966,17 @@ nsOfflineCacheUpdate::Begin()
         ProcessNextURI();
         return NS_OK;
     }
 
     // Start checking the manifest.
     nsCOMPtr<nsIURI> uri;
 
     mManifestItem = new nsOfflineManifestItem(this, mManifestURI,
-                                              mDocumentURI,
-                                              mPreviousApplicationCache,
-                                              mClientID);
+                                              mDocumentURI, mClientID);
     if (!mManifestItem) {
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     mState = STATE_CHECKING;
     NotifyChecking();
 
     nsresult rv = mManifestItem->OpenChannel();
@@ -1052,35 +1004,35 @@ nsOfflineCacheUpdate::Cancel()
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdate <private>
 //-----------------------------------------------------------------------------
 
 nsresult
-nsOfflineCacheUpdate::AddExistingItems(PRUint32 aType)
+nsOfflineCacheUpdate::AddOwnedItems(const nsACString &aOwnerURI)
 {
-    if (!mPreviousApplicationCache) {
-        return NS_OK;
-    }
-
-    PRUint32 count = 0;
-    char **keys = nsnull;
-    nsresult rv = mPreviousApplicationCache->GatherEntries(aType,
-                                                           &count, &keys);
+    PRUint32 count;
+    char **keys;
+    nsresult rv = mMainCacheSession->GetOwnedKeys(mUpdateDomain, aOwnerURI,
+                                                  &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]))) {
-            rv = AddURI(uri, aType);
-            NS_ENSURE_SUCCESS(rv, rv);
+            nsRefPtr<nsOfflineCacheUpdateItem> item =
+                new nsOfflineCacheUpdateItem(this, uri, mDocumentURI,
+                                             mClientID);
+            if (!item) return NS_ERROR_OUT_OF_MEMORY;
+
+            mItems.AppendElement(item);
         }
     }
 
     return NS_OK;
 }
 
 nsresult
 nsOfflineCacheUpdate::ProcessNextURI()
@@ -1133,18 +1085,16 @@ 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);
     }
 
@@ -1167,18 +1117,16 @@ 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);
     }
 
@@ -1243,30 +1191,28 @@ nsOfflineCacheUpdate::Finish()
     nsOfflineCacheUpdateService* service =
         nsOfflineCacheUpdateService::EnsureService();
 
     if (!service)
         return NS_ERROR_FAILURE;
 
     if (!mPartialUpdate) {
         if (mSucceeded) {
-            nsresult rv = mApplicationCache->Activate();
+            nsresult rv = mMainCacheSession->MergeTemporaryClientID(mClientID);
             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
@@ -1320,85 +1266,73 @@ 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, PRUint32 aType)
+nsOfflineCacheUpdate::AddURI(nsIURI *aURI, const nsACString &aOwnerSpec)
 {
     NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
 
     if (mState >= STATE_DOWNLOADING)
         return NS_ERROR_NOT_AVAILABLE;
 
-    // Resource URIs must have the same scheme as the manifest.
+    // Manifest 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,
-                                     mPreviousApplicationCache, mClientID,
-                                     aType);
+        new nsOfflineCacheUpdateItem(this, aURI, mDocumentURI, mClientID);
     if (!item) return NS_ERROR_OUT_OF_MEMORY;
 
     mItems.AppendElement(item);
     mAddedItems = PR_TRUE;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsOfflineCacheUpdate::AddDynamicURI(nsIURI *aURI)
 {
-    // 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);
+    return AddURI(aURI, mDynamicOwnerSpec);
 }
 
 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,17 +47,18 @@
 #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 "nsIApplicationCache.h"
+#include "nsIOfflineCacheSession.h"
+#include "nsIPrefetchService.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"
@@ -81,27 +82,22 @@ public:
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSIRUNNABLE
     NS_DECL_NSIINTERFACEREQUESTOR
     NS_DECL_NSICHANNELEVENTSINK
 
     nsOfflineCacheUpdateItem(nsOfflineCacheUpdate *aUpdate,
                              nsIURI *aURI,
                              nsIURI *aReferrerURI,
-                             nsIApplicationCache *aPreviousApplicationCache,
-                             const nsACString &aClientID,
-                             PRUint32 aType);
+                             const nsACString &aClientID);
     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;
@@ -115,17 +111,16 @@ 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; }
@@ -177,32 +172,29 @@ 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, PRUint32 aItemType);
+    nsresult AddURI(nsIURI *aURI, const nsACString &aOwnerSpec);
 
     nsresult ProcessNextURI();
 
-    nsresult AddExistingItems(PRUint32 aType);
+    nsresult AddOwnedItems(const nsACString &aOwnerURI);
 
     nsresult GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers);
     nsresult NotifyError();
     nsresult NotifyChecking();
     nsresult NotifyNoUpdate();
     nsresult NotifyDownloading();
     nsresult NotifyStarted(nsOfflineCacheUpdateItem *aItem);
     nsresult NotifyCompleted(nsOfflineCacheUpdateItem *aItem);
@@ -217,22 +209,24 @@ 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<nsIApplicationCache> mApplicationCache;
-    nsCOMPtr<nsIApplicationCache> mPreviousApplicationCache;
+    nsCOMPtr<nsIOfflineCacheSession> mCacheSession;
+    nsCOMPtr<nsIOfflineCacheSession> mMainCacheSession;
 
     nsCOMPtr<nsIObserverService> mObserverService;
 
     nsRefPtr<nsOfflineManifestItem> mManifestItem;
 
     /* Items being updated */
     PRInt32 mCurrentItem;
     nsTArray<nsRefPtr<nsOfflineCacheUpdateItem> > mItems;