WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-201461-20190925161255.patch (text/plain), 42.52 KB, created by
Rob Buis
on 2019-09-25 07:12:06 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Rob Buis
Created:
2019-09-25 07:12:06 PDT
Size:
42.52 KB
patch
obsolete
>Subversion Revision: 250201 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 678e4dffd433c0548b91f5ce009bc1cf68f79009..0a8951f3f6c89080d76db890ea886d875503bbee 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,24 @@ >+2019-09-25 Rob Buis <rbuis@igalia.com> >+ >+ Support stale-while-revalidate cache strategy >+ https://bugs.webkit.org/show_bug.cgi?id=201461 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Tests: imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https.html >+ imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch.html >+ imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-css.html >+ imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-image.html >+ imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-script.html >+ >+ * platform/network/CacheValidation.cpp: >+ (WebCore::parseCacheControlDirectives): >+ * platform/network/CacheValidation.h: >+ (WebCore::CacheControlDirectives::CacheControlDirectives): >+ * platform/network/ResourceResponseBase.cpp: >+ (WebCore::ResourceResponseBase::cacheControlStaleWhileRevalidate const): >+ * platform/network/ResourceResponseBase.h: >+ > 2019-09-22 David Kilzer <ddkilzer@apple.com> > > clang-tidy: Fix unnecessary copy/ref churn of for loop variables in WebCore >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index c792409c10ad5adb19386b211a8a5f45e4173e9f..99043418204ecd0a805ee5012b93ac7cef9d2b84 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,25 @@ >+2019-09-25 Rob Buis <rbuis@igalia.com> >+ >+ Support stale-while-revalidate cache strategy >+ https://bugs.webkit.org/show_bug.cgi?id=201461 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * NetworkProcess/cache/NetworkCache.cpp: >+ (WebKit::NetworkCache::responseHasExpired): >+ (WebKit::NetworkCache::responseNeedsRevalidation): >+ (WebKit::NetworkCache::makeUseDecision): >+ (WebKit::NetworkCache::makeStoreDecision): >+ (WebKit::NetworkCache::Cache::retrieve): >+ * NetworkProcess/cache/NetworkCache.h: >+ * NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp: >+ (WebKit::NetworkCache::constructRevalidationRequest): >+ (WebKit::NetworkCache::AsyncRevalidation::AsyncRevalidation): >+ (WebKit::NetworkCache::AsyncRevalidation::load const): >+ (WebKit::NetworkCache::AsyncRevalidation::staleWhileRevalidateEnding): >+ (WebKit::NetworkCache::SpeculativeLoadManager::startAsyncRevalidationIfNeeded): >+ * NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h: >+ > 2019-09-21 Dan Bernstein <mitz@apple.com> > > Fix an assertion failure introduced in r250186. >diff --git a/Source/WebCore/platform/network/CacheValidation.cpp b/Source/WebCore/platform/network/CacheValidation.cpp >index 4959050679ce0504842447eb1f5a0bf8a67683ce..76379816e333f5aaeb13687009e281470432bc57 100644 >--- a/Source/WebCore/platform/network/CacheValidation.cpp >+++ b/Source/WebCore/platform/network/CacheValidation.cpp >@@ -313,8 +313,20 @@ CacheControlDirectives parseCacheControlDirectives(const HTTPHeaderMap& headers) > double maxStale = directives[i].second.toDouble(&ok); > if (ok) > result.maxStale = Seconds { maxStale }; >- } else if (equalLettersIgnoringASCIICase(directives[i].first, "immutable")) >+ } else if (equalLettersIgnoringASCIICase(directives[i].first, "immutable")) { > result.immutable = true; >+ } else if (equalLettersIgnoringASCIICase(directives[i].first, "stale-while-revalidate")) { >+ if (result.staleWhileRevalidate) { >+ // First stale-while-revalidate directive wins if there are multiple ones. >+ continue; >+ } >+ bool ok; >+ double staleWhileRevalidate = directives[i].second.toDouble(&ok); >+ if (ok) { >+ result.maxStale = Seconds { staleWhileRevalidate }; >+ result.staleWhileRevalidate = true; >+ } >+ } > } > } > >diff --git a/Source/WebCore/platform/network/CacheValidation.h b/Source/WebCore/platform/network/CacheValidation.h >index aa7ad7f1314b63d373a2ac717227cccf1d0cbaad..c064561f50f0538396dc2ed9bcfdc75af74356d0 100644 >--- a/Source/WebCore/platform/network/CacheValidation.h >+++ b/Source/WebCore/platform/network/CacheValidation.h >@@ -65,6 +65,7 @@ struct CacheControlDirectives { > , noStore(false) > , mustRevalidate(false) > , immutable(false) >+ , staleWhileRevalidate(false) > { } > > Markable<Seconds, Seconds::MarkableTraits> maxAge; >@@ -73,6 +74,7 @@ struct CacheControlDirectives { > bool noStore : 1; > bool mustRevalidate : 1; > bool immutable : 1; >+ bool staleWhileRevalidate : 1; > }; > WEBCORE_EXPORT CacheControlDirectives parseCacheControlDirectives(const HTTPHeaderMap&); > >diff --git a/Source/WebCore/platform/network/ResourceResponseBase.cpp b/Source/WebCore/platform/network/ResourceResponseBase.cpp >index 20ac64d57034c69ea92bc7a43536f16d795ffa29..5cbdbfec9adcc7c77fa091c992804de49527fd1b 100644 >--- a/Source/WebCore/platform/network/ResourceResponseBase.cpp >+++ b/Source/WebCore/platform/network/ResourceResponseBase.cpp >@@ -655,6 +655,15 @@ Optional<Seconds> ResourceResponseBase::cacheControlMaxAge() const > return m_cacheControlDirectives.maxAge; > } > >+Optional<Seconds> ResourceResponseBase::cacheControlStaleWhileRevalidate() const >+{ >+ if (!m_haveParsedCacheControlHeader) >+ parseCacheControlDirectives(); >+ if (m_cacheControlDirectives.staleWhileRevalidate) >+ return m_cacheControlDirectives.maxStale; >+ return WTF::nullopt; >+} >+ > static Optional<WallTime> parseDateValueInHeader(const HTTPHeaderMap& headers, HTTPHeaderName headerName) > { > String headerValue = headers.get(headerName); >diff --git a/Source/WebCore/platform/network/ResourceResponseBase.h b/Source/WebCore/platform/network/ResourceResponseBase.h >index cb17b595487d10b773c4e4853543024a50f1a97f..40681f077ab9eed09c935bb0baac9e0b409c38de 100644 >--- a/Source/WebCore/platform/network/ResourceResponseBase.h >+++ b/Source/WebCore/platform/network/ResourceResponseBase.h >@@ -136,6 +136,7 @@ public: > WEBCORE_EXPORT bool cacheControlContainsImmutable() const; > WEBCORE_EXPORT bool hasCacheValidatorFields() const; > WEBCORE_EXPORT Optional<Seconds> cacheControlMaxAge() const; >+ WEBCORE_EXPORT Optional<Seconds> cacheControlStaleWhileRevalidate() const; > WEBCORE_EXPORT Optional<WallTime> date() const; > WEBCORE_EXPORT Optional<Seconds> age() const; > WEBCORE_EXPORT Optional<WallTime> expires() const; >diff --git a/Source/WebKit/NetworkProcess/cache/NetworkCache.cpp b/Source/WebKit/NetworkProcess/cache/NetworkCache.cpp >index f344d1aba64fe93c9cbebd47f43e8163bacd7c17..8709e0be9bcd8174d617f57e31f840a9a91fea3a 100644 >--- a/Source/WebKit/NetworkProcess/cache/NetworkCache.cpp >+++ b/Source/WebKit/NetworkProcess/cache/NetworkCache.cpp >@@ -152,7 +152,7 @@ static bool cachePolicyAllowsExpired(WebCore::ResourceRequestCachePolicy policy) > return false; > } > >-static bool responseHasExpired(const WebCore::ResourceResponse& response, WallTime timestamp, Optional<Seconds> maxStale) >+static bool responseHasExpired(const WebCore::ResourceResponse& response, WallTime timestamp, Optional<Seconds> maxStale, bool& inResponseStaleness) > { > if (response.cacheControlContainsNoCache()) > return true; >@@ -162,25 +162,35 @@ static bool responseHasExpired(const WebCore::ResourceResponse& response, WallTi > > auto maximumStaleness = maxStale ? maxStale.value() : 0_ms; > bool hasExpired = age - lifetime > maximumStaleness; >+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION) >+ if (hasExpired) { >+ auto responseMaxStaleness = response.cacheControlStaleWhileRevalidate(); >+ maximumStaleness += responseMaxStaleness ? responseMaxStaleness.value() : 0_ms; >+ inResponseStaleness = age - lifetime < maximumStaleness; >+ } >+#endif > > #ifndef LOG_DISABLED > if (hasExpired) >- LOG(NetworkCache, "(NetworkProcess) needsRevalidation hasExpired age=%f lifetime=%f max-stale=%g", age, lifetime, maxStale); >+ LOG(NetworkCache, "(NetworkProcess) needsRevalidation hasExpired age=%f lifetime=%f max-staleness=%f", age, lifetime, maximumStaleness); > #endif > > return hasExpired; > } > >-static bool responseNeedsRevalidation(const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& request, WallTime timestamp) >+static UseDecision responseNeedsRevalidation(const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& request, WallTime timestamp) > { > auto requestDirectives = WebCore::parseCacheControlDirectives(request.httpHeaderFields()); > if (requestDirectives.noCache) >- return true; >+ return UseDecision::Validate; > // For requests we ignore max-age values other than zero. > if (requestDirectives.maxAge && requestDirectives.maxAge.value() == 0_ms) >- return true; >+ return UseDecision::Validate; > >- return responseHasExpired(response, timestamp, requestDirectives.maxStale); >+ bool inResponseStaleness = false; >+ if (responseHasExpired(response, timestamp, requestDirectives.maxStale, inResponseStaleness)) >+ return inResponseStaleness ? UseDecision::AsyncRevalidate : UseDecision::Validate; >+ return UseDecision::Use; > } > > static UseDecision makeUseDecision(NetworkProcess& networkProcess, const PAL::SessionID& sessionID, const Entry& entry, const WebCore::ResourceRequest& request) >@@ -197,8 +207,9 @@ static UseDecision makeUseDecision(NetworkProcess& networkProcess, const PAL::Se > if (cachePolicyAllowsExpired(request.cachePolicy())) > return UseDecision::Use; > >- if (!responseNeedsRevalidation(entry.response(), request, entry.timeStamp())) >- return UseDecision::Use; >+ auto decision = responseNeedsRevalidation(entry.response(), request, entry.timeStamp()); >+ if (decision != UseDecision::Validate) >+ return decision; > > if (!entry.response().hasCacheValidatorFields()) > return UseDecision::NoDueToMissingValidatorFields; >@@ -251,8 +262,10 @@ static StoreDecision makeStoreDecision(const WebCore::ResourceRequest& originalR > bool storeUnconditionallyForHistoryNavigation = isMainResource || originalRequest.priority() == WebCore::ResourceLoadPriority::VeryHigh; > if (!storeUnconditionallyForHistoryNavigation) { > auto now = WallTime::now(); >- bool hasNonZeroLifetime = !response.cacheControlContainsNoCache() && WebCore::computeFreshnessLifetimeForHTTPFamily(response, now) > 0_ms; >- >+ Seconds allowedStale; >+ if (auto value = response.cacheControlStaleWhileRevalidate()) >+ allowedStale = value.value(); >+ bool hasNonZeroLifetime = !response.cacheControlContainsNoCache() && (WebCore::computeFreshnessLifetimeForHTTPFamily(response, now) > 0_ms || allowedStale > 0_ms); > bool possiblyReusable = response.hasCacheValidatorFields() || hasNonZeroLifetime; > if (!possiblyReusable) > return StoreDecision::NoDueToUnlikelyToReuse; >@@ -334,12 +347,11 @@ void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameI > } > #endif > >- m_storage->retrieve(storageKey, priority, [request, completionHandler = WTFMove(completionHandler), info = WTFMove(info), storageKey, networkProcess = makeRef(networkProcess()), sessionID = m_sessionID](auto record, auto timings) mutable { >+ m_storage->retrieve(storageKey, priority, [this, request, completionHandler = WTFMove(completionHandler), info = WTFMove(info), storageKey, networkProcess = makeRef(networkProcess()), sessionID = m_sessionID, frameID](auto record, auto timings) mutable { > info.storageTimings = timings; > > if (!record) { > LOG(NetworkCache, "(NetworkProcess) not found in storage"); >- > completeRetrieve(WTFMove(completionHandler), nullptr, info); > return false; > } >@@ -350,6 +362,15 @@ void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameI > > auto useDecision = entry ? makeUseDecision(networkProcess, sessionID, *entry, request) : UseDecision::NoDueToDecodeFailure; > switch (useDecision) { >+ case UseDecision::AsyncRevalidate: { >+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION) >+ if (m_speculativeLoadManager) { >+ std::unique_ptr<Entry> entryCopy = makeUnique<Entry>(*entry); >+ m_speculativeLoadManager->startAsyncRevalidationIfNeeded(request, storageKey, WTFMove(entryCopy), frameID); >+ } >+#endif >+ FALLTHROUGH; >+ } > case UseDecision::Use: > break; > case UseDecision::Validate: >diff --git a/Source/WebKit/NetworkProcess/cache/NetworkCache.h b/Source/WebKit/NetworkProcess/cache/NetworkCache.h >index 5d093d6ccebf4ae360f97c77718adf71b422358b..03b4004a878967d8d110e53b3a8b8914ecfc2a36 100644 >--- a/Source/WebKit/NetworkProcess/cache/NetworkCache.h >+++ b/Source/WebKit/NetworkProcess/cache/NetworkCache.h >@@ -81,6 +81,7 @@ enum class StoreDecision { > enum class UseDecision { > Use, > Validate, >+ AsyncRevalidate, > NoDueToVaryingHeaderMismatch, > NoDueToMissingValidatorFields, > NoDueToDecodeFailure, >diff --git a/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp b/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp >index 6794039b7e1917a4aabad4d2d508f73953786567..4beb050f1b52006e02d952810e158dd6b2ea5356 100644 >--- a/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp >+++ b/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp >@@ -486,7 +486,77 @@ void SpeculativeLoadManager::revalidateSubresource(const SubresourceInfo& subres > }); > m_pendingPreloads.add(key, WTFMove(revalidator)); > } >- >+ >+static inline ResourceRequest constructRevalidationRequest(const Key& key, const ResourceRequest& request, const Entry* entry) >+{ >+ ResourceRequest revalidationRequest = request; >+ if (!key.partition().isEmpty()) >+ revalidationRequest.setCachePartition(key.partition()); >+ ASSERT_WITH_MESSAGE(key.range().isEmpty(), "range is not supported"); >+ >+ revalidationRequest.makeUnconditional(); >+ if (entry) { >+ String eTag = entry->response().httpHeaderField(HTTPHeaderName::ETag); >+ if (!eTag.isEmpty()) >+ revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag); >+ >+ String lastModified = entry->response().httpHeaderField(HTTPHeaderName::LastModified); >+ if (!lastModified.isEmpty()) >+ revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified); >+ } >+ >+ revalidationRequest.setPriority(WebCore::ResourceLoadPriority::Low); >+ >+ return revalidationRequest; >+} >+ >+class AsyncRevalidation { >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ typedef Function<void (bool)> AsyncRevalidationCompletionHandler; >+ AsyncRevalidation(Cache& cache, const GlobalFrameID& frameID, const ResourceRequest& request, std::unique_ptr<NetworkCache::Entry> entry, AsyncRevalidationCompletionHandler&& handler) >+ : m_timer(*this, &AsyncRevalidation::staleWhileRevalidateEnding) >+ , m_completionHandler(WTFMove(handler)) >+ { >+ auto key = entry->key(); >+ auto revalidationRequest = constructRevalidationRequest(key, request, entry.get()); >+ auto age = WebCore::computeCurrentAge(entry->response(), entry->timeStamp()); >+ auto lifetime = WebCore::computeFreshnessLifetimeForHTTPFamily(entry->response(), entry->timeStamp()); >+ auto responseMaxStaleness = entry->response().cacheControlStaleWhileRevalidate(); >+ ASSERT(responseMaxStaleness); >+ m_timer.startOneShot(*responseMaxStaleness - (age - lifetime)); >+ m_load = makeUnique<SpeculativeLoad>(cache, frameID, revalidationRequest, WTFMove(entry), [this, key, revalidationRequest](std::unique_ptr<Entry> revalidatedEntry) { >+ ASSERT(!revalidatedEntry || !revalidatedEntry->needsValidation()); >+ ASSERT(!revalidatedEntry || revalidatedEntry->key() == key); >+ m_completionHandler(revalidatedEntry.get()); >+ }); >+ } >+ >+ const SpeculativeLoad& load() const { return *m_load; } >+ >+ void staleWhileRevalidateEnding() { m_completionHandler(true); } >+ >+private: >+ std::unique_ptr<SpeculativeLoad> m_load; >+ Timer m_timer; >+ AsyncRevalidationCompletionHandler m_completionHandler; >+}; >+ >+void SpeculativeLoadManager::startAsyncRevalidationIfNeeded(const ResourceRequest& request, const NetworkCache::Key& key, std::unique_ptr<Entry> entry, const GlobalFrameID& frameID) >+{ >+ auto* pendingAsyncRevalidation = m_pendingAsyncRevalidations.get(key); >+ if (pendingAsyncRevalidation && canUsePendingPreload(pendingAsyncRevalidation->load(), request)) >+ return; >+ >+ auto revalidator = makeUnique<AsyncRevalidation>(m_cache, frameID, request, WTFMove(entry), [this, key](bool ending) { >+ if (ending) { >+ m_pendingAsyncRevalidations.take(key); >+ LOG(NetworkCache, "(NetworkProcess) Async revalidation completed for '%s':", key.identifier().utf8().data()); >+ } >+ }); >+ m_pendingAsyncRevalidations.add(key, WTFMove(revalidator)); >+} >+ > static bool canRevalidate(const SubresourceInfo& subresourceInfo, const Entry* entry) > { > ASSERT(!subresourceInfo.isTransient()); >diff --git a/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h b/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h >index 3af4fdb8121fd7c5e918a039b400a5f3a3a86efa..f202fd666ec6705d7b6d48b3f48b4383a006a802 100644 >--- a/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h >+++ b/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h >@@ -38,6 +38,7 @@ namespace WebKit { > > namespace NetworkCache { > >+class AsyncRevalidation; > class Entry; > class SpeculativeLoad; > class SubresourceInfo; >@@ -56,6 +57,8 @@ public: > bool canRetrieve(const Key& storageKey, const WebCore::ResourceRequest&, const GlobalFrameID&) const; > void retrieve(const Key& storageKey, RetrieveCompletionHandler&&); > >+ void startAsyncRevalidationIfNeeded(const WebCore::ResourceRequest&, const NetworkCache::Key&, std::unique_ptr<Entry>, const GlobalFrameID&); >+ > private: > class PreloadedEntry; > >@@ -81,6 +84,8 @@ private: > > HashMap<Key, std::unique_ptr<PreloadedEntry>> m_preloadedEntries; > >+ HashMap<Key, std::unique_ptr<AsyncRevalidation>> m_pendingAsyncRevalidations; >+ > class ExpiringEntry; > HashMap<Key, std::unique_ptr<ExpiringEntry>> m_notPreloadedEntries; // For logging. > }; >diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog >index 4bef9fdc6982d69949ef4c888a58838485a5ccb6..71a76ae93d198ed764c69016f62b815e3f7af6c7 100644 >--- a/LayoutTests/imported/w3c/ChangeLog >+++ b/LayoutTests/imported/w3c/ChangeLog >@@ -1,3 +1,33 @@ >+2019-09-25 Rob Buis <rbuis@igalia.com> >+ >+ Support stale-while-revalidate cache strategy >+ https://bugs.webkit.org/show_bug.cgi?id=201461 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * resources/import-expectations.json: >+ * web-platform-tests/fetch/stale-while-revalidate/fetch-expected.txt: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https-expected.txt: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https.html: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/fetch.html: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/resources/stale-css.py: Added. >+ (main): >+ * web-platform-tests/fetch/stale-while-revalidate/resources/stale-image.py: Added. >+ (main): >+ * web-platform-tests/fetch/stale-while-revalidate/resources/stale-script.py: Added. >+ (id_token): >+ (main): >+ * web-platform-tests/fetch/stale-while-revalidate/resources/w3c-import.log: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/stale-css-expected.txt: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/stale-css.html: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/stale-image-expected.txt: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/stale-image.html: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/stale-script-expected.txt: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/stale-script.html: Added. >+ * web-platform-tests/fetch/stale-while-revalidate/sw-intercept.js: Added. >+ (async.broadcast): >+ * web-platform-tests/fetch/stale-while-revalidate/w3c-import.log: Added. >+ > 2019-09-20 Alex Christensen <achristensen@webkit.org> > > [resource-timing] Report performance entries with all HTTP status codes >diff --git a/LayoutTests/imported/w3c/resources/import-expectations.json b/LayoutTests/imported/w3c/resources/import-expectations.json >index 906d11aea9e31d3f7dae57a5d192d21f753b98c8..f7754b554b2cb0241181eee6cf0bf39bb9cae322 100644 >--- a/LayoutTests/imported/w3c/resources/import-expectations.json >+++ b/LayoutTests/imported/w3c/resources/import-expectations.json >@@ -158,6 +158,7 @@ > "web-platform-tests/fetch/api": "import", > "web-platform-tests/fetch/api/cors": "import", > "web-platform-tests/fetch/range": "import", >+ "web-platform-tests/fetch/stale-while-revalidate": "import", > "web-platform-tests/fullscreen": "skip", > "web-platform-tests/gamepad": "skip", > "web-platform-tests/generic-sensor": "skip", >@@ -368,4 +369,4 @@ > "web-platform-tests/worklets": "skip", > "web-platform-tests/x-frame-options": "skip", > "web-platform-tests/xhr": "import" >-} >+} >\ No newline at end of file >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..46bf26f4ab11c777adf248aa37ac0c7728237072 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Second fetch returns same response >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..46bf26f4ab11c777adf248aa37ac0c7728237072 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Second fetch returns same response >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https.html b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https.html >new file mode 100644 >index 0000000000000000000000000000000000000000..efcebc24a63f40de54a4c3991c9050eb74486a29 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https.html >@@ -0,0 +1,65 @@ >+<!DOCTYPE html> >+<html> >+<head> >+ <meta charset="utf-8"> >+ <title>Stale Revalidation Requests don't get sent to service worker</title> >+ <script src="/resources/testharness.js"></script> >+ <script src="/resources/testharnessreport.js"></script> >+ <script src="../../service-workers/service-worker/resources/test-helpers.sub.js"></script> >+ <script src="/common/utils.js"></script> >+</head> >+<body> >+<script> >+ >+ // Duplicating this resource to make service worker scoping simpler. >+ async function setupRegistrationAndWaitToBeControlled(t, scope) { >+ const controlled = new Promise((resolve) => { >+ navigator.serviceWorker.oncontrollerchange = () => { resolve(); }; >+ }); >+ const reg = await navigator.serviceWorker.register('sw-intercept.js'); >+ await wait_for_state(t, reg.installing, 'activated'); >+ await controlled; >+ add_completion_callback(_ => reg.unregister()); >+ return reg; >+ } >+ >+ // Using 250ms polling interval to provide enough 'network calmness' to give >+ // the background low priority revalidation request a chance to kick in. >+ function wait250ms(test) { >+ return new Promise(resolve => { >+ test.step_timeout(() => { >+ resolve(); >+ }, 250); >+ }); >+ } >+ >+ promise_test(async (test) => { >+ var request_token = token(); >+ const uri = 'resources/stale-script.py?token=' + request_token; >+ >+ await setupRegistrationAndWaitToBeControlled(test, 'resources/stale-script.py'); >+ >+ var service_worker_count = 0; >+ navigator.serviceWorker.addEventListener('message', function once(event) { >+ if (event.data.endsWith(uri)) { >+ service_worker_count++; >+ } >+ }); >+ >+ const response = await fetch(uri); >+ const response2 = await fetch(uri); >+ assert_equals(response.headers.get('Unique-Id'), response2.headers.get('Unique-Id')); >+ while(true) { >+ const revalidation_check = await fetch(`resources/stale-script.py?query&token=` + request_token); >+ if (revalidation_check.headers.get('Count') == '2') { >+ // The service worker should not see the revalidation request. >+ assert_equals(service_worker_count, 2); >+ break; >+ } >+ await wait250ms(test); >+ } >+ }, 'Second fetch returns same response'); >+ >+</script> >+</body> >+</html> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch.html b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch.html >new file mode 100644 >index 0000000000000000000000000000000000000000..73390c7ad5948c682b2fbdcb3c95a4c374dbba2d >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch.html >@@ -0,0 +1,32 @@ >+<!DOCTYPE html> >+<meta charset="utf-8"> >+<title>Tests Stale While Revalidate is not executed for fetch API</title> >+<script src="/resources/testharness.js"></script> >+<script src="/resources/testharnessreport.js"></script> >+<script src="/common/utils.js"></script> >+<script> >+function wait25ms(test) { >+ return new Promise(resolve => { >+ test.step_timeout(() => { >+ resolve(); >+ }, 25); >+ }); >+} >+ >+promise_test(async (test) => { >+ var request_token = token(); >+ >+ const response = await fetch(`resources/stale-script.py?token=` + request_token); >+ const response2 = await fetch(`resources/stale-script.py?token=` + request_token); >+ >+ assert_equals(response.headers.get('Unique-Id'), response2.headers.get('Unique-Id')); >+ >+ while(true) { >+ const revalidation_check = await fetch(`resources/stale-script.py?query&token=` + request_token); >+ if (revalidation_check.headers.get('Count') == '2') { >+ break; >+ } >+ await wait25ms(test); >+ } >+}, 'Second fetch returns same response'); >+</script> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-css.py b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-css.py >new file mode 100644 >index 0000000000000000000000000000000000000000..a6ae546d0651f97f3020829452db6225486dc451 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-css.py >@@ -0,0 +1,28 @@ >+def main(request, response): >+ >+ token = request.GET.first("token", None) >+ is_query = request.GET.first("query", None) != None >+ with request.server.stash.lock: >+ value = request.server.stash.take(token) >+ count = 0 >+ if value != None: >+ count = int(value) >+ if is_query: >+ if count < 2: >+ request.server.stash.put(token, count) >+ else: >+ count = count + 1 >+ request.server.stash.put(token, count) >+ if is_query: >+ headers = [("Count", count)] >+ content = "" >+ return 200, headers, content >+ else: >+ content = "body { background: rgb(0, 128, 0); }" >+ if count > 1: >+ content = "body { background: rgb(255, 0, 0); }" >+ >+ headers = [("Content-Type", "text/css"), >+ ("Cache-Control", "private, max-age=0, stale-while-revalidate=60")] >+ >+ return 200, headers, content >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-image.py b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-image.py >new file mode 100644 >index 0000000000000000000000000000000000000000..839eb84bb34bbd15e2ca7061ee4fa5724d2c64f8 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-image.py >@@ -0,0 +1,38 @@ >+import os.path >+ >+def main(request, response): >+ >+ token = request.GET.first("token", None) >+ is_query = request.GET.first("query", None) != None >+ with request.server.stash.lock: >+ value = request.server.stash.take(token) >+ count = 0 >+ if value != None: >+ count = int(value) >+ if is_query: >+ if count < 2: >+ request.server.stash.put(token, count) >+ else: >+ count = count + 1 >+ request.server.stash.put(token, count) >+ >+ if is_query: >+ headers = [("Count", count)] >+ content = "" >+ return 200, headers, content >+ else: >+ filename = "green-16x16.png" >+ if count > 1: >+ filename = "green-256x256.png" >+ >+ path = os.path.join(os.path.dirname(__file__), "../../../images", filename) >+ body = open(path, "rb").read() >+ >+ response.add_required_headers = False >+ response.writer.write_status(200) >+ response.writer.write_header("content-length", len(body)) >+ response.writer.write_header("Cache-Control", "private, max-age=0, stale-while-revalidate=60") >+ response.writer.write_header("content-type", "image/png") >+ response.writer.end_headers() >+ >+ response.writer.write(body) >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-script.py b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-script.py >new file mode 100644 >index 0000000000000000000000000000000000000000..8ad54671f4211735f56df50a55deea6ed281d5a2 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-script.py >@@ -0,0 +1,32 @@ >+import random, string, datetime >+ >+def id_token(): >+ letters = string.ascii_lowercase >+ return ''.join(random.choice(letters) for i in range(20)) >+ >+def main(request, response): >+ token = request.GET.first("token", None) >+ is_query = request.GET.first("query", None) != None >+ with request.server.stash.lock: >+ value = request.server.stash.take(token) >+ count = 0 >+ if value != None: >+ count = int(value) >+ if is_query: >+ if count < 2: >+ request.server.stash.put(token, count) >+ else: >+ count = count + 1 >+ request.server.stash.put(token, count) >+ >+ if is_query: >+ headers = [("Count", count)] >+ content = "" >+ return 200, headers, content >+ else: >+ unique_id = id_token() >+ headers = [("Content-Type", "text/javascript"), >+ ("Cache-Control", "private, max-age=0, stale-while-revalidate=60"), >+ ("Unique-Id", unique_id)] >+ content = "report('{}')".format(unique_id) >+ return 200, headers, content >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/w3c-import.log >new file mode 100644 >index 0000000000000000000000000000000000000000..75a7732a566d4a6f573cc97fd3d1454657d47680 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/w3c-import.log >@@ -0,0 +1,19 @@ >+The tests in this directory were imported from the W3C repository. >+Do NOT modify these tests directly in WebKit. >+Instead, create a pull request on the WPT github: >+ https://github.com/web-platform-tests/wpt >+ >+Then run the Tools/Scripts/import-w3c-tests in WebKit to reimport >+ >+Do NOT modify or remove this file. >+ >+------------------------------------------------------------------------ >+Properties requiring vendor prefixes: >+None >+Property values requiring vendor prefixes: >+None >+------------------------------------------------------------------------ >+List of files: >+/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-css.py >+/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-image.py >+/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/resources/stale-script.py >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-css-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-css-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..8ac99405a7b89c13e5787eaf079ed6f1488e8c10 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-css-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Cache returns stale resource >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-css.html b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-css.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f56260fdb45c0c2c60b4d76f63a76389df818b11 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-css.html >@@ -0,0 +1,45 @@ >+<!DOCTYPE html> >+<meta charset="utf-8"> >+<title>Tests Stale While Revalidate works for css</title> >+<script src="/resources/testharness.js"></script> >+<script src="/resources/testharnessreport.js"></script> >+<script src="/common/utils.js"></script> >+<body> >+<script> >+ >+var request_token = token(); >+async_test(t => { >+ window.onload = t.step_func(() => { >+ t.step_timeout(() => { >+ assert_equals(window.getComputedStyle(document.body).getPropertyValue('background-color'), "rgb(0, 128, 0)"); >+ var link2 = document.createElement("link"); >+ link2.onload = t.step_func(() => { >+ assert_equals(window.getComputedStyle(document.body).getPropertyValue('background-color'), "rgb(0, 128, 0)"); >+ var checkResult = () => { >+ // We poll because we don't know when the revalidation will occur. >+ fetch("resources/stale-css.py?query&token=" + request_token).then(t.step_func((response) => { >+ var count = response.headers.get("Count"); >+ if (count == '2') { >+ t.done(); >+ } else { >+ t.step_timeout(checkResult, 25); >+ } >+ })); >+ }; >+ t.step_timeout(checkResult, 25); >+ }); >+ link2.rel = "stylesheet"; >+ link2.type = "text/css"; >+ link2.href = "resources/stale-css.py?token=" + request_token; >+ document.body.appendChild(link2); >+ }, 0); >+ }); >+}, 'Cache returns stale resource'); >+ >+var link = document.createElement("link"); >+link.rel = "stylesheet"; >+link.type = "text/css"; >+link.href = "resources/stale-css.py?token=" + request_token; >+document.body.appendChild(link); >+</script> >+</body> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-image-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-image-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..1e42014defd7191096c33cce5830ef7caa1a57a6 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-image-expected.txt >@@ -0,0 +1,4 @@ >+ >+ >+PASS Cache returns stale resource >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-image.html b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-image.html >new file mode 100644 >index 0000000000000000000000000000000000000000..0a08f81729de49985c6575e1a7a5fcb77d3a0ee2 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-image.html >@@ -0,0 +1,49 @@ >+<!DOCTYPE html> >+<meta charset="utf-8"> >+<title>Tests Stale While Revalidate works for images</title> >+<script src="/resources/testharness.js"></script> >+<script src="/resources/testharnessreport.js"></script> >+<script src="/common/utils.js"></script> >+<body> >+<!-- >+Use a child document to load the second stale image into because >+an image loaded into the same document will skip cache-control headers. >+See: https://html.spec.whatwg.org/#the-list-of-available-images >+--> >+<iframe id="child" srcdoc=""></iframe> >+<script> >+ >+var request_token = token(); >+async_test(t => { >+ window.onload = t.step_func(() => { >+ t.step_timeout(() => { >+ assert_equals(document.getElementById("firstimage").width, 16, "Width is 16"); >+ var childDocument = document.getElementById('child').contentDocument; >+ var img2 = childDocument.createElement("img"); >+ img2.onload = t.step_func(() => { >+ assert_equals(img2.width, 16, "image dimension"); >+ var checkResult = () => { >+ // We poll because we don't know when the revalidation will occur. >+ fetch("resources/stale-image.py?query&token=" + request_token).then(t.step_func((response) => { >+ var count = response.headers.get("Count"); >+ if (count == '2') { >+ t.done(); >+ } else { >+ t.step_timeout(checkResult, 25); >+ } >+ })); >+ }; >+ t.step_timeout(checkResult, 25); >+ }); >+ img2.src = "resources/stale-image.py?token=" + request_token; >+ childDocument.body.appendChild(img2); >+ }, 0); >+ }); >+}, 'Cache returns stale resource'); >+ >+var img = document.createElement("img"); >+img.src = "resources/stale-image.py?token=" + request_token; >+img.id = "firstimage"; >+document.body.appendChild(img); >+</script> >+</body> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-script-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-script-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..8ac99405a7b89c13e5787eaf079ed6f1488e8c10 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-script-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Cache returns stale resource >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-script.html b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-script.html >new file mode 100644 >index 0000000000000000000000000000000000000000..68793e50056bc6053ea410d658aed373d19f9a41 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-script.html >@@ -0,0 +1,53 @@ >+<!DOCTYPE html> >+<meta charset="utf-8"> >+<title>Tests Stale While Revalidate works for scripts</title> >+<script src="/resources/testharness.js"></script> >+<script src="/resources/testharnessreport.js"></script> >+<script src="/common/utils.js"></script> >+<body> >+<script> >+var last_modified; >+var last_modified_count = 0; >+var request_token = token(); >+ >+// The script will call report via a uniquely generated ID on the subresource. >+// If it is a cache hit the ID will be the same and the test will pass. >+function report(mod) { >+ if (!last_modified) { >+ last_modified = mod; >+ last_modified_count = 1; >+ } else if (last_modified == mod) { >+ last_modified_count++; >+ } >+} >+ >+async_test(t => { >+ window.onload = t.step_func(() => { >+ step_timeout(() => { >+ var script = document.createElement("script"); >+ script.src = "resources/stale-script.py?token=" + request_token; >+ document.body.appendChild(script); >+ script.onload = t.step_func(() => { >+ assert_equals(last_modified_count, 2, "last modified"); >+ var checkResult = () => { >+ // We poll because we don't know when the revalidation will occur. >+ fetch("resources/stale-script.py?query&token=" + request_token).then(t.step_func((response) => { >+ var count = response.headers.get("Count"); >+ if (count == '2') { >+ t.done(); >+ } else { >+ t.step_timeout(checkResult, 25); >+ } >+ })); >+ }; >+ t.step_timeout(checkResult, 25); >+ }); >+ }, 0); >+ }); >+}, 'Cache returns stale resource'); >+ >+var script = document.createElement("script"); >+script.src = "resources/stale-script.py?token=" + request_token; >+document.body.appendChild(script); >+</script> >+</body> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/sw-intercept.js b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/sw-intercept.js >new file mode 100644 >index 0000000000000000000000000000000000000000..dca7de51b0b8c5518276e70ae219b7bc8f869a95 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/sw-intercept.js >@@ -0,0 +1,14 @@ >+async function broadcast(msg) { >+ for (const client of await clients.matchAll()) { >+ client.postMessage(msg); >+ } >+} >+ >+self.addEventListener('fetch', event => { >+ event.waitUntil(broadcast(event.request.url)); >+ event.respondWith(fetch(event.request)); >+}); >+ >+self.addEventListener('activate', event => { >+ self.clients.claim(); >+}); >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/w3c-import.log >new file mode 100644 >index 0000000000000000000000000000000000000000..ab9dd06f846a7068fea2b828781ad75cc198e7a3 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/w3c-import.log >@@ -0,0 +1,22 @@ >+The tests in this directory were imported from the W3C repository. >+Do NOT modify these tests directly in WebKit. >+Instead, create a pull request on the WPT github: >+ https://github.com/web-platform-tests/wpt >+ >+Then run the Tools/Scripts/import-w3c-tests in WebKit to reimport >+ >+Do NOT modify or remove this file. >+ >+------------------------------------------------------------------------ >+Properties requiring vendor prefixes: >+None >+Property values requiring vendor prefixes: >+None >+------------------------------------------------------------------------ >+List of files: >+/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https.html >+/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch.html >+/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-css.html >+/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-image.html >+/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-script.html >+/LayoutTests/imported/w3c/web-platform-tests/fetch/stale-while-revalidate/sw-intercept.js
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 201461
:
379546
|
379550
|
379563
|
380014
|
380309
|
380310
|
380325
|
380743
|
380744
|
380745
|
381807
|
381809
|
381813
|
381827
|
382942
|
383356
|
383373
|
383436