Bug 786299 - Delete app-cache related to an app when uninstalled, part 1 r=jduell
authorJason Duell <jduell.mcbugs@gmail.com>
Fri, 28 Sep 2012 16:13:15 -0700
changeset 108686 a6228bc289587667d4dc19792731c4fd311fa4a5
parent 108685 93e76aaf861579f4dea5615605d17b33166576c5
child 108687 bec7e68cad9af2ccf552f024d61c37352097890c
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersjduell
bugs786299
milestone18.0a1
Bug 786299 - Delete app-cache related to an app when uninstalled, part 1 r=jduell
netwerk/base/public/nsIApplicationCacheService.idl
netwerk/cache/nsApplicationCacheService.cpp
netwerk/cache/nsDiskCacheDeviceSQL.cpp
netwerk/cache/nsDiskCacheDeviceSQL.h
--- a/netwerk/base/public/nsIApplicationCacheService.idl
+++ b/netwerk/base/public/nsIApplicationCacheService.idl
@@ -10,17 +10,17 @@ interface nsIApplicationCache;
 interface nsIFile;
 interface nsIURI;
 interface nsILoadContext;
 
 /**
  * The application cache service manages the set of application cache
  * groups.
  */
-[scriptable, uuid(F94DB1CC-AB56-480b-8F86-40748878557E)]
+[scriptable, uuid(1750F671-0170-4d3f-A836-455501141E32)]
 interface nsIApplicationCacheService : nsISupports
 {
     /**
      * Create group string identifying cache group according the manifest
      * URL and the given load context.
      */
     ACString buildGroupID(in nsIURI aManifestURL,
                           in nsILoadContext aLoadContext);
@@ -58,16 +58,30 @@ interface nsIApplicationCacheService : n
     nsIApplicationCache getActiveCache(in ACString group);
 
     /**
      * Deactivate the currently-active cache object for a cache group.
      */
     void deactivateGroup(in ACString group);
 
     /**
+     * Deletes some or all of an application's cache entries.  
+     *
+     * @param appId
+     *    The mozIApplication.localId of the application.
+     * 
+     * @param discardOnlyBrowserEntries 
+     *    If true, only entries marked as 'inBrowserElement' are deleted 
+     *    (this is used by browser applications to delete user browsing 
+     *    data/history.).  If false, *all* entries for the given appId are
+     *    deleted (this is used for application uninstallation).
+     */
+    void discardByAppId(in int32_t appID, in boolean discardOnlyBrowserEntries);
+
+    /**
      * Try to find the best application cache to serve a resource.
      */
     nsIApplicationCache chooseApplicationCache(in ACString key,
                                                [optional] in nsILoadContext loadContext);
 
     /**
      * Flags the key as being opportunistically cached.
      *
--- a/netwerk/cache/nsApplicationCacheService.cpp
+++ b/netwerk/cache/nsApplicationCacheService.cpp
@@ -125,16 +125,28 @@ nsApplicationCacheService::CacheOpportun
 
     nsRefPtr<nsOfflineCacheDevice> device;
     nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device));
     NS_ENSURE_SUCCESS(rv, rv);
     return device->CacheOpportunistically(cache, key);
 }
 
 NS_IMETHODIMP
+nsApplicationCacheService::DiscardByAppId(int32_t appID, bool isInBrowser)
+{
+    if (!mCacheService)
+        return NS_ERROR_UNEXPECTED;
+
+    nsRefPtr<nsOfflineCacheDevice> device;
+    nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device));
+    NS_ENSURE_SUCCESS(rv, rv);
+    return device->DiscardByAppId(appID, isInBrowser);
+}
+
+NS_IMETHODIMP
 nsApplicationCacheService::GetGroups(uint32_t *count,
                                      char ***keys)
 {
     if (!mCacheService)
         return NS_ERROR_UNEXPECTED;
 
     nsRefPtr<nsOfflineCacheDevice> device;
     nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device));
--- a/netwerk/cache/nsDiskCacheDeviceSQL.cpp
+++ b/netwerk/cache/nsDiskCacheDeviceSQL.cpp
@@ -1210,16 +1210,17 @@ nsOfflineCacheDevice::Init()
                                                      "  ON ns.ClientID = groups.ActiveClientID"
                                                      " WHERE ns.NameSpace <= ?1 AND ?1 GLOB ns.NameSpace || '*'"
                                                      " ORDER BY ns.NameSpace DESC, groups.ActivateTimeStamp DESC;"),
     StatementSql ( mStatement_FindNamespaceEntry,    "SELECT NameSpace, Data, ItemType FROM moz_cache_namespaces"
                                                      " WHERE ClientID = ?1"
                                                      " AND NameSpace <= ?2 AND ?2 GLOB NameSpace || '*'"
                                                      " ORDER BY NameSpace DESC;"),
     StatementSql ( mStatement_InsertNamespaceEntry,  "INSERT INTO moz_cache_namespaces (ClientID, NameSpace, Data, ItemType) VALUES(?, ?, ?, ?);"),
+    StatementSql ( mStatement_EnumerateApps,         "SELECT GroupID, ActiveClientID FROM moz_cache_groups WHERE GroupID LIKE ?1;"),
     StatementSql ( mStatement_EnumerateGroups,       "SELECT GroupID, ActiveClientID FROM moz_cache_groups;"),
     StatementSql ( mStatement_EnumerateGroupsTimeOrder, "SELECT GroupID, ActiveClientID FROM moz_cache_groups ORDER BY ActivateTimeStamp;")
   };
   for (uint32_t i = 0; NS_SUCCEEDED(rv) && i < ArrayLength(prepared); ++i)
   {
     LOG(("Creating statement: %s\n", prepared[i].sql));
 
     rv = mDB->CreateStatement(nsDependentCString(prepared[i].sql),
@@ -1241,16 +1242,27 @@ GetGroupForCache(const nsCSubstring &cli
   group.Assign(clientID);
   group.Truncate(group.FindChar('|'));
   NS_UnescapeURL(group);
 
   return NS_OK;
 }
 
 nsresult
+AppendJARIdentifier(nsACString &_result, int32_t appId, bool isInBrowserElement)
+{
+    _result.Append('#');
+    _result.AppendInt(appId);
+    _result.Append('+');
+    _result.Append(isInBrowserElement ? 't' : 'f');
+
+    return NS_OK;
+}
+
+nsresult
 GetJARIdentifier(nsIURI *aURI,
                  nsILoadContext *aLoadContext,
                  nsACString &_result)
 {
     _result.Truncate();
 
     if (!aLoadContext)
         return NS_OK;
@@ -1266,21 +1278,17 @@ GetJARIdentifier(nsIURI *aURI,
     uint32_t appId;
     rv = aLoadContext->GetAppId(&appId);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!isInBrowserElement && appId == NECKO_NO_APP_ID)
         return NS_OK;
 
     // This load context has some special attributes, create a jar identifier
-    _result.AppendInt(appId);
-    _result.Append('+');
-    _result.Append(isInBrowserElement ? 't' : 'f');
-
-    return NS_OK;
+    return AppendJARIdentifier(_result, appId, isInBrowserElement);
 }
 
 } // anon namespace
 
 // static
 nsresult
 nsOfflineCacheDevice::BuildApplicationCacheGroupID(nsIURI *aManifestURL,
                                                    nsILoadContext *aLoadContext,
@@ -1296,20 +1304,18 @@ nsOfflineCacheDevice::BuildApplicationCa
 
   _result.Assign(manifestSpec);
 
   nsAutoCString jarid;
   rv = GetJARIdentifier(aManifestURL, aLoadContext, jarid);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Include JAR ID, i.e. the extended origin if present.
-  if (!jarid.IsEmpty()) {
-    _result.Append('#');
+  if (!jarid.IsEmpty())
     _result.Append(jarid);
-  }
 
   return NS_OK;
 }
 
 nsresult
 nsOfflineCacheDevice::InitActiveCaches()
 {
   mCaches.Init();
@@ -2357,16 +2363,62 @@ nsOfflineCacheDevice::DeactivateGroup(co
     mActiveCaches.RemoveEntry(*active);
     mActiveCachesByGroup.Remove(group);
     active = nullptr;
   }
 
   return NS_OK;
 }
 
+nsresult
+nsOfflineCacheDevice::DiscardByAppId(int32_t appID, bool browserEntriesOnly)
+{
+  nsresult rv;
+
+  nsAutoCString jaridsuffix;
+  jaridsuffix.Append('%');
+  rv = AppendJARIdentifier(jaridsuffix, appID, browserEntriesOnly);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  AutoResetStatement statement(mStatement_EnumerateApps);
+  rv = statement->BindUTF8StringByIndex(0, jaridsuffix);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool hasRows;
+  rv = statement->ExecuteStep(&hasRows);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  while (hasRows) {
+    nsAutoCString group;
+    rv = statement->GetUTF8String(0, group);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCString clientID;
+    rv = statement->GetUTF8String(1, clientID);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIRunnable> ev =
+      new nsOfflineCacheDiscardCache(this, group, clientID);
+
+    rv = nsCacheService::DispatchToCacheIOThread(ev);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = statement->ExecuteStep(&hasRows);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  if (!browserEntriesOnly) {
+    // If deleting app, delete any 'inBrowserElement' entries too
+    rv = DiscardByAppId(appID, true);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
 bool
 nsOfflineCacheDevice::CanUseCache(nsIURI *keyURI,
                                   const nsACString &clientID,
                                   nsILoadContext *loadContext)
 {
   if (!mActiveCaches.Contains(clientID))
     return false;
 
--- a/netwerk/cache/nsDiskCacheDeviceSQL.h
+++ b/netwerk/cache/nsDiskCacheDeviceSQL.h
@@ -153,16 +153,18 @@ public:
 
   nsresult                ChooseApplicationCache(const nsACString &key,
                                                  nsILoadContext *loadContext,
                                                  nsIApplicationCache **out);
 
   nsresult                CacheOpportunistically(nsIApplicationCache* cache,
                                                  const nsACString &key);
 
+  nsresult                DiscardByAppId(int32_t appID, bool isInBrowser);
+
   nsresult                GetGroups(uint32_t *count,char ***keys);
 
   nsresult                GetGroupsTimeOrdered(uint32_t *count,
                                                char ***keys);
 
   bool                    IsLocked(const nsACString &key);
   void                    Lock(const nsACString &key);
   void                    Unlock(const nsACString &key);
@@ -252,16 +254,17 @@ private:
   nsCOMPtr<mozIStorageStatement>  mStatement_FindNamespaceEntry;
   nsCOMPtr<mozIStorageStatement>  mStatement_InsertNamespaceEntry;
   nsCOMPtr<mozIStorageStatement>  mStatement_CleanupUnmarked;
   nsCOMPtr<mozIStorageStatement>  mStatement_GatherEntries;
   nsCOMPtr<mozIStorageStatement>  mStatement_ActivateClient;
   nsCOMPtr<mozIStorageStatement>  mStatement_DeactivateGroup;
   nsCOMPtr<mozIStorageStatement>  mStatement_FindClient;
   nsCOMPtr<mozIStorageStatement>  mStatement_FindClientByNamespace;
+  nsCOMPtr<mozIStorageStatement>  mStatement_EnumerateApps;
   nsCOMPtr<mozIStorageStatement>  mStatement_EnumerateGroups;
   nsCOMPtr<mozIStorageStatement>  mStatement_EnumerateGroupsTimeOrder;
 
   nsCOMPtr<nsIFile>               mBaseDirectory;
   nsCOMPtr<nsIFile>               mCacheDirectory;
   uint32_t                        mCacheCapacity; // in bytes
   int32_t                         mDeltaCounter;
   bool                            mAutoShutdown;