From 0919eed89cf7ecbc8411c0f9decaccd38ceec20d Mon Sep 17 00:00:00 2001 From: "dcamp%mozilla.com" Date: Wed, 9 Apr 2008 05:22:35 +0000 Subject: [PATCH] Bug 425792: Properly update and use expiration times when updating the offline cache. r/sr=biesi, b1.9=damons git-svn-id: svn://10.0.0.236/trunk@249887 18797224-902f-48f8-a5cc-f745e15eee43 --- .../tests/mochitest/ajax/offline/Makefile.in | 4 + .../mochitest/ajax/offline/changing1Hour.sjs | 8 ++ .../mochitest/ajax/offline/changing1Sec.sjs | 9 ++ .../ajax/offline/changingManifest.sjs | 12 +++ .../mochitest/ajax/offline/offlineTests.js | 76 +++++++++++++++-- .../ajax/offline/test_changingManifest.html | 85 +++++++++++++++++++ mozilla/netwerk/cache/src/nsCacheService.cpp | 6 +- .../protocol/http/src/nsHttpChannel.cpp | 30 ++++++- 8 files changed, 219 insertions(+), 11 deletions(-) create mode 100644 mozilla/dom/tests/mochitest/ajax/offline/changing1Hour.sjs create mode 100644 mozilla/dom/tests/mochitest/ajax/offline/changing1Sec.sjs create mode 100644 mozilla/dom/tests/mochitest/ajax/offline/changingManifest.sjs create mode 100644 mozilla/dom/tests/mochitest/ajax/offline/test_changingManifest.html diff --git a/mozilla/dom/tests/mochitest/ajax/offline/Makefile.in b/mozilla/dom/tests/mochitest/ajax/offline/Makefile.in index 199ef707ff0..04598ae4768 100644 --- a/mozilla/dom/tests/mochitest/ajax/offline/Makefile.in +++ b/mozilla/dom/tests/mochitest/ajax/offline/Makefile.in @@ -52,6 +52,7 @@ _TEST_FILES = \ test_missingFile.html \ test_simpleManifest.html \ test_identicalManifest.html \ + test_changingManifest.html \ test_offlineIFrame.html \ badManifestMagic.cacheManifest \ badManifestMagic.cacheManifest^headers^ \ @@ -60,6 +61,9 @@ _TEST_FILES = \ simpleManifest.cacheManifest \ simpleManifest.cacheManifest^headers^ \ simpleManifest.notmanifest \ + changing1Sec.sjs \ + changing1Hour.sjs \ + changingManifest.sjs \ offlineChild.html \ $(NULL) diff --git a/mozilla/dom/tests/mochitest/ajax/offline/changing1Hour.sjs b/mozilla/dom/tests/mochitest/ajax/offline/changing1Hour.sjs new file mode 100644 index 00000000000..2a103596507 --- /dev/null +++ b/mozilla/dom/tests/mochitest/ajax/offline/changing1Hour.sjs @@ -0,0 +1,8 @@ +function handleRequest(request, response) +{ + response.setStatusLine(request.httpVersion, 200, "Ok"); + response.setHeader("Content-Type", "text/plain"); + response.setHeader("Cache-Control", "max-age=3600"); + + response.write(Date.now()); +} diff --git a/mozilla/dom/tests/mochitest/ajax/offline/changing1Sec.sjs b/mozilla/dom/tests/mochitest/ajax/offline/changing1Sec.sjs new file mode 100644 index 00000000000..cb9428b6c32 --- /dev/null +++ b/mozilla/dom/tests/mochitest/ajax/offline/changing1Sec.sjs @@ -0,0 +1,9 @@ +function handleRequest(request, response) +{ + response.setStatusLine(request.httpVersion, 200, "Ok"); + response.setHeader("Content-Type", "text/plain"); + response.setHeader("Cache-Control", "max-age=1"); + + response.write(Date.now()); +} + diff --git a/mozilla/dom/tests/mochitest/ajax/offline/changingManifest.sjs b/mozilla/dom/tests/mochitest/ajax/offline/changingManifest.sjs new file mode 100644 index 00000000000..b0d06196237 --- /dev/null +++ b/mozilla/dom/tests/mochitest/ajax/offline/changingManifest.sjs @@ -0,0 +1,12 @@ +function handleRequest(request, response) +{ + response.setStatusLine(request.httpVersion, 200, "Ok"); + response.setHeader("Content-Type", "text/cache-manifest"); + response.setHeader("Cache-Control", "no-cache"); + + response.write("CACHE MANIFEST\n"); + response.write("#" + Date.now() + "\n"); + response.write("http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/changing1Hour.sjs\n"); + response.write("http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/changing1Sec.sjs\n"); +} + diff --git a/mozilla/dom/tests/mochitest/ajax/offline/offlineTests.js b/mozilla/dom/tests/mochitest/ajax/offline/offlineTests.js index a8a92cbd414..06a062984a4 100644 --- a/mozilla/dom/tests/mochitest/ajax/offline/offlineTests.js +++ b/mozilla/dom/tests/mochitest/ajax/offline/offlineTests.js @@ -4,6 +4,63 @@ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var Cc = Components.classes; var Ci = Components.interfaces; +const kNetBase = 2152398848; // 0x804B0000 +var NS_ERROR_CACHE_KEY_NOT_FOUND = kNetBase + 61; +var NS_ERROR_CACHE_KEY_WAIT_FOR_VALIDATION = kNetBase + 64; + +// Reading the contents of multiple cache entries asynchronously +function OfflineCacheContents(urls) { + this.urls = urls; + this.contents = {}; +} + +OfflineCacheContents.prototype = { +QueryInterface: function(iid) { + if (!iid.equals(Ci.nsISupports) && + !iid.equals(Ci.nsICacheListener)) { + throw Cr.NS_ERROR_NO_INTERFACE; + } + return this; + }, +onCacheEntryAvailable: function(desc, accessGranted, status) { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + if (!desc) { + this.fetch(this.callback); + return; + } + + var stream = desc.QueryInterface(Ci.nsICacheEntryDescriptor).openInputStream(0); + var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"] + .createInstance(Components.interfaces.nsIScriptableInputStream); + sstream.init(stream); + this.contents[desc.key] = sstream.read(sstream.available()); + sstream.close(); + desc.close(); + this.fetch(this.callback); + }, + +fetch: function(callback) +{ + this.callback = callback; + if (this.urls.length == 0) { + callback(this.contents); + return; + } + + var url = this.urls.shift(); + var self = this; + + var cacheService = Cc["@mozilla.org/network/cache-service;1"] + .getService(Ci.nsICacheService); + var cacheSession = cacheService.createSession("HTTP-offline", + Ci.nsICache.STORE_OFFLINE, + true); + cacheSession.asyncOpenCacheEntry(url, Ci.nsICache.ACCESS_READ, this); +} + +}; + var OfflineTest = { _slaveWindow: null, @@ -103,6 +160,11 @@ is: function(a, b, name) return this._masterWindow.SimpleTest.is(a, b, name); }, +isnot: function(a, b, name) +{ + return this._masterWindow.SimpleTest.isnot(a, b, name); +}, + clear: function() { // Clear the ownership list @@ -179,7 +241,7 @@ priv: function(func) var self = this; return function() { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - func(); + func(arguments); } }, @@ -191,7 +253,7 @@ checkCache: function(url, expectEntry) Ci.nsICache.STORE_OFFLINE, true); try { - var entry = cacheSession.openCacheEntry(url, Ci.nsICache.ACCESS_READ, true); + var entry = cacheSession.openCacheEntry(url, Ci.nsICache.ACCESS_READ, false); if (expectEntry) { this.ok(true, url + " should exist in the offline cache"); } else { @@ -199,15 +261,19 @@ checkCache: function(url, expectEntry) } entry.close(); } catch (e) { - // this constant isn't in Components.results - const kNetBase = 2152398848; // 0x804B0000 - var NS_ERROR_CACHE_KEY_NOT_FOUND = kNetBase + 61 if (e.result == NS_ERROR_CACHE_KEY_NOT_FOUND) { if (expectEntry) { this.ok(false, url + " should exist in the offline cache"); } else { this.ok(true, url + " should not exist in the offline cache"); } + } else if (e.result == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) { + // 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; } diff --git a/mozilla/dom/tests/mochitest/ajax/offline/test_changingManifest.html b/mozilla/dom/tests/mochitest/ajax/offline/test_changingManifest.html new file mode 100644 index 00000000000..93decb34413 --- /dev/null +++ b/mozilla/dom/tests/mochitest/ajax/offline/test_changingManifest.html @@ -0,0 +1,85 @@ + + +changing manifest test + + + + + + + + + + + + + diff --git a/mozilla/netwerk/cache/src/nsCacheService.cpp b/mozilla/netwerk/cache/src/nsCacheService.cpp index 7f15f7c701c..5aa65939d38 100644 --- a/mozilla/netwerk/cache/src/nsCacheService.cpp +++ b/mozilla/netwerk/cache/src/nsCacheService.cpp @@ -1465,8 +1465,10 @@ nsCacheService::ActivateEntry(nsCacheRequest * request, if (entry && ((request->AccessRequested() == nsICache::ACCESS_WRITE) || - (entry->mExpirationTime <= SecondsFromPRTime(PR_Now()) && - request->WillDoomEntriesIfExpired()))) + ((request->StoragePolicy() != nsICache::STORE_OFFLINE) && + (entry->mExpirationTime <= SecondsFromPRTime(PR_Now()) && + request->WillDoomEntriesIfExpired())))) + { // this is FORCE-WRITE request or the entry has expired rv = DoomEntry_Internal(entry); diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp index f57a8f3531d..b7f0f249124 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -1540,10 +1540,11 @@ nsHttpChannel::UpdateExpirationTime() { NS_ENSURE_TRUE(mResponseHead, NS_ERROR_FAILURE); + nsresult rv; + PRUint32 expirationTime = 0; if (!mResponseHead->MustValidate()) { PRUint32 freshnessLifetime = 0; - nsresult rv; rv = mResponseHead->ComputeFreshnessLifetime(&freshnessLifetime); if (NS_FAILED(rv)) return rv; @@ -1569,7 +1570,16 @@ nsHttpChannel::UpdateExpirationTime() expirationTime = now; } } - return mCacheEntry->SetExpirationTime(expirationTime); + + rv = mCacheEntry->SetExpirationTime(expirationTime); + NS_ENSURE_SUCCESS(rv, rv); + + if (mOfflineCacheEntry) { + rv = mOfflineCacheEntry->SetExpirationTime(expirationTime); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; } // CheckCache is called from Connect after a cache entry has been opened for @@ -1631,10 +1641,11 @@ nsHttpChannel::CheckCache() // Don't bother to validate LOAD_ONLY_FROM_CACHE items. // Don't bother to validate items that are read-only, - // unless they are read-only because of INHIBIT_CACHING. + // unless they are read-only because of INHIBIT_CACHING or because + // we're updating the offline cache. if (mLoadFlags & LOAD_ONLY_FROM_CACHE || (mCacheAccess == nsICache::ACCESS_READ && - !(mLoadFlags & INHIBIT_CACHING))) { + !((mLoadFlags & INHIBIT_CACHING) || mCacheForOfflineUse))) { mCachedContentIsValid = PR_TRUE; return NS_OK; } @@ -2054,6 +2065,17 @@ nsHttpChannel::InitOfflineCacheEntry() return NS_OK; } + // This entry's expiration time should match the main entry's expiration + // time. UpdateExpirationTime() will keep it in sync once the offline + // cache entry has been created. + if (mCacheEntry) { + PRUint32 expirationTime; + nsresult rv = mCacheEntry->GetExpirationTime(&expirationTime); + NS_ENSURE_SUCCESS(rv, rv); + + mOfflineCacheEntry->SetExpirationTime(expirationTime); + } + return AddCacheEntryHeaders(mOfflineCacheEntry); }