Changeset 252397 in webkit


Ignore:
Timestamp:
Nov 13, 2019 2:22:04 AM (4 years ago)
Author:
commit-queue@webkit.org
Message:

Support stale-while-revalidate cache strategy
https://bugs.webkit.org/show_bug.cgi?id=201461

Patch by Rob Buis <rbuis@igalia.com> on 2019-11-13
Reviewed by Youenn Fablet.

LayoutTests/imported/w3c:

Import stale-while-revalidate WPT tests.

  • 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.

Source/WebCore:

Start parsing the stale-while-revalidate Cache-Control directive
and expose it on ResourceResponse.

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:
  • platform/network/ResourceResponseBase.cpp:

(WebCore::ResourceResponseBase::cacheControlStaleWhileRevalidate const):

  • platform/network/ResourceResponseBase.h:

Source/WebKit:

Add a new UseDecision value AsyncRevalidate for async revalidation. This is used
when the retrieved cache entry is a stale-while-revalidate response [1].
In case of AsyncRevalidate, a check is made to see if there is a
current async revalidation ongoing for the entry, if not one is
started. Regardless, the stale entry is returned, until either the
async revalidation ends successfully or at the moment when the
response expires for real.

[1] https://fetch.spec.whatwg.org/#concept-stale-while-revalidate-response

  • NetworkProcess/NetworkSession.cpp:

(WebKit::NetworkSession::NetworkSession):

  • NetworkProcess/NetworkSession.h:

(WebKit::NetworkSession::isStaleWhileRevalidateEnabled const):

  • NetworkProcess/NetworkSessionCreationParameters.cpp:

(WebKit::NetworkSessionCreationParameters::encode const):
(WebKit::NetworkSessionCreationParameters::decode):

  • NetworkProcess/NetworkSessionCreationParameters.h:
  • NetworkProcess/cache/AsyncRevalidation.cpp: Added.

(WebKit::NetworkCache::constructRevalidationRequest):
(WebKit::NetworkCache::AsyncRevalidation::staleWhileRevalidateEnding):
(WebKit::NetworkCache::AsyncRevalidation::AsyncRevalidation):

  • NetworkProcess/cache/AsyncRevalidation.h: Added.

(WebKit::NetworkCache::AsyncRevalidation::load const):

  • NetworkProcess/cache/NetworkCache.cpp:

(WebKit::NetworkCache::responseNeedsRevalidation):
(WebKit::NetworkCache::makeUseDecision):
(WebKit::NetworkCache::makeStoreDecision):
(WebKit::NetworkCache::Cache::startAsyncRevalidationIfNeeded):
(WebKit::NetworkCache::Cache::retrieve):
(WebKit::NetworkCache::responseHasExpired): Deleted.

  • NetworkProcess/cache/NetworkCache.h:
  • NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp:

(WebKit::NetworkCache::dumpHTTPHeadersDiff):
(WebKit::NetworkCache::requestsHeadersMatch):

  • NetworkProcess/cache/NetworkCacheSpeculativeLoad.h:
  • NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp:

(WebKit::NetworkCache::dumpHTTPHeadersDiff): Deleted.
(WebKit::NetworkCache::requestsHeadersMatch): Deleted.

  • Sources.txt:
  • UIProcess/API/C/WKWebsiteDataStoreConfigurationRef.cpp:

(WKWebsiteDataStoreConfigurationGetStaleWhileRevalidateEnabled):
(WKWebsiteDataStoreConfigurationSetStaleWhileRevalidateEnabled):

  • UIProcess/API/C/WKWebsiteDataStoreConfigurationRef.h:
  • UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm:

(WebKit::WebsiteDataStore::parameters):

  • UIProcess/WebsiteData/WebsiteDataStoreConfiguration.cpp:

(WebKit::WebsiteDataStoreConfiguration::copy const):

  • UIProcess/WebsiteData/WebsiteDataStoreConfiguration.h:

(WebKit::WebsiteDataStoreConfiguration::staleWhileRevalidateEnabled const):
(WebKit::WebsiteDataStoreConfiguration::setStaleWhileRevalidateEnabled):

  • WebKit.xcodeproj/project.pbxproj:

Tools:

Enable stale-while-revalidate for the test runner.

  • WebKitTestRunner/TestController.cpp:

(WTR::TestController::websiteDataStore):

LayoutTests:

Skip newly imported tests for WK1.

  • platform/ios-wk1/TestExpectations:
  • platform/mac-wk1/TestExpectations:
Location:
trunk
Files:
20 added
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r252391 r252397  
     12019-11-13  Rob Buis  <rbuis@igalia.com>
     2
     3        Support stale-while-revalidate cache strategy
     4        https://bugs.webkit.org/show_bug.cgi?id=201461
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Skip newly imported tests for WK1.
     9
     10        * platform/ios-wk1/TestExpectations:
     11        * platform/mac-wk1/TestExpectations:
     12
    1132019-11-12  Fujii Hironori  <Hironori.Fujii@sony.com>
    214
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r252366 r252397  
     12019-11-13  Rob Buis  <rbuis@igalia.com>
     2
     3        Support stale-while-revalidate cache strategy
     4        https://bugs.webkit.org/show_bug.cgi?id=201461
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Import stale-while-revalidate WPT tests.
     9
     10        * resources/import-expectations.json:
     11        * web-platform-tests/fetch/stale-while-revalidate/fetch-expected.txt: Added.
     12        * web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https-expected.txt: Added.
     13        * web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https.html: Added.
     14        * web-platform-tests/fetch/stale-while-revalidate/fetch.html: Added.
     15        * web-platform-tests/fetch/stale-while-revalidate/resources/stale-css.py: Added.
     16        (main):
     17        * web-platform-tests/fetch/stale-while-revalidate/resources/stale-image.py: Added.
     18        (main):
     19        * web-platform-tests/fetch/stale-while-revalidate/resources/stale-script.py: Added.
     20        (id_token):
     21        (main):
     22        * web-platform-tests/fetch/stale-while-revalidate/resources/w3c-import.log: Added.
     23        * web-platform-tests/fetch/stale-while-revalidate/stale-css-expected.txt: Added.
     24        * web-platform-tests/fetch/stale-while-revalidate/stale-css.html: Added.
     25        * web-platform-tests/fetch/stale-while-revalidate/stale-image-expected.txt: Added.
     26        * web-platform-tests/fetch/stale-while-revalidate/stale-image.html: Added.
     27        * web-platform-tests/fetch/stale-while-revalidate/stale-script-expected.txt: Added.
     28        * web-platform-tests/fetch/stale-while-revalidate/stale-script.html: Added.
     29        * web-platform-tests/fetch/stale-while-revalidate/sw-intercept.js: Added.
     30        (async.broadcast):
     31        * web-platform-tests/fetch/stale-while-revalidate/w3c-import.log: Added.
     32
    1332019-11-12  Carlos Alberto Lopez Perez  <clopez@igalia.com>
    234
  • trunk/LayoutTests/imported/w3c/resources/import-expectations.json

    r252335 r252397  
    177177    "web-platform-tests/fetch/api/cors": "import",
    178178    "web-platform-tests/fetch/range": "import",
     179    "web-platform-tests/fetch/stale-while-revalidate": "import",
    179180    "web-platform-tests/fullscreen": "skip",
    180181    "web-platform-tests/gamepad": "skip",
  • trunk/LayoutTests/platform/ios-wk1/TestExpectations

    r251279 r252397  
    20072007# Skip IsLoggedIn
    20082008http/tests/is-logged-in/ [ Skip ]
     2009
     2010# Stale-while-revalidate is not supported on WK1
     2011imported/w3c/web-platform-tests/fetch/stale-while-revalidate [ Skip ]
  • trunk/LayoutTests/platform/mac-wk1/TestExpectations

    r252353 r252397  
    823823
    824824webkit.org/b/203517 imported/w3c/web-platform-tests/css/css-sizing/dynamic-available-size-iframe.html [ Pass ImageOnlyFailure ]
     825
     826# Stale-while-revalidate is not supported on WK1
     827imported/w3c/web-platform-tests/fetch/stale-while-revalidate [ Skip ]
  • trunk/Source/WebCore/ChangeLog

    r252393 r252397  
     12019-11-13  Rob Buis  <rbuis@igalia.com>
     2
     3        Support stale-while-revalidate cache strategy
     4        https://bugs.webkit.org/show_bug.cgi?id=201461
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Start parsing the stale-while-revalidate Cache-Control directive
     9        and expose it on ResourceResponse.
     10
     11        Tests: imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch-sw.https.html
     12               imported/w3c/web-platform-tests/fetch/stale-while-revalidate/fetch.html
     13               imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-css.html
     14               imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-image.html
     15               imported/w3c/web-platform-tests/fetch/stale-while-revalidate/stale-script.html
     16
     17        * platform/network/CacheValidation.cpp:
     18        (WebCore::parseCacheControlDirectives):
     19        * platform/network/CacheValidation.h:
     20        * platform/network/ResourceResponseBase.cpp:
     21        (WebCore::ResourceResponseBase::cacheControlStaleWhileRevalidate const):
     22        * platform/network/ResourceResponseBase.h:
     23
    1242019-11-12  Simon Fraser  <simon.fraser@apple.com>
    225
  • trunk/Source/WebCore/platform/network/CacheValidation.cpp

    r250153 r252397  
    314314                if (ok)
    315315                    result.maxStale = Seconds { maxStale };
    316             } else if (equalLettersIgnoringASCIICase(directives[i].first, "immutable"))
     316            } else if (equalLettersIgnoringASCIICase(directives[i].first, "immutable")) {
    317317                result.immutable = true;
     318            } else if (equalLettersIgnoringASCIICase(directives[i].first, "stale-while-revalidate")) {
     319                if (result.staleWhileRevalidate) {
     320                    // First stale-while-revalidate directive wins if there are multiple ones.
     321                    continue;
     322                }
     323                bool ok;
     324                double staleWhileRevalidate = directives[i].second.toDouble(&ok);
     325                if (ok)
     326                    result.staleWhileRevalidate = Seconds { staleWhileRevalidate };
     327            }
    318328        }
    319329    }
  • trunk/Source/WebCore/platform/network/CacheValidation.h

    r250287 r252397  
    7070    Markable<Seconds, Seconds::MarkableTraits> maxAge;
    7171    Markable<Seconds, Seconds::MarkableTraits> maxStale;
     72    Markable<Seconds, Seconds::MarkableTraits> staleWhileRevalidate;
    7273    bool noCache : 1;
    7374    bool noStore : 1;
  • trunk/Source/WebCore/platform/network/ResourceResponseBase.cpp

    r252047 r252397  
    658658}
    659659
     660Optional<Seconds> ResourceResponseBase::cacheControlStaleWhileRevalidate() const
     661{
     662    if (!m_haveParsedCacheControlHeader)
     663        parseCacheControlDirectives();
     664    return m_cacheControlDirectives.staleWhileRevalidate;
     665}
     666
    660667static Optional<WallTime> parseDateValueInHeader(const HTTPHeaderMap& headers, HTTPHeaderName headerName)
    661668{
  • trunk/Source/WebCore/platform/network/ResourceResponseBase.h

    r252047 r252397  
    138138    WEBCORE_EXPORT bool hasCacheValidatorFields() const;
    139139    WEBCORE_EXPORT Optional<Seconds> cacheControlMaxAge() const;
     140    WEBCORE_EXPORT Optional<Seconds> cacheControlStaleWhileRevalidate() const;
    140141    WEBCORE_EXPORT Optional<WallTime> date() const;
    141142    WEBCORE_EXPORT Optional<Seconds> age() const;
  • trunk/Source/WebKit/ChangeLog

    r252392 r252397  
     12019-11-13  Rob Buis  <rbuis@igalia.com>
     2
     3        Support stale-while-revalidate cache strategy
     4        https://bugs.webkit.org/show_bug.cgi?id=201461
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Add a new UseDecision value AsyncRevalidate for async revalidation. This is used
     9        when the retrieved cache entry is a stale-while-revalidate response [1].
     10        In case of AsyncRevalidate, a check is made to see if there is a
     11        current async revalidation ongoing for the entry, if not one is
     12        started. Regardless, the stale entry is returned, until either the
     13        async revalidation ends successfully or at the moment when the
     14        response expires for real.
     15
     16        [1] https://fetch.spec.whatwg.org/#concept-stale-while-revalidate-response
     17
     18        * NetworkProcess/NetworkSession.cpp:
     19        (WebKit::NetworkSession::NetworkSession):
     20        * NetworkProcess/NetworkSession.h:
     21        (WebKit::NetworkSession::isStaleWhileRevalidateEnabled const):
     22        * NetworkProcess/NetworkSessionCreationParameters.cpp:
     23        (WebKit::NetworkSessionCreationParameters::encode const):
     24        (WebKit::NetworkSessionCreationParameters::decode):
     25        * NetworkProcess/NetworkSessionCreationParameters.h:
     26        * NetworkProcess/cache/AsyncRevalidation.cpp: Added.
     27        (WebKit::NetworkCache::constructRevalidationRequest):
     28        (WebKit::NetworkCache::AsyncRevalidation::staleWhileRevalidateEnding):
     29        (WebKit::NetworkCache::AsyncRevalidation::AsyncRevalidation):
     30        * NetworkProcess/cache/AsyncRevalidation.h: Added.
     31        (WebKit::NetworkCache::AsyncRevalidation::load const):
     32        * NetworkProcess/cache/NetworkCache.cpp:
     33        (WebKit::NetworkCache::responseNeedsRevalidation):
     34        (WebKit::NetworkCache::makeUseDecision):
     35        (WebKit::NetworkCache::makeStoreDecision):
     36        (WebKit::NetworkCache::Cache::startAsyncRevalidationIfNeeded):
     37        (WebKit::NetworkCache::Cache::retrieve):
     38        (WebKit::NetworkCache::responseHasExpired): Deleted.
     39        * NetworkProcess/cache/NetworkCache.h:
     40        * NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp:
     41        (WebKit::NetworkCache::dumpHTTPHeadersDiff):
     42        (WebKit::NetworkCache::requestsHeadersMatch):
     43        * NetworkProcess/cache/NetworkCacheSpeculativeLoad.h:
     44        * NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp:
     45        (WebKit::NetworkCache::dumpHTTPHeadersDiff): Deleted.
     46        (WebKit::NetworkCache::requestsHeadersMatch): Deleted.
     47        * Sources.txt:
     48        * UIProcess/API/C/WKWebsiteDataStoreConfigurationRef.cpp:
     49        (WKWebsiteDataStoreConfigurationGetStaleWhileRevalidateEnabled):
     50        (WKWebsiteDataStoreConfigurationSetStaleWhileRevalidateEnabled):
     51        * UIProcess/API/C/WKWebsiteDataStoreConfigurationRef.h:
     52        * UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm:
     53        (WebKit::WebsiteDataStore::parameters):
     54        * UIProcess/WebsiteData/WebsiteDataStoreConfiguration.cpp:
     55        (WebKit::WebsiteDataStoreConfiguration::copy const):
     56        * UIProcess/WebsiteData/WebsiteDataStoreConfiguration.h:
     57        (WebKit::WebsiteDataStoreConfiguration::staleWhileRevalidateEnabled const):
     58        (WebKit::WebsiteDataStoreConfiguration::setStaleWhileRevalidateEnabled):
     59        * WebKit.xcodeproj/project.pbxproj:
     60
    1612019-11-12  Simon Fraser  <simon.fraser@apple.com>
    262
  • trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp

    r251672 r252397  
    109109    }
    110110
     111    m_isStaleWhileRevalidateEnabled = parameters.staleWhileRevalidateEnabled;
     112
    111113    m_adClickAttribution->setPingLoadFunction([this, weakThis = makeWeakPtr(this)](NetworkResourceLoadParameters&& loadParameters, CompletionHandler<void(const WebCore::ResourceError&, const WebCore::ResourceResponse&)>&& completionHandler) {
    112114        if (!weakThis)
  • trunk/Source/WebKit/NetworkProcess/NetworkSession.h

    r251672 r252397  
    125125    unsigned testSpeedMultiplier() const { return m_testSpeedMultiplier; }
    126126
     127    bool isStaleWhileRevalidateEnabled() const { return m_isStaleWhileRevalidateEnabled; }
     128
    127129protected:
    128130    NetworkSession(NetworkProcess&, const NetworkSessionCreationParameters&);
     
    145147    bool m_thirdPartyCookieBlockingEnabled { false };
    146148#endif
     149    bool m_isStaleWhileRevalidateEnabled { false };
    147150    UniqueRef<AdClickAttributionManager> m_adClickAttribution;
    148151
  • trunk/Source/WebKit/NetworkProcess/NetworkSessionCreationParameters.cpp

    r251467 r252397  
    7979    encoder << networkCacheSpeculativeValidationEnabled;
    8080    encoder << shouldUseTestingNetworkSession;
     81    encoder << staleWhileRevalidateEnabled;
    8182    encoder << testSpeedMultiplier;
    8283    encoder << suppressesConnectionTerminationOnSystemChange;
     
    244245    if (!shouldUseTestingNetworkSession)
    245246        return WTF::nullopt;
    246    
     247
     248    Optional<bool> staleWhileRevalidateEnabled;
     249    decoder >> staleWhileRevalidateEnabled;
     250    if (!staleWhileRevalidateEnabled)
     251        return WTF::nullopt;
     252
    247253    Optional<unsigned> testSpeedMultiplier;
    248254    decoder >> testSpeedMultiplier;
     
    293299        , WTFMove(*networkCacheSpeculativeValidationEnabled)
    294300        , WTFMove(*shouldUseTestingNetworkSession)
     301        , WTFMove(*staleWhileRevalidateEnabled)
    295302        , WTFMove(*testSpeedMultiplier)
    296303        , WTFMove(*suppressesConnectionTerminationOnSystemChange)
  • trunk/Source/WebKit/NetworkProcess/NetworkSessionCreationParameters.h

    r251467 r252397  
    9797    bool networkCacheSpeculativeValidationEnabled { false };
    9898    bool shouldUseTestingNetworkSession { false };
     99    bool staleWhileRevalidateEnabled { false };
    99100    unsigned testSpeedMultiplier { 1 };
    100101    bool suppressesConnectionTerminationOnSystemChange { false };
  • trunk/Source/WebKit/NetworkProcess/cache/NetworkCache.cpp

    r250143 r252397  
    2727#include "NetworkCache.h"
    2828
     29#include "AsyncRevalidation.h"
    2930#include "Logging.h"
     31#include "NetworkCacheSpeculativeLoad.h"
    3032#include "NetworkCacheSpeculativeLoadManager.h"
    3133#include "NetworkCacheStorage.h"
    3234#include "NetworkProcess.h"
     35#include "NetworkSession.h"
    3336#include <WebCore/CacheValidation.h>
    3437#include <WebCore/HTTPHeaderNames.h>
     
    153156}
    154157
    155 static bool responseHasExpired(const WebCore::ResourceResponse& response, WallTime timestamp, Optional<Seconds> maxStale)
     158static UseDecision responseNeedsRevalidation(NetworkSession& networkSession, const WebCore::ResourceResponse& response, WallTime timestamp, Optional<Seconds> maxStale)
    156159{
    157160    if (response.cacheControlContainsNoCache())
    158         return true;
     161        return UseDecision::Validate;
    159162
    160163    auto age = WebCore::computeCurrentAge(response, timestamp);
     
    163166    auto maximumStaleness = maxStale ? maxStale.value() : 0_ms;
    164167    bool hasExpired = age - lifetime > maximumStaleness;
    165 
     168#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
     169    if (hasExpired && !maxStale && networkSession.isStaleWhileRevalidateEnabled()) {
     170        auto responseMaxStaleness = response.cacheControlStaleWhileRevalidate();
     171        maximumStaleness += responseMaxStaleness ? responseMaxStaleness.value() : 0_ms;
     172        bool inResponseStaleness = age - lifetime < maximumStaleness;
     173        if (inResponseStaleness)
     174            return UseDecision::AsyncRevalidate;
     175    }
     176#endif
     177
     178    if (hasExpired) {
    166179#ifndef LOG_DISABLED
    167     if (hasExpired)
    168         LOG(NetworkCache, "(NetworkProcess) needsRevalidation hasExpired age=%f lifetime=%f max-stale=%g", age, lifetime, maxStale);
    169 #endif
    170 
    171     return hasExpired;
    172 }
    173 
    174 static bool responseNeedsRevalidation(const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& request, WallTime timestamp)
     180        LOG(NetworkCache, "(NetworkProcess) needsRevalidation hasExpired age=%f lifetime=%f max-staleness=%f", age, lifetime, maximumStaleness);
     181#endif
     182        return UseDecision::Validate;
     183    }
     184
     185    return UseDecision::Use;
     186}
     187
     188static UseDecision responseNeedsRevalidation(NetworkSession& networkSession, const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& request, WallTime timestamp)
    175189{
    176190    auto requestDirectives = WebCore::parseCacheControlDirectives(request.httpHeaderFields());
    177191    if (requestDirectives.noCache)
    178         return true;
     192        return UseDecision::Validate;
    179193    // For requests we ignore max-age values other than zero.
    180194    if (requestDirectives.maxAge && requestDirectives.maxAge.value() == 0_ms)
    181         return true;
    182 
    183     return responseHasExpired(response, timestamp, requestDirectives.maxStale);
     195        return UseDecision::Validate;
     196
     197    return responseNeedsRevalidation(networkSession, response, timestamp, requestDirectives.maxStale);
    184198}
    185199
     
    198212        return UseDecision::Use;
    199213
    200     if (!responseNeedsRevalidation(entry.response(), request, entry.timeStamp()))
    201         return UseDecision::Use;
     214    auto decision = responseNeedsRevalidation(*networkProcess.networkSession(sessionID), entry.response(), request, entry.timeStamp());
     215    if (decision != UseDecision::Validate)
     216        return decision;
    202217
    203218    if (!entry.response().hasCacheValidatorFields())
     
    252267    if (!storeUnconditionallyForHistoryNavigation) {
    253268        auto now = WallTime::now();
    254         bool hasNonZeroLifetime = !response.cacheControlContainsNoCache() && WebCore::computeFreshnessLifetimeForHTTPFamily(response, now) > 0_ms;
    255 
     269        Seconds allowedStale { 0_ms };
     270#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
     271        if (auto value = response.cacheControlStaleWhileRevalidate())
     272            allowedStale = value.value();
     273#endif
     274        bool hasNonZeroLifetime = !response.cacheControlContainsNoCache() && (WebCore::computeFreshnessLifetimeForHTTPFamily(response, now) > 0_ms || allowedStale > 0_ms);
    256275        bool possiblyReusable = response.hasCacheValidatorFields() || hasNonZeroLifetime;
    257276        if (!possiblyReusable)
     
    297316#endif
    298317
     318#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
     319void Cache::startAsyncRevalidationIfNeeded(const WebCore::ResourceRequest& request, const NetworkCache::Key& key, std::unique_ptr<Entry>&& entry, const GlobalFrameID& frameID)
     320{
     321    m_pendingAsyncRevalidations.ensure(key, [&] {
     322        return makeUnique<AsyncRevalidation>(*this, frameID, request, WTFMove(entry), [this, key](AsyncRevalidation::Result result) {
     323            m_pendingAsyncRevalidations.remove(key);
     324            LOG(NetworkCache, "(NetworkProcess) Async revalidation completed for '%s' with result %d", key.identifier().utf8().data(), static_cast<int>(result));
     325        });
     326    });
     327}
     328#endif
     329
    299330void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameID& frameID, RetrieveCompletionHandler&& completionHandler)
    300331{
     
    335366#endif
    336367
    337     m_storage->retrieve(storageKey, priority, [request, completionHandler = WTFMove(completionHandler), info = WTFMove(info), storageKey, networkProcess = makeRef(networkProcess()), sessionID = m_sessionID](auto record, auto timings) mutable {
     368    m_storage->retrieve(storageKey, priority, [this, protectedThis = makeRef(*this), request, completionHandler = WTFMove(completionHandler), info = WTFMove(info), storageKey, networkProcess = makeRef(networkProcess()), sessionID = m_sessionID, frameID](auto record, auto timings) mutable {
    338369        info.storageTimings = timings;
    339370
    340371        if (!record) {
    341372            LOG(NetworkCache, "(NetworkProcess) not found in storage");
    342 
    343373            completeRetrieve(WTFMove(completionHandler), nullptr, info);
    344374            return false;
     
    351381        auto useDecision = entry ? makeUseDecision(networkProcess, sessionID, *entry, request) : UseDecision::NoDueToDecodeFailure;
    352382        switch (useDecision) {
     383        case UseDecision::AsyncRevalidate: {
     384#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
     385            auto entryCopy = makeUnique<Entry>(*entry);
     386            entryCopy->setNeedsValidation(true);
     387            startAsyncRevalidationIfNeeded(request, storageKey, WTFMove(entryCopy), frameID);
     388#endif
     389            FALLTHROUGH;
     390        }
    353391        case UseDecision::Use:
    354392            break;
  • trunk/Source/WebKit/NetworkProcess/cache/NetworkCache.h

    r250287 r252397  
    5151namespace NetworkCache {
    5252
     53class AsyncRevalidation;
    5354class Cache;
    5455class SpeculativeLoadManager;
     
    8384    Use,
    8485    Validate,
     86    AsyncRevalidate,
    8587    NoDueToVaryingHeaderMismatch,
    8688    NoDueToMissingValidatorFields,
     
    168170#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
    169171    SpeculativeLoadManager* speculativeLoadManager() { return m_speculativeLoadManager.get(); }
     172
     173    void startAsyncRevalidationIfNeeded(const WebCore::ResourceRequest&, const NetworkCache::Key&, std::unique_ptr<Entry>&&, const GlobalFrameID&);
    170174#endif
    171175
     
    194198    std::unique_ptr<WebCore::LowPowerModeNotifier> m_lowPowerModeNotifier;
    195199    std::unique_ptr<SpeculativeLoadManager> m_speculativeLoadManager;
     200
     201    HashMap<Key, std::unique_ptr<AsyncRevalidation>> m_pendingAsyncRevalidations;
    196202#endif
    197203
  • trunk/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp

    r250053 r252397  
    156156}
    157157
     158#if !LOG_DISABLED
     159
     160static void dumpHTTPHeadersDiff(const HTTPHeaderMap& headersA, const HTTPHeaderMap& headersB)
     161{
     162    auto aEnd = headersA.end();
     163    for (auto it = headersA.begin(); it != aEnd; ++it) {
     164        String valueB = headersB.get(it->key);
     165        if (valueB.isNull())
     166            LOG(NetworkCacheSpeculativePreloading, "* '%s' HTTP header is only in first request (value: %s)", it->key.utf8().data(), it->value.utf8().data());
     167        else if (it->value != valueB)
     168            LOG(NetworkCacheSpeculativePreloading, "* '%s' HTTP header differs in both requests: %s != %s", it->key.utf8().data(), it->value.utf8().data(), valueB.utf8().data());
     169    }
     170    auto bEnd = headersB.end();
     171    for (auto it = headersB.begin(); it != bEnd; ++it) {
     172        if (!headersA.contains(it->key))
     173            LOG(NetworkCacheSpeculativePreloading, "* '%s' HTTP header is only in second request (value: %s)", it->key.utf8().data(), it->value.utf8().data());
     174    }
     175}
     176
     177#endif
     178
     179bool requestsHeadersMatch(const ResourceRequest& speculativeValidationRequest, const ResourceRequest& actualRequest)
     180{
     181    ASSERT(!actualRequest.isConditional());
     182    ResourceRequest speculativeRequest = speculativeValidationRequest;
     183    speculativeRequest.makeUnconditional();
     184
     185    if (speculativeRequest.httpHeaderFields() != actualRequest.httpHeaderFields()) {
     186        LOG(NetworkCacheSpeculativePreloading, "Cannot reuse speculatively validated entry because HTTP headers used for validation do not match");
     187#if !LOG_DISABLED
     188        dumpHTTPHeadersDiff(speculativeRequest.httpHeaderFields(), actualRequest.httpHeaderFields());
     189#endif
     190        return false;
     191    }
     192    return true;
     193}
     194
    158195} // namespace NetworkCache
    159196} // namespace WebKit
  • trunk/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h

    r250974 r252397  
    7979};
    8080
     81bool requestsHeadersMatch(const WebCore::ResourceRequest& speculativeValidationRequest, const WebCore::ResourceRequest& actualRequest);
     82
    8183} // namespace NetworkCache
    8284} // namespace WebKit
  • trunk/Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp

    r249501 r252397  
    257257}
    258258
    259 #if !LOG_DISABLED
    260 
    261 static void dumpHTTPHeadersDiff(const HTTPHeaderMap& headersA, const HTTPHeaderMap& headersB)
    262 {
    263     auto aEnd = headersA.end();
    264     for (auto it = headersA.begin(); it != aEnd; ++it) {
    265         String valueB = headersB.get(it->key);
    266         if (valueB.isNull())
    267             LOG(NetworkCacheSpeculativePreloading, "* '%s' HTTP header is only in first request (value: %s)", it->key.utf8().data(), it->value.utf8().data());
    268         else if (it->value != valueB)
    269             LOG(NetworkCacheSpeculativePreloading, "* '%s' HTTP header differs in both requests: %s != %s", it->key.utf8().data(), it->value.utf8().data(), valueB.utf8().data());
    270     }
    271     auto bEnd = headersB.end();
    272     for (auto it = headersB.begin(); it != bEnd; ++it) {
    273         if (!headersA.contains(it->key))
    274             LOG(NetworkCacheSpeculativePreloading, "* '%s' HTTP header is only in second request (value: %s)", it->key.utf8().data(), it->value.utf8().data());
    275     }
    276 }
    277 
    278 #endif
    279 
    280 static bool requestsHeadersMatch(const ResourceRequest& speculativeValidationRequest, const ResourceRequest& actualRequest)
    281 {
    282     ASSERT(!actualRequest.isConditional());
    283     ResourceRequest speculativeRequest = speculativeValidationRequest;
    284     speculativeRequest.makeUnconditional();
    285 
    286     if (speculativeRequest.httpHeaderFields() != actualRequest.httpHeaderFields()) {
    287         LOG(NetworkCacheSpeculativePreloading, "Cannot reuse speculatively validated entry because HTTP headers used for validation do not match");
    288 #if !LOG_DISABLED
    289         dumpHTTPHeadersDiff(speculativeRequest.httpHeaderFields(), actualRequest.httpHeaderFields());
    290 #endif
    291         return false;
    292     }
    293     return true;
    294 }
    295 
    296259bool SpeculativeLoadManager::canUsePreloadedEntry(const PreloadedEntry& entry, const ResourceRequest& actualRequest)
    297260{
  • trunk/Source/WebKit/Sources.txt

    r251814 r252397  
    7979NetworkProcess/cache/CacheStorageEngineCaches.cpp
    8080NetworkProcess/cache/CacheStorageEngineConnection.cpp
     81NetworkProcess/cache/AsyncRevalidation.cpp
    8182NetworkProcess/cache/NetworkCache.cpp
    8283NetworkProcess/cache/NetworkCacheBlobStorage.cpp
  • trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreConfigurationRef.cpp

    r250463 r252397  
    140140    WebKit::toImpl(configuration)->setTestingSessionEnabled(enabled);
    141141}
     142
     143bool WKWebsiteDataStoreConfigurationGetStaleWhileRevalidateEnabled(WKWebsiteDataStoreConfigurationRef configuration)
     144{
     145    return WebKit::toImpl(configuration)->staleWhileRevalidateEnabled();
     146}
     147
     148void WKWebsiteDataStoreConfigurationSetStaleWhileRevalidateEnabled(WKWebsiteDataStoreConfigurationRef configuration, bool enabled)
     149{
     150    WebKit::toImpl(configuration)->setStaleWhileRevalidateEnabled(enabled);
     151}
  • trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreConfigurationRef.h

    r250458 r252397  
    6767WK_EXPORT void WKWebsiteDataStoreConfigurationSetTestingSessionEnabled(WKWebsiteDataStoreConfigurationRef configuration, bool enabled);
    6868
     69WK_EXPORT bool WKWebsiteDataStoreConfigurationGetStaleWhileRevalidateEnabled(WKWebsiteDataStoreConfigurationRef configuration);
     70WK_EXPORT void WKWebsiteDataStoreConfigurationSetStaleWhileRevalidateEnabled(WKWebsiteDataStoreConfigurationRef configuration, bool enabled);
     71
    6972#ifdef __cplusplus
    7073}
  • trunk/Source/WebKit/UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm

    r251467 r252397  
    151151        m_configuration->networkCacheSpeculativeValidationEnabled(),
    152152        m_configuration->testingSessionEnabled(),
     153        m_configuration->staleWhileRevalidateEnabled(),
    153154        m_configuration->testSpeedMultiplier(),
    154155        m_configuration->suppressesConnectionTerminationOnSystemChange(),
  • trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.cpp

    r252354 r252397  
    5757    copy->m_fastServerTrustEvaluationEnabled = this->m_fastServerTrustEvaluationEnabled;
    5858    copy->m_networkCacheSpeculativeValidationEnabled = this->m_networkCacheSpeculativeValidationEnabled;
     59    copy->m_staleWhileRevalidateEnabled = this->m_staleWhileRevalidateEnabled;
    5960    copy->m_cacheStorageDirectory = this->m_cacheStorageDirectory;
    6061    copy->m_perOriginStorageQuota = this->m_perOriginStorageQuota;
  • trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.h

    r252354 r252397  
    8585    bool testingSessionEnabled() const { return m_testingSessionEnabled; }
    8686    void setTestingSessionEnabled(bool enabled) { m_testingSessionEnabled = enabled; }
    87    
     87
     88    bool staleWhileRevalidateEnabled() const { return m_staleWhileRevalidateEnabled; }
     89    void setStaleWhileRevalidateEnabled(bool enabled) { m_staleWhileRevalidateEnabled = enabled; }
     90
    8891    unsigned testSpeedMultiplier() const { return m_testSpeedMultiplier; }
    8992    void setTestSpeedMultiplier(unsigned multiplier) { m_testSpeedMultiplier = multiplier; }
    90    
     93
    9194#if PLATFORM(COCOA)
    9295    CFDictionaryRef proxyConfiguration() const { return m_proxyConfiguration.get(); }
     
    160163    bool m_networkCacheSpeculativeValidationEnabled { false };
    161164#endif
     165    bool m_staleWhileRevalidateEnabled { false };
    162166    String m_localStorageDirectory;
    163167    String m_mediaKeysStorageDirectory;
  • trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj

    r252303 r252397  
    13961396                A7D792D81767CCA300881CBE /* ActivityAssertion.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D792D41767CB0900881CBE /* ActivityAssertion.h */; };
    13971397                AAB145E6223F931200E489D8 /* PrefetchCache.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB145E4223F931200E489D8 /* PrefetchCache.h */; };
     1398                AAFA634F234F7C6400FFA864 /* AsyncRevalidation.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFA634E234F7C6300FFA864 /* AsyncRevalidation.h */; };
    13981399                B62E7312143047B00069EC35 /* WKHitTestResult.h in Headers */ = {isa = PBXBuildFile; fileRef = B62E7311143047B00069EC35 /* WKHitTestResult.h */; settings = {ATTRIBUTES = (Private, ); }; };
    13991400                B878B615133428DC006888E9 /* CorrectionPanel.h in Headers */ = {isa = PBXBuildFile; fileRef = B878B613133428DC006888E9 /* CorrectionPanel.h */; };
     
    41824183                AAB145E4223F931200E489D8 /* PrefetchCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrefetchCache.h; sourceTree = "<group>"; };
    41834184                AAB145E5223F931200E489D8 /* PrefetchCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrefetchCache.cpp; sourceTree = "<group>"; };
     4185                AAFA634E234F7C6300FFA864 /* AsyncRevalidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncRevalidation.h; sourceTree = "<group>"; };
     4186                AAFA6350234F7C7300FFA864 /* AsyncRevalidation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncRevalidation.cpp; sourceTree = "<group>"; };
    41844187                B396EA5512E0ED2D00F4FEB7 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
    41854188                B62E730F143047A60069EC35 /* WKHitTestResult.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKHitTestResult.cpp; sourceTree = "<group>"; };
     
    92189221                        isa = PBXGroup;
    92199222                        children = (
     9223                                AAFA6350234F7C7300FFA864 /* AsyncRevalidation.cpp */,
     9224                                AAFA634E234F7C6300FFA864 /* AsyncRevalidation.h */,
    92209225                                41897ED61F415D860016FA42 /* CacheStorageEngine.cpp */,
    92219226                                41897ED21F415D850016FA42 /* CacheStorageEngine.h */,
     
    94669471                                CE1A0BD21A48E6C60054EF74 /* AssertionServicesSPI.h in Headers */,
    94679472                                515E7728183DD6F60007203F /* AsyncRequest.h in Headers */,
     9473                                AAFA634F234F7C6400FFA864 /* AsyncRevalidation.h in Headers */,
    94689474                                BCEE966D112FAF57006BCC24 /* Attachment.h in Headers */,
    94699475                                E1A31732134CEA6C007C9A4F /* AttributedString.h in Headers */,
  • trunk/Tools/ChangeLog

    r252377 r252397  
     12019-11-13  Rob Buis  <rbuis@igalia.com>
     2
     3        Support stale-while-revalidate cache strategy
     4        https://bugs.webkit.org/show_bug.cgi?id=201461
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Enable stale-while-revalidate for the test runner.
     9
     10        * WebKitTestRunner/TestController.cpp:
     11        (WTR::TestController::websiteDataStore):
     12
    1132019-11-12  Wenson Hsieh  <wenson_hsieh@apple.com>
    214
  • trunk/Tools/WebKitTestRunner/TestController.cpp

    r252228 r252397  
    533533            WKWebsiteDataStoreConfigurationSetPerOriginStorageQuota(configuration.get(), 400 * 1024);
    534534            WKWebsiteDataStoreConfigurationSetNetworkCacheSpeculativeValidationEnabled(configuration.get(), true);
     535            WKWebsiteDataStoreConfigurationSetStaleWhileRevalidateEnabled(configuration.get(), true);
    535536            WKWebsiteDataStoreConfigurationSetTestingSessionEnabled(configuration.get(), true);
    536537        }
Note: See TracChangeset for help on using the changeset viewer.