зеркало из https://github.com/mozilla/pjs.git
Bug 425792: Properly update and use expiration times when updating the offline cache. r/sr=biesi, b1.9=damons
This commit is contained in:
Родитель
821918e2c9
Коммит
949505d29b
|
@ -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)
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" manifest="http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/changingManifest.sjs">
|
||||
<head>
|
||||
<title>changing manifest test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var gGotChecking = false;
|
||||
var gGotDownloading = false;
|
||||
|
||||
var g1SecUrl = "http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/changing1Sec.sjs";
|
||||
var g1HourUrl = "http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/changing1Hour.sjs";
|
||||
|
||||
var gCacheContents = null;
|
||||
|
||||
function manifestUpdatedAgain()
|
||||
{
|
||||
OfflineTest.ok(gGotChecking, "Should get a checking event on the second update");
|
||||
OfflineTest.ok(gGotDownloading, "Should get a downloading event on the second update");
|
||||
|
||||
// Get the initial contents of the first two files.
|
||||
fetcher = new OfflineCacheContents([g1SecUrl, g1HourUrl]);
|
||||
fetcher.fetch(function(contents) {
|
||||
// Make sure the contents of the 1-second-expiration file have changed,
|
||||
// but that the 1-hour-expiration has not.
|
||||
OfflineTest.isnot(gCacheContents[g1SecUrl], contents[g1SecUrl], "1-second expiration should have changed");
|
||||
OfflineTest.is(gCacheContents[g1HourUrl], contents[g1HourUrl], "1-hour expiration should not have changed");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
function failAndFinish(e) {
|
||||
OfflineTest.ok(false, "Unexpected event: " + e.type);
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
}
|
||||
|
||||
function manifestUpdated()
|
||||
{
|
||||
OfflineTest.ok(gGotChecking, "Should get a checking event");
|
||||
OfflineTest.ok(gGotDownloading, "Should get a downloading event");
|
||||
|
||||
// Get the initial contents of the first two files.
|
||||
fetcher = new OfflineCacheContents([g1SecUrl, g1HourUrl]);
|
||||
fetcher.fetch(function(contents) {
|
||||
gCacheContents = contents;
|
||||
|
||||
// Now make sure applicationCache.update() does what we expect.
|
||||
applicationCache.oncached = OfflineTest.priv(manifestUpdatedAgain);
|
||||
applicationCache.onnoupdate = 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);
|
||||
});
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
applicationCache.onerror = failAndFinish;
|
||||
applicationCache.onnoupdate = failAndFinish;
|
||||
|
||||
applicationCache.onchecking = function() { gGotChecking = true; };
|
||||
applicationCache.ondownloading = function() { gGotDownloading = true; };
|
||||
applicationCache.oncached = OfflineTest.priv(manifestUpdated);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче