diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp index a83a3e23292b..1915f23ab89c 100644 --- a/netwerk/cache/nsCacheService.cpp +++ b/netwerk/cache/nsCacheService.cpp @@ -1588,6 +1588,7 @@ nsCacheService::GetCustomOfflineDevice(nsIFile *aProfileDir, rv = CreateCustomOfflineDevice(aProfileDir, aQuota, aDevice); NS_ENSURE_SUCCESS(rv, rv); + (*aDevice)->SetAutoShutdown(); mCustomOfflineDevices.Put(profilePath, *aDevice); } @@ -1676,6 +1677,20 @@ nsCacheService::CreateMemoryDevice() return rv; } +nsresult +nsCacheService::RemoveCustomOfflineDevice(nsOfflineCacheDevice *aDevice) +{ + nsCOMPtr profileDir = aDevice->BaseDirectory(); + if (!profileDir) + return NS_ERROR_UNEXPECTED; + + nsAutoString profilePath; + nsresult rv = profileDir->GetPath(profilePath); + NS_ENSURE_SUCCESS(rv, rv); + + mCustomOfflineDevices.Remove(profilePath); + return NS_OK; +} nsresult nsCacheService::CreateRequest(nsCacheSession * session, diff --git a/netwerk/cache/nsCacheService.h b/netwerk/cache/nsCacheService.h index ae4dcdcf8f39..5ec8abbed27a 100644 --- a/netwerk/cache/nsCacheService.h +++ b/netwerk/cache/nsCacheService.h @@ -199,6 +199,8 @@ private: nsOfflineCacheDevice **aDevice); nsresult CreateMemoryDevice(); + nsresult RemoveCustomOfflineDevice(nsOfflineCacheDevice *aDevice); + nsresult CreateRequest(nsCacheSession * session, const nsACString & clientKey, nsCacheAccessMode accessRequested, diff --git a/netwerk/cache/nsDiskCacheDeviceSQL.cpp b/netwerk/cache/nsDiskCacheDeviceSQL.cpp index 08bd8cbb69f0..fdafabe2b932 100644 --- a/netwerk/cache/nsDiskCacheDeviceSQL.cpp +++ b/netwerk/cache/nsDiskCacheDeviceSQL.cpp @@ -685,6 +685,10 @@ nsApplicationCache::Activate() NS_ENSURE_TRUE(mDevice, NS_ERROR_NOT_AVAILABLE); mDevice->ActivateCache(mGroup, mClientID); + + if (mDevice->AutoShutdown(this)) + mDevice = nsnull; + return NS_OK; } @@ -830,6 +834,7 @@ nsOfflineCacheDevice::nsOfflineCacheDevice() : mDB(nsnull) , mCacheCapacity(0) , mDeltaCounter(0) + , mAutoShutdown(false) { } @@ -2418,3 +2423,23 @@ nsOfflineCacheDevice::SetCapacity(PRUint32 capacity) { mCacheCapacity = capacity * 1024; } + +bool +nsOfflineCacheDevice::AutoShutdown(nsIApplicationCache * aAppCache) +{ + if (!mAutoShutdown) + return false; + + mAutoShutdown = false; + + Shutdown(); + + nsRefPtr cacheService = nsCacheService::GlobalInstance(); + cacheService->RemoveCustomOfflineDevice(this); + + nsCAutoString clientID; + aAppCache->GetClientID(clientID); + mCaches.Remove(clientID); + + return true; +} diff --git a/netwerk/cache/nsDiskCacheDeviceSQL.h b/netwerk/cache/nsDiskCacheDeviceSQL.h index 25d311924d58..1c76fa42dddc 100644 --- a/netwerk/cache/nsDiskCacheDeviceSQL.h +++ b/netwerk/cache/nsDiskCacheDeviceSQL.h @@ -167,6 +167,8 @@ public: void SetCacheParentDirectory(nsIFile * parentDir); void SetCapacity(PRUint32 capacity); + void SetAutoShutdown() { mAutoShutdown = true; } + bool AutoShutdown(nsIApplicationCache * aAppCache); nsIFile * BaseDirectory() { return mBaseDirectory; } nsIFile * CacheDirectory() { return mCacheDirectory; } @@ -257,6 +259,7 @@ private: nsCOMPtr mCacheDirectory; PRUint32 mCacheCapacity; // in bytes PRInt32 mDeltaCounter; + bool mAutoShutdown; nsInterfaceHashtable mCaches; nsClassHashtable mActiveCachesByGroup; diff --git a/netwerk/test/unit/test_cacheForOfflineUse_no-store.js b/netwerk/test/unit/test_cacheForOfflineUse_no-store.js index a0dad53763bf..303c2b4d1cff 100644 --- a/netwerk/test/unit/test_cacheForOfflineUse_no-store.js +++ b/netwerk/test/unit/test_cacheForOfflineUse_no-store.js @@ -5,7 +5,7 @@ do_load_httpd_js(); var httpServer = null; const testFileName = "test_nsHttpChannel_CacheForOfflineUse-no-store"; -const cacheClientID = testFileName; +const cacheClientID = testFileName + "|fake-group-id"; const basePath = "/" + testFileName + "/"; const baseURI = "http://localhost:4444" + basePath; const normalEntry = "normal"; @@ -17,9 +17,13 @@ function make_channel_for_offline_use(url, callback, ctx) { var ios = Cc["@mozilla.org/network/io-service;1"]. getService(Ci.nsIIOService); var chan = ios.newChannel(url, "", null); - var cachingChan = chan.QueryInterface(Ci.nsICachingChannel); - cachingChan.cacheForOfflineUse = true; - cachingChan.offlineCacheClientID = cacheClientID; + + var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"]. + getService(Components.interfaces.nsIApplicationCacheService); + var appCache = cacheService.getApplicationCache(cacheClientID); + + var appCacheChan = chan.QueryInterface(Ci.nsIApplicationCacheChannel); + appCacheChan.applicationCacheForWrite = appCache; return chan; } diff --git a/netwerk/test/unit/test_offlinecache_custom-directory.js b/netwerk/test/unit/test_offlinecache_custom-directory.js index 43becb2a2e8e..52c6921f9ec5 100644 --- a/netwerk/test/unit/test_offlinecache_custom-directory.js +++ b/netwerk/test/unit/test_offlinecache_custom-directory.js @@ -64,6 +64,22 @@ function finish_test(customDir) file2.append("0B457F75198B29-0"); do_check_eq(file2.exists(), true); + // This must not throw an exception. After the update has finished + // the index file can be freely removed. This way we check this process + // is no longer keeping the file open. Check like this will probably + // work only Windows systems. + + // This test could potentially randomaly fail when we start closing + // the offline cache database off the main thread. Tries in a loop + // may be a solution then. + try { + indexSqlFile.remove(false); + do_check_true(true); + } + catch (ex) { + do_throw("Could not remove the sqlite.index file, we still keep it open \n" + ex + "\n"); + } + httpServer.stop(do_test_finished); }