Created
December 1, 2015 23:52
-
-
Save valenting/d31c1add96a6bc73c190 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User Valentin Gosu <[email protected]> | |
# Parent f97f55fc53b5d63e90ad875f3a75028ef4dc70bb | |
diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp | |
--- a/netwerk/cache2/CacheEntry.cpp | |
+++ b/netwerk/cache2/CacheEntry.cpp | |
@@ -1086,16 +1086,22 @@ NS_IMETHODIMP CacheEntry::GetIsForcedVal | |
} | |
*aIsForcedValid = CacheStorageService::Self()->IsForcedValidEntry(key); | |
LOG(("CacheEntry::GetIsForcedValid [this=%p, IsForcedValid=%d]", this, *aIsForcedValid)); | |
return NS_OK; | |
} | |
+NS_IMETHODIMP CacheEntry::GetIsPinned(bool *aIsPinned) | |
+{ | |
+ *aIsPinned = mPinned; | |
+ return NS_OK; | |
+} | |
+ | |
NS_IMETHODIMP CacheEntry::ForceValidFor(uint32_t aSecondsToTheFuture) | |
{ | |
LOG(("CacheEntry::ForceValidFor [this=%p, aSecondsToTheFuture=%d]", this, aSecondsToTheFuture)); | |
nsAutoCString key; | |
nsresult rv = HashingKeyWithStorage(key); | |
if (NS_FAILED(rv)) { | |
return rv; | |
diff --git a/netwerk/cache2/OldWrappers.cpp b/netwerk/cache2/OldWrappers.cpp | |
--- a/netwerk/cache2/OldWrappers.cpp | |
+++ b/netwerk/cache2/OldWrappers.cpp | |
@@ -367,16 +367,22 @@ NS_IMETHODIMP | |
} | |
NS_IMETHODIMP _OldCacheEntryWrapper::GetIsForcedValid(bool *aIsForcedValid) | |
{ | |
// Unused stub | |
return NS_ERROR_NOT_IMPLEMENTED; | |
} | |
+NS_IMETHODIMP _OldCacheEntryWrapper::GetIsPinned(bool *aIsPinned) | |
+{ | |
+ // Unused stub | |
+ return NS_ERROR_NOT_IMPLEMENTED; | |
+} | |
+ | |
NS_IMETHODIMP _OldCacheEntryWrapper::ForceValidFor(uint32_t aSecondsToTheFuture) | |
{ | |
// Unused stub | |
return NS_ERROR_NOT_IMPLEMENTED; | |
} | |
NS_IMPL_ISUPPORTS(_OldCacheEntryWrapper, nsICacheEntry) | |
diff --git a/netwerk/cache2/OldWrappers.h b/netwerk/cache2/OldWrappers.h | |
--- a/netwerk/cache2/OldWrappers.h | |
+++ b/netwerk/cache2/OldWrappers.h | |
@@ -120,16 +120,17 @@ public: | |
nsresult GetDataSize(uint32_t *aDataSize) | |
{ | |
return mOldInfo->GetDataSize(aDataSize); | |
} | |
NS_IMETHOD AsyncDoom(nsICacheEntryDoomCallback* listener) override; | |
NS_IMETHOD GetPersistent(bool *aPersistToDisk) override; | |
NS_IMETHOD GetIsForcedValid(bool *aIsForcedValid) override; | |
+ NS_IMETHOD GetIsPinned(bool *aIsPinned) override; | |
NS_IMETHOD ForceValidFor(uint32_t aSecondsToTheFuture) override; | |
NS_IMETHOD SetValid() override { return NS_OK; } | |
NS_IMETHOD MetaDataReady() override { return NS_OK; } | |
NS_IMETHOD Recreate(bool, nsICacheEntry**) override; | |
NS_IMETHOD GetDataSize(int64_t *size) override; | |
NS_IMETHOD OpenInputStream(int64_t offset, nsIInputStream * *_retval) override; | |
NS_IMETHOD OpenOutputStream(int64_t offset, nsIOutputStream * *_retval) override; | |
NS_IMETHOD MaybeMarkValid() override; | |
diff --git a/netwerk/cache2/nsICacheEntry.idl b/netwerk/cache2/nsICacheEntry.idl | |
--- a/netwerk/cache2/nsICacheEntry.idl | |
+++ b/netwerk/cache2/nsICacheEntry.idl | |
@@ -80,16 +80,21 @@ interface nsICacheEntry : nsISupports | |
/** | |
* The state variable for whether this entry is currently forced valid. | |
* Defaults to false for normal cache validation behavior, and will return | |
* true if the number of seconds set by forceValidFor() has yet to be reached. | |
*/ | |
readonly attribute boolean isForcedValid; | |
/** | |
+ * This variable indicates if the cache entry is pinned or not. | |
+ */ | |
+ readonly attribute boolean isPinned; | |
+ | |
+ /** | |
* Open blocking input stream to cache data. Use the stream transport | |
* service to asynchronously read this stream on a background thread. | |
* The returned stream MAY implement nsISeekableStream. | |
* | |
* @param offset | |
* read starting from this offset into the cached data. an offset | |
* beyond the end of the stream has undefined consequences. | |
* | |
diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp | |
--- a/netwerk/protocol/http/nsHttpChannel.cpp | |
+++ b/netwerk/protocol/http/nsHttpChannel.cpp | |
@@ -3268,16 +3268,24 @@ nsHttpChannel::OnCacheEntryCheck(nsICach | |
NS_ENSURE_SUCCESS(rv,rv); | |
bool doValidation = false; | |
bool canAddImsHeader = true; | |
bool isForcedValid = false; | |
entry->GetIsForcedValid(&isForcedValid); | |
+ bool isPinned = false; | |
+ entry->GetIsPinned(&isPinned); | |
+ | |
+ if (mCacheStorage && isPinned && (mLoadFlags & VALIDATE_ALWAYS)) { | |
+ // TODO: uncomment this line in order to trigger different bug | |
+ // isForcedValid = false; | |
+ } | |
+ | |
// Cached entry is not the entity we request (see bug #633743) | |
if (ResponseWouldVary(entry)) { | |
LOG(("Validating based on Vary headers returning TRUE\n")); | |
canAddImsHeader = false; | |
doValidation = true; | |
} | |
// Check isForcedValid to see if it is possible to skip validation | |
// See netwerk/cache2/nsICacheEntry.idl for details | |
diff --git a/netwerk/test/unit/test_cache2-31e-deferred-update.js b/netwerk/test/unit/test_cache2-31e-deferred-update.js | |
new file mode 100644 | |
--- /dev/null | |
+++ b/netwerk/test/unit/test_cache2-31e-deferred-update.js | |
@@ -0,0 +1,198 @@ | |
+Cu.import('resource://gre/modules/LoadContextInfo.jsm'); | |
+Cu.import("resource://testing-common/httpd.js"); | |
+Cu.import("resource://gre/modules/Services.jsm"); | |
+Cu.import("resource://gre/modules/NetUtil.jsm"); | |
+ | |
+var gRequestIndex = 0; | |
+function contentHandler(metadata, response) | |
+{ | |
+ gRequestIndex++; | |
+ | |
+ dump("## Response number "+gRequestIndex+"\n"); | |
+ | |
+ response.setHeader("Content-Type", 'application/package'); | |
+ response.setHeader("ETag", '"'+gRequestIndex+'"'); | |
+ | |
+ var body = 'number:' + gRequestIndex; | |
+ response.bodyOutputStream.write(body, body.length); | |
+} | |
+ | |
+var gStorage = null; | |
+var gHttpServer = null; | |
+ | |
+XPCOMUtils.defineLazyGetter(this, "gPath", function() { | |
+ return "http://localhost:" + gHttpServer.identity.primaryPort + "/path"; | |
+}); | |
+ | |
+function run_test() | |
+{ | |
+ do_get_profile(); | |
+ | |
+ // setup test | |
+ gHttpServer = new HttpServer(); | |
+ gHttpServer.registerPathHandler("/path", contentHandler); | |
+ | |
+ gHttpServer.start(-1); | |
+ | |
+ let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); | |
+ let principal = ssm.createCodebasePrincipal(createURI(gPath), {}); | |
+ let loadContext = LoadContextInfo.custom(false, false, principal.originAttributes); | |
+ let cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"] | |
+ .getService(Ci.nsICacheStorageService); | |
+ gStorage = cacheService.diskCacheStorage(loadContext, false); | |
+ | |
+ add_test(simple_get); | |
+ add_test(test_update); | |
+ | |
+ run_next_test(); | |
+} | |
+ | |
+function get_pinning_storage() { | |
+ let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); | |
+ let principal = ssm.createCodebasePrincipal(createURI(gPath), {}); | |
+ let loadContext = LoadContextInfo.custom(false, false, principal.originAttributes); | |
+ let cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"] | |
+ .getService(Ci.nsICacheStorageService); | |
+ let storage = cacheService.pinningCacheStorage(loadContext); | |
+ let pinningStorage = storage.QueryInterface(Ci.nsIPinningCacheStorage); | |
+ return pinningStorage; | |
+} | |
+ | |
+function getChannelForURL(url, notificationCallbacks) { | |
+ let uri = createURI(url); | |
+ let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] | |
+ .getService(Ci.nsIScriptSecurityManager); | |
+ let principal = ssm.createCodebasePrincipal(uri, {}); | |
+ let tmpChannel = | |
+ NetUtil.newChannel({ | |
+ uri: url, | |
+ loadingPrincipal: principal, | |
+ contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER | |
+ }); | |
+ | |
+ if (notificationCallbacks) { | |
+ // Use custom notificationCallbacks if any. | |
+ tmpChannel.notificationCallbacks = notificationCallbacks; | |
+ } else { | |
+ tmpChannel.notificationCallbacks = | |
+ new LoadContextCallback(principal.appId, | |
+ principal.isInBrowserElement, | |
+ false, | |
+ false); | |
+ | |
+ } | |
+ return tmpChannel; | |
+} | |
+ | |
+function simple_get() { | |
+ do_check_true(true); | |
+ let pinningStorage = get_pinning_storage(); | |
+ let chan = getChannelForURL(gPath); | |
+ let cachingChannel = chan.QueryInterface(Ci.nsICachingChannel); | |
+ cachingChannel.cacheOnlyMetadata = true; | |
+ cachingChannel.cacheStorage = pinningStorage; | |
+ chan.asyncOpen({ | |
+ onStartRequest: function(request, ctx) { | |
+ }, | |
+ onDataAvailable: function(request, context, stream, offset, count) { | |
+ let content = read_stream(stream, count); | |
+ }, | |
+ onStopRequest: function(request, ctx, status) { | |
+ run_next_test(); | |
+ } | |
+ }, null); | |
+} | |
+ | |
+// This test attempts to revalidate the pinned cache entry. | |
+// If it succeeds, at the end, the cache should contain a pinned cache entry | |
+// which is different from the previous one (different Etag) | |
+function test_update() { | |
+ let pinningStorage = get_pinning_storage(); | |
+ pinningStorage.defer(); | |
+ | |
+ // Open previous cache entry | |
+ gStorage.asyncOpenURI(createURI(gPath), "", Ci.nsICacheStorage.OPEN_READONLY, { | |
+ onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; }, | |
+ onCacheEntryAvailable: function (entry, isnew, appcache, status) { | |
+ | |
+ do_check_true(!!entry); | |
+ | |
+ // Create new entry in deferred cache, and copy metadata | |
+ let pinnedEntry = pinningStorage.openTruncate(createURI(gPath), ""); | |
+ entry.visitMetaData({ | |
+ onMetaDataElement: function(key, value) { | |
+ pinnedEntry.setMetaDataElement(key,value); | |
+ } | |
+ }); | |
+ pinnedEntry.metaDataReady(); | |
+ | |
+ // Open a new channel to download resource | |
+ let chan = getChannelForURL(gPath); | |
+ chan.loadFlags |= Ci.nsIRequest.VALIDATE_ALWAYS; | |
+ let cachingChannel = chan.QueryInterface(Ci.nsICachingChannel); | |
+ cachingChannel.cacheOnlyMetadata = true; | |
+ cachingChannel.cacheStorage = pinningStorage; | |
+ | |
+ dump("About to open channel. Bug1: it stalls\n"); | |
+ // Opening the channel should replace the cache entry with the new one | |
+ // after revalidation | |
+ chan.asyncOpen({ | |
+ onStartRequest: function(request, ctx) { | |
+ dump("onStartRequest\n"); | |
+ }, | |
+ onDataAvailable: function(request, context, stream, offset, count) { | |
+ let content = read_stream(stream, count); | |
+ dump("content" + content+ "\n"); | |
+ }, | |
+ onStopRequest: function(request, ctx, status) { | |
+ dump("onStopRequest\n"); | |
+ | |
+ // Commit the storage. | |
+ pinningStorage.commit({ | |
+ onCacheStorageCommitted: function(result) { | |
+ do_check_eq(result, Cr.NS_OK); | |
+ | |
+ // Now check the entry can be opened. | |
+ check_open_entry(); | |
+ } | |
+ }); | |
+ } | |
+ }, null); | |
+ } | |
+ }); | |
+} | |
+ | |
+function check_open_entry() { | |
+ dump("Opening:" +gPath+"\n"); | |
+ gStorage.asyncOpenURI(createURI(gPath), "", Ci.nsICacheStorage.OPEN_READONLY, { | |
+ onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; }, | |
+ onCacheEntryAvailable: function (entry, isnew, appcache, status) { | |
+ if (entry) { | |
+ dump("FOUND ENTRY " + entry.key + "\n"); | |
+ entry.visitMetaData({ | |
+ onMetaDataElement: function(key, value) { | |
+ dump("Metadata: "+key+":"+value+" [end]\n"); | |
+ } | |
+ }); | |
+ // Success! | |
+ run_next_test(); | |
+ } else { | |
+ dump("NOT FOUND "+gPath+"\n") | |
+ dump("Bug2: asyncOpenURI did not find the pinned entry.\n"); | |
+ } | |
+ | |
+ gStorage.asyncVisitStorage({ | |
+ onCacheStorageInfo: function(aEntryCount, aConsumption, aCapacity, aDiskDirectory) { | |
+ | |
+ }, | |
+ onCacheEntryInfo: function(aURI, aIdEnhance, aDataSize, aFetchCount, aLastModifiedTime, aExpirationTime, aPinned) { | |
+ dump("aURI: "+aURI.spec +" pinned: "+aPinned+"\n"); | |
+ }, | |
+ onCacheEntryVisitCompleted: function() { | |
+ } | |
+ }, true); | |
+ | |
+ } | |
+ }); | |
+} | |
+ | |
diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini | |
--- a/netwerk/test/unit/xpcshell.ini | |
+++ b/netwerk/test/unit/xpcshell.ini | |
@@ -75,16 +75,17 @@ skip-if = true | |
[test_cache2-30a-entry-pinning.js] | |
[test_cache2-30b-pinning-storage-clear.js] | |
[test_cache2-30c-pinning-deferred-doom.js] | |
[test_cache2-30d-pinning-WasEvicted-API.js] | |
[test_cache2-31a-deferred-commit.js] | |
[test_cache2-31b-deferred-rollback.js] | |
[test_cache2-31c-deferred-open-truncate.js] | |
[test_cache2-31d-deferred-persistence-check.js] | |
+[test_cache2-31e-deferred-update.js] | |
[test_partial_response_entry_size_smart_shrink.js] | |
[test_304_responses.js] | |
[test_421.js] | |
[test_cacheForOfflineUse_no-store.js] | |
[test_307_redirect.js] | |
[test_NetUtil.js] | |
[test_URIs.js] | |
[test_URIs2.js] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment