Changeset 288949 in webkit


Ignore:
Timestamp:
Feb 2, 2022 2:15:07 AM (6 months ago)
Author:
youenn@apple.com
Message:

ServiceWorkerNavigationPreloader should only be used once
https://bugs.webkit.org/show_bug.cgi?id=235882
<rdar://88226432>

Reviewed by Chris Dumez.

Source/WebKit:

In case service worker preload is being used and related service worker context crashes (or service worker context sends bad messages),
We can end up in a bad state where we will ask the preload twice for the same response (once for good, and the next one as we go to didNotHandle case).
To prevent this, we add checks in loadResponseFromPreloader and loadBodyFromPreloader.
As part of this investigation, I found out that ServiceWorkerNavigationPreloader is not correctly handling the case of preload responses coming from cache.
In particular, no body will be given since we return early in waitForBody in case the preload network load is null.
Prevent this by making sure waitForBody calls the response completion handler if available, even if the preload network load is null.
And update the response body callback before executing the response completion handler to make sure data received synchronously from the preload is given to the service worker fetch task.

Test: http/wpt/service-workers/fetch-service-worker-preload-cache.https.html

  • NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp:
  • NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.cpp:

LayoutTests:

  • http/wpt/service-workers/fetch-service-worker-preload-cache.https-expected.txt: Added.
  • http/wpt/service-workers/fetch-service-worker-preload-cache.https.html: Added.
  • http/wpt/service-workers/resources/fetch-service-worker-preload-script.py:
Location:
trunk
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r288944 r288949  
     12022-02-02  Youenn Fablet  <youenn@apple.com>
     2
     3        ServiceWorkerNavigationPreloader should only be used once
     4        https://bugs.webkit.org/show_bug.cgi?id=235882
     5        <rdar://88226432>
     6
     7        Reviewed by Chris Dumez.
     8
     9        * http/wpt/service-workers/fetch-service-worker-preload-cache.https-expected.txt: Added.
     10        * http/wpt/service-workers/fetch-service-worker-preload-cache.https.html: Added.
     11        * http/wpt/service-workers/resources/fetch-service-worker-preload-script.py:
     12
    1132022-02-01  Alan Bujtas  <zalan@apple.com>
    214
  • trunk/LayoutTests/http/wpt/service-workers/resources/fetch-service-worker-preload-script.py

    r286944 r288949  
    3131    if not value:
    3232        value = b"nothing"
    33     response.headers.set(b"Cache-Control", b"no-cache")
     33
     34    if b"cache" in request.GET:
     35        response.headers.set(b"Cache-Control", b"max-age=31536000")
     36    else:
     37        response.headers.set(b"Cache-Control", b"no-cache")
    3438
    3539    if b"download" in request.GET:
  • trunk/Source/WebKit/ChangeLog

    r288942 r288949  
     12022-02-02  Youenn Fablet  <youenn@apple.com>
     2
     3        ServiceWorkerNavigationPreloader should only be used once
     4        https://bugs.webkit.org/show_bug.cgi?id=235882
     5        <rdar://88226432>
     6
     7        Reviewed by Chris Dumez.
     8
     9        In case service worker preload is being used and related service worker context crashes (or service worker context sends bad messages),
     10        We can end up in a bad state where we will ask the preload twice for the same response (once for good, and the next one as we go to didNotHandle case).
     11        To prevent this, we add checks in loadResponseFromPreloader and loadBodyFromPreloader.
     12        As part of this investigation, I found out that ServiceWorkerNavigationPreloader is not correctly handling the case of preload responses coming from cache.
     13        In particular, no body will be given since we return early in waitForBody in case the preload network load is null.
     14        Prevent this by making sure waitForBody calls the response completion handler if available, even if the preload network load is null.
     15        And update the response body callback before executing the response completion handler to make sure data received synchronously from the preload is given to the service worker fetch task.
     16
     17        Test: http/wpt/service-workers/fetch-service-worker-preload-cache.https.html
     18
     19        * NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp:
     20        * NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.cpp:
     21
    1222022-02-01  Myles C. Maxfield  <mmaxfield@apple.com>
    223
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp

    r288898 r288949  
    364364    SWFETCH_RELEASE_LOG("loadResponseFromPreloader");
    365365
    366     ASSERT(!m_isLoadingFromPreloader);
     366    if (m_isLoadingFromPreloader)
     367        return;
     368
    367369    m_isLoadingFromPreloader = true;
    368370
     
    393395
    394396    ASSERT(m_isLoadingFromPreloader);
     397    if (!m_preloader) {
     398        SWFETCH_RELEASE_LOG_ERROR("loadBodyFromPreloader preloader is null");
     399        didFail(ResourceError(errorDomainWebKitInternal, 0, m_loader.originalRequest().url(), "Request canceled from preloader"_s, ResourceError::Type::Cancellation));
     400        return;
     401    }
     402
    395403    m_preloader->waitForBody([weakThis = WeakPtr { *this }, this](auto&& chunk, int length) {
    396404        if (!weakThis)
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.cpp

    r287684 r288949  
    232232void ServiceWorkerNavigationPreloader::waitForBody(BodyCallback&& callback)
    233233{
    234     if (!m_error.isNull()) {
     234    if (!m_error.isNull() || !m_responseCompletionHandler) {
    235235        callback({ }, 0);
    236236        return;
     
    238238
    239239    ASSERT(!m_response.isNull());
    240     ASSERT(m_responseCompletionHandler || !m_networkLoad);
    241     if (!m_networkLoad) {
    242         callback({ }, 0);
    243         return;
    244     }
    245     if (m_responseCompletionHandler)
    246         m_responseCompletionHandler(PolicyAction::Use);
    247240    m_bodyCallback = WTFMove(callback);
     241    m_responseCompletionHandler(PolicyAction::Use);
    248242}
    249243
Note: See TracChangeset for help on using the changeset viewer.