Changeset 289533 in webkit


Ignore:
Timestamp:
Feb 10, 2022 7:45:10 AM (5 months ago)
Author:
youenn@apple.com
Message:

Settling of a fetch promise should be delayed in case page is entering page cache
https://bugs.webkit.org/show_bug.cgi?id=236292
<rdar://88452971>

Reviewed by Chris Dumez.

Source/WebCore:

Make sure to enqueue a task before resolving fetch promise as otherwise, page might continue running JavaScript.
Do this for worker as well for good measure.
We move signal aborted checks to two clients to handle rejecting fetch promise synchronously.

Test: http/tests/navigation/fetch-pagecache.html

  • Modules/cache/DOMCache.cpp:
  • Modules/fetch/FetchResponse.cpp:
  • Modules/fetch/FetchResponse.h:
  • Modules/fetch/WindowOrWorkerGlobalScopeFetch.cpp:
  • workers/service/FetchEvent.cpp:

LayoutTests:

  • http/tests/navigation/fetch-pagecache-expected.txt: Added.
  • http/tests/navigation/fetch-pagecache.html: Added.
Location:
trunk
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r289526 r289533  
     12022-02-10  Youenn Fablet  <youenn@apple.com>
     2
     3        Settling of a fetch promise should be delayed in case page is entering page cache
     4        https://bugs.webkit.org/show_bug.cgi?id=236292
     5        <rdar://88452971>
     6
     7        Reviewed by Chris Dumez.
     8
     9        * http/tests/navigation/fetch-pagecache-expected.txt: Added.
     10        * http/tests/navigation/fetch-pagecache.html: Added.
     11
    1122022-02-10  Antti Koivisto  <antti@apple.com>
    213
  • trunk/Source/WebCore/ChangeLog

    r289532 r289533  
     12022-02-10  Youenn Fablet  <youenn@apple.com>
     2
     3        Settling of a fetch promise should be delayed in case page is entering page cache
     4        https://bugs.webkit.org/show_bug.cgi?id=236292
     5        <rdar://88452971>
     6
     7        Reviewed by Chris Dumez.
     8
     9        Make sure to enqueue a task before resolving fetch promise as otherwise, page might continue running JavaScript.
     10        Do this for worker as well for good measure.
     11        We move signal aborted checks to two clients to handle rejecting fetch promise synchronously.
     12
     13        Test: http/tests/navigation/fetch-pagecache.html
     14
     15        * Modules/cache/DOMCache.cpp:
     16        * Modules/fetch/FetchResponse.cpp:
     17        * Modules/fetch/FetchResponse.h:
     18        * Modules/fetch/WindowOrWorkerGlobalScopeFetch.cpp:
     19        * workers/service/FetchEvent.cpp:
     20
    1212022-02-10  Chris Dumez  <cdumez@apple.com>
    222
  • trunk/Source/WebCore/Modules/cache/DOMCache.cpp

    r287760 r289533  
    260260    for (auto& request : requests) {
    261261        auto& requestReference = request.get();
    262         FetchResponse::fetch(*scriptExecutionContext(), requestReference, [this, request = WTFMove(request), taskHandler](ExceptionOr<FetchResponse&>&& result) mutable {
     262        if (requestReference.signal().aborted()) {
     263            taskHandler->error(Exception { AbortError, "Request signal is aborted"_s });
     264            return;
     265        }
     266        FetchResponse::fetch(*scriptExecutionContext(), requestReference, [this, request = WTFMove(request), taskHandler](auto&& result) mutable {
    263267
    264268            if (taskHandler->isDone())
     
    270274            }
    271275
    272             auto& response = result.releaseReturnValue();
     276            auto protectedResponse = result.releaseReturnValue();
     277            auto& response = protectedResponse.get();
    273278
    274279            if (!response.ok()) {
     
    296301            size_t recordPosition = taskHandler->addRecord(toConnectionRecord(request.get(), response, nullptr));
    297302
    298             response.consumeBodyReceivedByChunk([taskHandler = WTFMove(taskHandler), recordPosition, data = SharedBufferBuilder(), response = Ref { response }] (auto&& result) mutable {
     303            response.consumeBodyReceivedByChunk([taskHandler = WTFMove(taskHandler), recordPosition, data = SharedBufferBuilder(), response = WTFMove(protectedResponse)] (auto&& result) mutable {
    299304                if (taskHandler->isDone())
    300305                    return;
  • trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp

    r288088 r289533  
    238238void FetchResponse::fetch(ScriptExecutionContext& context, FetchRequest& request, NotificationCallback&& responseCallback, const String& initiator)
    239239{
    240     if (request.signal().aborted()) {
    241         responseCallback(Exception { AbortError, "Request signal is aborted"_s });
    242         // FIXME: Cancel request body if it is a stream.
    243         return;
    244     }
    245 
    246240    if (request.isReadableStreamBody()) {
    247241        responseCallback(Exception { NotSupportedError, "ReadableStream uploading is not supported"_s });
     
    356350
    357351    if (auto responseCallback = WTFMove(m_responseCallback))
    358         responseCallback(m_response);
     352        responseCallback(Ref { m_response });
    359353}
    360354
  • trunk/Source/WebCore/Modules/fetch/FetchResponse.h

    r288088 r289533  
    6464    static ExceptionOr<Ref<FetchResponse>> redirect(ScriptExecutionContext&, const String& url, int status);
    6565
    66     using NotificationCallback = Function<void(ExceptionOr<FetchResponse&>&&)>;
     66    using NotificationCallback = Function<void(ExceptionOr<Ref<FetchResponse>>&&)>;
    6767    static void fetch(ScriptExecutionContext&, FetchRequest&, NotificationCallback&&, const String& initiator);
    6868
  • trunk/Source/WebCore/Modules/fetch/WindowOrWorkerGlobalScopeFetch.cpp

    r286419 r289533  
    3030#include "DOMWindow.h"
    3131#include "Document.h"
     32#include "EventLoop.h"
    3233#include "FetchResponse.h"
    3334#include "JSDOMPromiseDeferred.h"
     
    4041using FetchResponsePromise = DOMPromiseDeferred<IDLInterface<FetchResponse>>;
    4142
    42 void WindowOrWorkerGlobalScopeFetch::fetch(DOMWindow& window, FetchRequest::Info&& input, FetchRequest::Init&& init, Ref<DeferredPromise>&& deferred)
     43// https://fetch.spec.whatwg.org/#dom-global-fetch
     44static void doFetch(ScriptExecutionContext& scope, FetchRequest::Info&& input, FetchRequest::Init&& init, FetchResponsePromise&& promise)
    4345{
    44     FetchResponsePromise promise = WTFMove(deferred);
    45 
    46     auto* document = window.document();
    47     if (!document) {
    48         promise.reject(InvalidStateError);
     46    auto requestOrException = FetchRequest::create(scope, WTFMove(input), WTFMove(init));
     47    if (requestOrException.hasException()) {
     48        promise.reject(requestOrException.releaseException());
    4949        return;
    5050    }
    5151
    52     auto request = FetchRequest::create(*document, WTFMove(input), WTFMove(init));
    53     if (request.hasException()) {
    54         promise.reject(request.releaseException());
     52    auto request = requestOrException.releaseReturnValue();
     53    if (request->signal().aborted()) {
     54        promise.reject(Exception { AbortError, "Request signal is aborted"_s });
    5555        return;
    5656    }
    5757
    58     FetchResponse::fetch(*document, request.releaseReturnValue(), [promise = WTFMove(promise), userGestureToken = UserGestureIndicator::currentUserGesture()](ExceptionOr<FetchResponse&>&& result) mutable {
    59         if (!userGestureToken || userGestureToken->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwardingForFetch()) || !userGestureToken->processingUserGesture()) {
     58    FetchResponse::fetch(scope, request.get(), [promise = WTFMove(promise), scope = Ref { scope }](auto&& result) mutable {
     59        scope->eventLoop().queueTask(TaskSource::Networking, [promise = WTFMove(promise), result = WTFMove(result)]() mutable {
    6060            promise.settle(WTFMove(result));
    61             return;
    62         }
    63 
    64         UserGestureIndicator gestureIndicator(userGestureToken, UserGestureToken::GestureScope::MediaOnly, UserGestureToken::IsPropagatedFromFetch::Yes);
    65         promise.settle(WTFMove(result));
     61        });
    6662    }, cachedResourceRequestInitiators().fetch);
    6763}
    6864
    69 void WindowOrWorkerGlobalScopeFetch::fetch(WorkerGlobalScope& scope, FetchRequest::Info&& input, FetchRequest::Init&& init, Ref<DeferredPromise>&& deferred)
     65void WindowOrWorkerGlobalScopeFetch::fetch(DOMWindow& window, FetchRequest::Info&& input, FetchRequest::Init&& init, Ref<DeferredPromise>&& promise)
    7066{
    71     FetchResponsePromise promise = WTFMove(deferred);
    72 
    73     auto request = FetchRequest::create(scope, WTFMove(input), WTFMove(init));
    74     if (request.hasException()) {
    75         promise.reject(request.releaseException());
     67    auto* document = window.document();
     68    if (!document) {
     69        promise->reject(InvalidStateError);
    7670        return;
    7771    }
     72    doFetch(*document, WTFMove(input), WTFMove(init), WTFMove(promise));
     73}
    7874
    79     FetchResponse::fetch(scope, request.releaseReturnValue().get(), [promise = WTFMove(promise)](ExceptionOr<FetchResponse&>&& result) mutable {
    80         promise.settle(WTFMove(result));
    81     }, cachedResourceRequestInitiators().fetch);
     75void WindowOrWorkerGlobalScopeFetch::fetch(WorkerGlobalScope& scope, FetchRequest::Info&& input, FetchRequest::Init&& init, Ref<DeferredPromise>&& promise)
     76{
     77    doFetch(scope, WTFMove(input), WTFMove(init), WTFMove(promise));
    8278}
    8379
Note: See TracChangeset for help on using the changeset viewer.