Title: [295488] trunk
Revision
295488
Author
commit-qu...@webkit.org
Date
2022-06-13 07:07:54 -0700 (Mon, 13 Jun 2022)

Log Message

Do not route the navigation preload response body to the service worker if we can avoid it
https://bugs.webkit.org/show_bug.cgi?id=241122
rdar://problem/94141714

Patch by Youenn Fablet <youe...@gmail.com> on 2022-06-13
Reviewed by Chris Dumez.

To further optimize navigation preload, we always start the preload as soon as possible.
In addition to that, we no longer pipe the body through the service worker in the common case:
- When the preload receives the response, it sends it to the service worker that will resolve the preload promise.
- The service worker is then expected to synchronously provide it to the FetchEvent.
- If the fetch event gets the preload response and the preload response has not been started to load in the service worker,
  the service worker instructs network process to let the preload directly go to the WebProcess.
- The preload response body might be loaded in the service worker if the response is cloned or if the service worker does not instruct
  the fetch event to use the preload fast enough. We schedule one task for the body to actually be loaded in the service worker.
- Set service worker navigation preload redirection fetchStart based on the navigation preloader start to continue passing
  LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/navigation-preload/resource-timing.https.html.

We store the preload response/error in WebServiceWorkerFetchTaskClient as the preload response might be received between the time the fetch event
is received and the time the fetch event is dispatched.

* LayoutTests/http/wpt/service-workers/navigation-optimization-worker.js: Added.
(async doTest):
* LayoutTests/http/wpt/service-workers/navigation-optimization.https-expected.txt: Added.
* LayoutTests/http/wpt/service-workers/navigation-optimization.https.html: Added.
* LayoutTests/http/wpt/service-workers/resources/navigation-optimization.py: Added.
(main):
* LayoutTests/http/wpt/service-workers/resources/service-worker-iframe-preload-script.py:
(main):
* LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https-expected.txt:
* LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https.html:
* Source/WebCore/Headers.cmake:
* Source/WebCore/Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::createFetchResponse):
(WebCore::FetchResponse::fetch):
(WebCore::FetchResponse::startLoader):
(WebCore::FetchResponse::setReceivedInternalResponse):
(WebCore::FetchResponse::BodyLoader::didReceiveResponse):
(WebCore::FetchResponse::markAsDisturbed):
* Source/WebCore/Modules/fetch/FetchResponse.h:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/bindings/js/JSFetchEventCustom.cpp:
* Source/WebCore/testing/ServiceWorkerInternals.cpp:
* Source/WebCore/workers/service/FetchEvent.cpp:
(WebCore::FetchEvent::preloadResponse):
(WebCore::FetchEvent::navigationPreloadIsReady):
(WebCore::FetchEvent::navigationPreloadFailed):
* Source/WebCore/workers/service/FetchEvent.h:
* Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp:
(WebCore::ServiceWorkerFetch::processResponse):
(WebCore::ServiceWorkerFetch::dispatchFetchEvent):
* Source/WebCore/workers/service/context/ServiceWorkerFetch.h:
* Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp:
(WebCore::ServiceWorkerThreadProxy::navigationPreloadIsReady):
(WebCore::ServiceWorkerThreadProxy::navigationPreloadFailed):
* Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.h:
* Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp:
(WebKit::ServiceWorkerFetchTask::ServiceWorkerFetchTask):
(WebKit::ServiceWorkerFetchTask::startFetch):
(WebKit::ServiceWorkerFetchTask::usePreload):
(WebKit::ServiceWorkerFetchTask::loadResponseFromPreloader):
(WebKit::ServiceWorkerFetchTask::preloadResponseIsReady):
* Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h:
* Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.messages.in:
* Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.cpp:
(WebKit::ServiceWorkerNavigationPreloader::ServiceWorkerNavigationPreloader):
(WebKit::ServiceWorkerNavigationPreloader::didReceiveResponse):
(WebKit::ServiceWorkerNavigationPreloader::waitForResponse):
* Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp:
(WebKit::WebSWContextManagerConnection::navigationPreloadIsReady):
(WebKit::WebSWContextManagerConnection::navigationPreloadFailed):
* Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h:
* Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.messages.in:
* Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.cpp:
(WebKit::WebServiceWorkerFetchTaskClient::navigationPreloadIsReady):
(WebKit::WebServiceWorkerFetchTaskClient::navigationPreloadFailed):
(WebKit::WebServiceWorkerFetchTaskClient::usePreload):
(WebKit::WebServiceWorkerFetchTaskClient::cleanup):
* Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.h:

Canonical link: https://commits.webkit.org/251493@main

Modified Paths

Added Paths

Diff

Added: trunk/LayoutTests/http/wpt/service-workers/navigation-optimization-worker.js (0 => 295488)


--- trunk/LayoutTests/http/wpt/service-workers/navigation-optimization-worker.js	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/navigation-optimization-worker.js	2022-06-13 14:07:54 UTC (rev 295488)
@@ -0,0 +1,19 @@
+async function doTest(event)
+{
+    if (event.preloadResponse) {
+        event.respondWith(event.preloadResponse.then((response) => {
+            if (event.request.url.includes("get-body")) {
+                const clone = response.clone();
+                clone.body.getReader();
+                return response;
+            }
+            if (self.internals)
+                setTimeout(() => internals.terminate(), 0);
+            return response;
+        }));
+        return;
+    }
+    event.respondWith(fetch(event.request));
+}
+
+self.addEventListener("fetch", doTest);

Added: trunk/LayoutTests/http/wpt/service-workers/navigation-optimization.https-expected.txt (0 => 295488)


--- trunk/LayoutTests/http/wpt/service-workers/navigation-optimization.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/navigation-optimization.https-expected.txt	2022-06-13 14:07:54 UTC (rev 295488)
@@ -0,0 +1,6 @@
+
+
+PASS Setup worker
+PASS Make sure a load that is transferred in network process continues even if service worker gets terminated.
+PASS Make sure a load that a preload response can be read right away.
+

Added: trunk/LayoutTests/http/wpt/service-workers/navigation-optimization.https.html (0 => 295488)


--- trunk/LayoutTests/http/wpt/service-workers/navigation-optimization.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/navigation-optimization.https.html	2022-06-13 14:07:54 UTC (rev 295488)
@@ -0,0 +1,49 @@
+<html>
+<head>
+<script src=""
+<script src=""
+<script src=""
+</head>
+<body>
+<script>
+promise_test(async (test) => {
+    const scope = "resources";
+    const registration = await navigator.serviceWorker.register("navigation-optimization-worker.js", { scope : scope });
+    activeWorker = registration.active;
+    if (activeWorker)
+        return;
+    activeWorker = registration.installing;
+    await new Promise(resolve => {
+        activeWorker.addEventListener('statechange', () => {
+            if (activeWorker.state === "activated")
+                resolve();
+        });
+    });
+
+    await registration.navigationPreload.enable();
+}, "Setup worker");
+
+promise_test(async (test) => {
+    const promise1 = new Promise((resolve, reject) => { window.callback1 = resolve; setTimeout(() => reject("callback1"), 4000); });
+    const promise2 = new Promise((resolve, reject) => { window.callback2 = resolve; setTimeout(() => reject("callback2"), 5000); });
+
+    // The iframe is responsible to call callback1 and callback2.
+    with_iframe("/WebKit/service-workers/resources/navigation-optimization.py?delay=1.0");
+
+    await promise1;
+    await promise2;
+}, "Make sure a load that is transferred in network process continues even if service worker gets terminated.");
+
+promise_test(async (test) => {
+    const promise1 = new Promise((resolve, reject) => { window.callback1 = resolve; setTimeout(() => reject("callback1"), 4000); });
+    const promise2 = new Promise((resolve, reject) => { window.callback2 = resolve; setTimeout(() => reject("callback2"), 5000); });
+
+    // The iframe is responsible to call callback1 and callback2.
+    with_iframe("/WebKit/service-workers/resources/navigation-optimization.py?get-body");
+
+    await promise1;
+    await promise2;
+}, "Make sure a load that a preload response can be read right away.");
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/wpt/service-workers/resources/navigation-optimization.py (0 => 295488)


--- trunk/LayoutTests/http/wpt/service-workers/resources/navigation-optimization.py	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/resources/navigation-optimization.py	2022-06-13 14:07:54 UTC (rev 295488)
@@ -0,0 +1,14 @@
+import time
+
+def main(request, response):
+    delay = 0.05
+    headers = []
+    if b"delay" in request.GET:
+        delay = float(request.GET.first(b"delay"))
+    response.headers.set(b"Content-type", b"text/html")
+    response.headers.append(b"Access-Control-Allow-Origin", b"*")
+    response.write_status_headers()
+    response.writer.write_content("<script>parent.callback1();</script>")
+    time.sleep(delay)
+    response.writer.write_content("<script>parent.callback2();</script>")
+    time.sleep(delay)

Modified: trunk/LayoutTests/http/wpt/service-workers/resources/service-worker-iframe-preload-script.py (295487 => 295488)


--- trunk/LayoutTests/http/wpt/service-workers/resources/service-worker-iframe-preload-script.py	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/LayoutTests/http/wpt/service-workers/resources/service-worker-iframe-preload-script.py	2022-06-13 14:07:54 UTC (rev 295488)
@@ -17,7 +17,7 @@
     if not value:
         response.headers.set(b"Cache-Control", b"no-cache")
         response.headers.set(b"Content-Type", b"text/html")
-        return "<html><body><script>window.value = 'nothing';</script></body></html>"
+        return "nothing"
 
     response.headers.set(b"Cache-Control", b"no-cache")
     response.headers.set(b"Content-Type", b"text/ascii")

Modified: trunk/LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https-expected.txt (295487 => 295488)


--- trunk/LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https-expected.txt	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https-expected.txt	2022-06-13 14:07:54 UTC (rev 295488)
@@ -1,5 +1,5 @@
 
 
 PASS Setup activating worker
-PASS Service worker load uses preload if available and fetch event was not handled
+PASS Service worker load uses preload that starts as soon as possible
 

Modified: trunk/LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https.html (295487 => 295488)


--- trunk/LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https.html	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https.html	2022-06-13 14:07:54 UTC (rev 295488)
@@ -64,11 +64,11 @@
     activeWorker.postMessage("fetch");
 
     const response = await fetchPromise;
-    assert_equals(await response.text(), "before-navigation");
+    assert_equals(await response.text(), "nothing");
 
     const frame = await iframePromise;
-    assert_equals(frame.contentWindow.value, "nothing");
-}, "Service worker load uses preload if available and fetch event was not handled");
+    assert_equals(frame.contentWindow.document.body.innerText, "before-navigation");
+}, "Service worker load uses preload that starts as soon as possible");
 </script>
 </body>
 </html>

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/navigation-preload/resources/resource-timing-scope.py (295487 => 295488)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/navigation-preload/resources/resource-timing-scope.py	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/navigation-preload/resources/resource-timing-scope.py	2022-06-13 14:07:54 UTC (rev 295488)
@@ -1,3 +1,4 @@
+import time
 import zlib
 
 def main(request, response):

Modified: trunk/Source/WebCore/Headers.cmake (295487 => 295488)


--- trunk/Source/WebCore/Headers.cmake	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/Headers.cmake	2022-06-13 14:07:54 UTC (rev 295488)
@@ -164,11 +164,11 @@
 
     Modules/fetch/FetchBodyConsumer.h
     Modules/fetch/FetchBodySource.h
-    Modules/fetch/FetchRequestCredentials.h
     Modules/fetch/FetchHeaders.h
     Modules/fetch/FetchIdentifier.h
     Modules/fetch/FetchLoader.h
     Modules/fetch/FetchLoaderClient.h
+    Modules/fetch/FetchRequestCredentials.h
 
     Modules/filesystemaccess/FileSystemDirectoryHandle.h
     Modules/filesystemaccess/FileSystemFileHandle.h
@@ -425,6 +425,7 @@
     bindings/js/BufferSource.h
     bindings/js/CachedScriptFetcher.h
     bindings/js/CommonVM.h
+    bindings/js/DOMPromiseProxy.h
     bindings/js/DOMWrapperWorld.h
     bindings/js/ExceptionDetails.h
     bindings/js/GCController.h
@@ -2026,6 +2027,9 @@
     workers/WorkerThreadType.h
     workers/WorkerType.h
 
+    workers/service/ExtendableEvent.h
+    workers/service/ExtendableEventInit.h
+    workers/service/FetchEvent.h
     workers/service/NavigationPreloadState.h
     workers/service/SWClientConnection.h
     workers/service/ServiceWorkerClientData.h

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp (295487 => 295488)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -235,15 +235,8 @@
     });
 }
 
-void FetchResponse::fetch(ScriptExecutionContext& context, FetchRequest& request, NotificationCallback&& responseCallback, const String& initiator)
+Ref<FetchResponse> FetchResponse::createFetchResponse(ScriptExecutionContext& context, FetchRequest& request, NotificationCallback&& responseCallback)
 {
-    if (request.isReadableStreamBody()) {
-        responseCallback(Exception { NotSupportedError, "ReadableStream uploading is not supported"_s });
-        return;
-    }
-
-    InspectorInstrumentation::willFetch(context, request.url().string());
-
     auto response = adoptRef(*new FetchResponse(&context, FetchBody { }, FetchHeaders::create(FetchHeaders::Guard::Immutable), { }));
     response->suspendIfNeeded();
 
@@ -252,10 +245,28 @@
     response->addAbortSteps(request.signal());
 
     response->m_bodyLoader = makeUnique<BodyLoader>(response.get(), WTFMove(responseCallback));
-    if (!response->m_bodyLoader->start(context, request, initiator))
-        response->m_bodyLoader = nullptr;
+    return response;
 }
 
+void FetchResponse::fetch(ScriptExecutionContext& context, FetchRequest& request, NotificationCallback&& responseCallback, const String& initiator)
+{
+    if (request.isReadableStreamBody()) {
+        responseCallback(Exception { NotSupportedError, "ReadableStream uploading is not supported"_s });
+        return;
+    }
+
+    auto response = createFetchResponse(context, request, WTFMove(responseCallback));
+    response->startLoader(context, request, initiator);
+}
+
+void FetchResponse::startLoader(ScriptExecutionContext& context, FetchRequest& request, const String& initiator)
+{
+    InspectorInstrumentation::willFetch(context, request.url().string());
+
+    if (m_bodyLoader && !m_bodyLoader->start(context, request, initiator))
+        m_bodyLoader = nullptr;
+}
+
 const String& FetchResponse::url() const
 {
     if (m_responseURL.isNull()) {
@@ -322,6 +333,26 @@
     }
 }
 
+static std::atomic<uint64_t> nextOpaqueLoadIdentifier;
+void FetchResponse::setReceivedInternalResponse(const ResourceResponse& resourceResponse, FetchOptions::Credentials credentials)
+{
+    if (m_hasInitializedInternalResponse)
+        return;
+
+    m_hasInitializedInternalResponse = true;
+    auto performCheck = credentials == FetchOptions::Credentials::Include ? ResourceResponse::PerformExposeAllHeadersCheck::No : ResourceResponse::PerformExposeAllHeadersCheck::Yes;
+    m_filteredResponse = ResourceResponseBase::filter(resourceResponse, performCheck);
+    m_internalResponse = resourceResponse;
+    m_internalResponse.setType(m_filteredResponse->type());
+    if (resourceResponse.tainting() == ResourceResponse::Tainting::Opaque) {
+        m_opaqueLoadIdentifier = ++nextOpaqueLoadIdentifier;
+        setBodyAsOpaque();
+    }
+
+    m_headers->filterAndFill(m_filteredResponse->httpHeaderFields(), FetchHeaders::Guard::Response);
+    updateContentType();
+}
+
 FetchResponse::BodyLoader::BodyLoader(FetchResponse& response, NotificationCallback&& responseCallback)
     : m_response(response)
     , m_responseCallback(WTFMove(responseCallback))
@@ -333,21 +364,10 @@
 {
 }
 
-static uint64_t nextOpaqueLoadIdentifier { 0 };
 void FetchResponse::BodyLoader::didReceiveResponse(const ResourceResponse& resourceResponse)
 {
-    auto performCheck = m_credentials == FetchOptions::Credentials::Include ? ResourceResponse::PerformExposeAllHeadersCheck::No : ResourceResponse::PerformExposeAllHeadersCheck::Yes;
-    m_response.m_filteredResponse = ResourceResponseBase::filter(resourceResponse, performCheck);
-    m_response.m_internalResponse = resourceResponse;
-    m_response.m_internalResponse.setType(m_response.m_filteredResponse->type());
-    if (resourceResponse.tainting() == ResourceResponse::Tainting::Opaque) {
-        m_response.m_opaqueLoadIdentifier = ++nextOpaqueLoadIdentifier;
-        m_response.setBodyAsOpaque();
-    }
+    m_response.setReceivedInternalResponse(resourceResponse, m_credentials);
 
-    m_response.m_headers->filterAndFill(m_response.m_filteredResponse->httpHeaderFields(), FetchHeaders::Guard::Response);
-    m_response.updateContentType();
-
     if (auto responseCallback = WTFMove(m_responseCallback))
         responseCallback(Ref { m_response });
 }
@@ -385,7 +405,16 @@
     m_credentials = request.fetchOptions().credentials;
     m_loader = makeUnique<FetchLoader>(*this, &m_response.m_body->consumer());
     m_loader->start(context, request, initiator);
-    return m_loader->isStarted();
+
+    if (!m_loader->isStarted())
+        return false;
+
+    if (m_shouldStartStreaming) {
+        auto data = ""
+        ASSERT_UNUSED(data, !data);
+    }
+
+    return true;
 }
 
 void FetchResponse::BodyLoader::stop()
@@ -399,7 +428,7 @@
 {
     ASSERT(!m_consumeDataCallback);
     m_consumeDataCallback = WTFMove(consumeDataCallback);
-    auto data = ""
+    auto data = ""
     if (!data)
         return;
 
@@ -421,6 +450,12 @@
     return body().take();
 }
 
+void FetchResponse::markAsDisturbed()
+{
+    ASSERT(!m_isDisturbed);
+    m_isDisturbed = true;
+}
+
 void FetchResponse::consumeBodyReceivedByChunk(ConsumeDataByChunkCallback&& callback)
 {
     ASSERT(isBodyReceivedByChunk());
@@ -518,7 +553,11 @@
 
 RefPtr<FragmentedSharedBuffer> FetchResponse::BodyLoader::startStreaming()
 {
-    ASSERT(m_loader);
+    if (!m_loader) {
+        m_shouldStartStreaming = true;
+        return nullptr;
+    }
+
     return m_loader->startStreaming();
 }
 

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.h (295487 => 295488)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.h	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.h	2022-06-13 14:07:54 UTC (rev 295488)
@@ -65,6 +65,7 @@
 
     using NotificationCallback = Function<void(ExceptionOr<Ref<FetchResponse>>&&)>;
     static void fetch(ScriptExecutionContext&, FetchRequest&, NotificationCallback&&, const String& initiator);
+    static Ref<FetchResponse> createFetchResponse(ScriptExecutionContext&, FetchRequest&, NotificationCallback&&);
 
     void startConsumingStream(unsigned);
     void consumeChunk(Ref<JSC::Uint8Array>&&);
@@ -113,7 +114,13 @@
     bool hasWasmMIMEType() const;
 
     const NetworkLoadMetrics& networkLoadMetrics() const { return m_networkLoadMetrics; }
+    void setReceivedInternalResponse(const ResourceResponse&, FetchOptions::Credentials);
+    void startLoader(ScriptExecutionContext&, FetchRequest&, const String& initiator);
 
+    void setIsNavigationPreload(bool isNavigationPreload) { m_isNavigationPreload = isNavigationPreload; }
+    bool isAvailableNavigationPreload() const { return m_isNavigationPreload && m_bodyLoader && !m_bodyLoader->hasLoader() && !hasReadableStreamBody(); }
+    void markAsDisturbed();
+
 private:
     FetchResponse(ScriptExecutionContext*, std::optional<FetchBody>&&, Ref<FetchHeaders>&&, ResourceResponse&&);
 
@@ -137,6 +144,8 @@
 
         void consumeDataByChunk(ConsumeDataByChunkCallback&&);
 
+        bool hasLoader() const { return !!m_loader; }
+
         RefPtr<FragmentedSharedBuffer> startStreaming();
         NotificationCallback takeNotificationCallback() { return WTFMove(m_responseCallback); }
         ConsumeDataByChunkCallback takeConsumeDataCallback() { return WTFMove(m_consumeDataCallback); }
@@ -154,6 +163,7 @@
         std::unique_ptr<FetchLoader> m_loader;
         Ref<PendingActivity<FetchResponse>> m_pendingActivity;
         FetchOptions::Credentials m_credentials;
+        bool m_shouldStartStreaming { false };
     };
 
     mutable std::optional<ResourceResponse> m_filteredResponse;
@@ -165,6 +175,8 @@
     uint64_t m_opaqueLoadIdentifier { 0 };
     RefPtr<AbortSignal> m_abortSignal;
     NetworkLoadMetrics m_networkLoadMetrics;
+    bool m_hasInitializedInternalResponse { false };
+    bool m_isNavigationPreload { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (295487 => 295488)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-06-13 14:07:54 UTC (rev 295488)
@@ -1174,6 +1174,9 @@
 		4181C64A255B4C2800AEB0FF /* RTCRtpSFrameTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = 4181C644255B4C2700AEB0FF /* RTCRtpSFrameTransform.h */; };
 		418205471E53E98C00D62207 /* RTCController.h in Headers */ = {isa = PBXBuildFile; fileRef = 418205451E53C8CD00D62207 /* RTCController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		4184F5161EAF05A800F18BF0 /* OrientationNotifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 4184F5151EAF059800F18BF0 /* OrientationNotifier.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		41860F0D2847A49600E4A395 /* FetchEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 41AF37881F8C1E7900111C31 /* FetchEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		41860F0E2847A58B00E4A395 /* ExtendableEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 41AF378A1F8C1E7A00111C31 /* ExtendableEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		41860F0F2847A5BE00E4A395 /* ExtendableEventInit.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131F3B41F955BC30059995A /* ExtendableEventInit.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		4186BD3E213EE3400001826F /* LibWebRTCUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D1A049213EDDFD0063FB6B /* LibWebRTCUtils.cpp */; };
 		4186BD3F213EE3430001826F /* LibWebRTCRtpSenderBackend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D1A04B213EDDFE0063FB6B /* LibWebRTCRtpSenderBackend.cpp */; };
 		4186BD40213EE3450001826F /* LibWebRTCRtpReceiverBackend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D1A04A213EDDFE0063FB6B /* LibWebRTCRtpReceiverBackend.cpp */; };
@@ -2508,7 +2511,7 @@
 		7C4C96DF1AD4483500363572 /* JSReadableStreamBYOBReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C4C96DB1AD4483500363572 /* JSReadableStreamBYOBReader.h */; };
 		7C4C96DF1AD4483500365A50 /* JSReadableStreamDefaultReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C4C96DB1AD4483500365A50 /* JSReadableStreamDefaultReader.h */; };
 		7C514E0324AF805E0050710F /* ColorConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C514E0024AF80580050710F /* ColorConversion.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		7C516AD41F3525200034B6BF /* DOMPromiseProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C516AD21F3525200034B6BF /* DOMPromiseProxy.h */; };
+		7C516AD41F3525200034B6BF /* DOMPromiseProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C516AD21F3525200034B6BF /* DOMPromiseProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		7C5222961E1DAE03002CB8F7 /* IDLTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C5222951E1DADF8002CB8F7 /* IDLTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		7C5222991E1DAE1C002CB8F7 /* ActiveDOMCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C5222981E1DAE16002CB8F7 /* ActiveDOMCallback.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		7C52229E1E1DAE47002CB8F7 /* RuntimeEnabledFeatures.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C52229C1E1DAE47002CB8F7 /* RuntimeEnabledFeatures.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -36470,6 +36473,7 @@
 				BCEA485A097D93020094C9E4 /* LegacyInlineTextBox.h in Headers */,
 				E4E94D6122FF158A00DD191F /* LegacyLineLayout.h in Headers */,
 				F44A5F591FED38F2007F5944 /* LegacyNSPasteboardTypes.h in Headers */,
+				41860F0E2847A58B00E4A395 /* ExtendableEvent.h in Headers */,
 				A185B42A1E8211A100DC9118 /* LegacyPreviewLoader.h in Headers */,
 				A10DBF4718F92317000D70C6 /* LegacyPreviewLoaderClient.h in Headers */,
 				436708C312D9CA4B00044234 /* LegacyRenderSVGContainer.h in Headers */,
@@ -37145,6 +37149,7 @@
 				550A0BCA085F6039007353D6 /* QualifiedName.h in Headers */,
 				83C1F5941EDF69D300410D27 /* QualifiedNameCache.h in Headers */,
 				CD20ED3C27878FFB0038BE44 /* QueuedVideoOutput.h in Headers */,
+				41860F0F2847A5BE00E4A395 /* ExtendableEventInit.h in Headers */,
 				A15E31F41E0CB0B5004B371C /* QuickLook.h in Headers */,
 				9BAEE92C22388A7D004157A9 /* Quirks.h in Headers */,
 				379E371713736A6600B9E919 /* QuotedPrintable.h in Headers */,
@@ -38166,6 +38171,7 @@
 				97AABD1714FA09D5007457AE /* ThreadableWebSocketChannel.h in Headers */,
 				97AABD1914FA09D5007457AE /* ThreadableWebSocketChannelClientWrapper.h in Headers */,
 				51DF6D7E0B92A16D00C2DC85 /* ThreadCheck.h in Headers */,
+				41860F0D2847A49600E4A395 /* FetchEvent.h in Headers */,
 				0F6383DE18615B29003E5DB5 /* ThreadedScrollingTree.h in Headers */,
 				E1FF57A30F01255B00891EBB /* ThreadGlobalData.h in Headers */,
 				51D7EFEA1BDE8F8C00E93E10 /* ThreadSafeDataBuffer.h in Headers */,

Modified: trunk/Source/WebCore/bindings/js/JSFetchEventCustom.cpp (295487 => 295488)


--- trunk/Source/WebCore/bindings/js/JSFetchEventCustom.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/bindings/js/JSFetchEventCustom.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -28,6 +28,7 @@
 
 #if ENABLE(SERVICE_WORKER)
 
+#include "FetchRequest.h"
 #include "WebCoreOpaqueRoot.h"
 #include "WebCoreOpaqueRoot.h"
 

Modified: trunk/Source/WebCore/testing/ServiceWorkerInternals.cpp (295487 => 295488)


--- trunk/Source/WebCore/testing/ServiceWorkerInternals.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/testing/ServiceWorkerInternals.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -29,6 +29,7 @@
 #if ENABLE(SERVICE_WORKER)
 
 #include "FetchEvent.h"
+#include "FetchRequest.h"
 #include "JSFetchResponse.h"
 #include "PushSubscription.h"
 #include "PushSubscriptionData.h"

Modified: trunk/Source/WebCore/workers/service/FetchEvent.cpp (295487 => 295488)


--- trunk/Source/WebCore/workers/service/FetchEvent.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/workers/service/FetchEvent.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -28,6 +28,7 @@
 
 #include "CachedResourceRequestInitiators.h"
 #include "EventNames.h"
+#include "FetchRequest.h"
 #include "JSDOMPromise.h"
 #include "JSFetchResponse.h"
 #include "Logging.h"
@@ -163,32 +164,45 @@
             }
             return *m_preloadResponsePromise;
         }
+    }
+    return *m_preloadResponsePromise;
+}
 
-        auto request = FetchRequest::create(context, { }, FetchHeaders::create(), ResourceRequest { m_request->internalRequest() } , FetchOptions { m_request->fetchOptions() }, String { m_request->internalRequestReferrer() });
-        request->setNavigationPreloadIdentifier(m_navigationPreloadIdentifier);
-        FetchResponse::fetch(context, request.get(), [protectedThis = Ref { *this }](auto&& result) {
-            if (result.hasException()) {
-                protectedThis->m_preloadResponsePromise->reject(result.releaseException());
-                return;
-            }
+void FetchEvent::navigationPreloadIsReady(ResourceResponse&& response)
+{
+    auto* globalObject = m_handled->globalObject();
+    auto* context = globalObject ? globalObject->scriptExecutionContext() : nullptr;
+    if (!context)
+        return;
 
-            Ref response = result.releaseReturnValue();
-            auto* context = response->scriptExecutionContext();
-            if (!context)
-                return;
-            auto* globalObject = context->globalObject();
-            if (!globalObject)
-                return;
+    if (!m_preloadResponsePromise)
+        m_preloadResponsePromise = makeUnique<PreloadResponsePromise>();
 
-            auto& vm = globalObject->vm();
-            JSC::JSLockHolder lock(vm);
-            JSC::Strong<JSC::Unknown> value { vm, toJS(globalObject, JSC::jsCast<JSDOMGlobalObject*>(globalObject), response.get()) };
-            protectedThis->m_preloadResponsePromise->resolve(value);
-        }, cachedResourceRequestInitiators().navigation);
-    }
-    return *m_preloadResponsePromise;
+    auto request = FetchRequest::create(*context, { }, FetchHeaders::create(), ResourceRequest { m_request->internalRequest() } , FetchOptions { m_request->fetchOptions() }, String { m_request->internalRequestReferrer() });
+    request->setNavigationPreloadIdentifier(m_navigationPreloadIdentifier);
+
+    auto fetchResponse = FetchResponse::createFetchResponse(*context, request.get(), { });
+    fetchResponse->setReceivedInternalResponse(response, FetchOptions::Credentials::Include);
+    fetchResponse->setIsNavigationPreload(true);
+
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+    JSC::Strong<JSC::Unknown> value { vm, toJS(globalObject, JSC::jsCast<JSDOMGlobalObject*>(globalObject), fetchResponse.get()) };
+    m_preloadResponsePromise->resolve(value);
+
+    // We postpone the load to leave some time for the service worker to use the preload before loading it.
+    context->postTask([fetchResponse = WTFMove(fetchResponse), request = WTFMove(request)](auto& context) {
+        fetchResponse->startLoader(context, request.get(), cachedResourceRequestInitiators().navigation);
+    });
 }
 
+void FetchEvent::navigationPreloadFailed(ResourceError&& error)
+{
+    if (!m_preloadResponsePromise)
+        m_preloadResponsePromise = makeUnique<PreloadResponsePromise>();
+    m_preloadResponsePromise->reject(Exception { TypeError, error.sanitizedDescription() });
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(SERVICE_WORKER)

Modified: trunk/Source/WebCore/workers/service/FetchEvent.h (295487 => 295488)


--- trunk/Source/WebCore/workers/service/FetchEvent.h	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/workers/service/FetchEvent.h	2022-06-13 14:07:54 UTC (rev 295488)
@@ -29,7 +29,8 @@
 
 #include "DOMPromiseProxy.h"
 #include "ExtendableEvent.h"
-#include "FetchRequest.h"
+#include "FetchIdentifier.h"
+#include "ResourceError.h"
 #include <wtf/CompletionHandler.h>
 #include <wtf/Expected.h>
 
@@ -40,8 +41,8 @@
 namespace WebCore {
 
 class DOMPromise;
+class FetchRequest;
 class FetchResponse;
-class ResourceError;
 
 class FetchEvent final : public ExtendableEvent {
     WTF_MAKE_ISO_ALLOCATED(FetchEvent);
@@ -81,6 +82,8 @@
     PreloadResponsePromise& preloadResponse(ScriptExecutionContext&);
 
     void setNavigationPreloadIdentifier(FetchIdentifier);
+    WEBCORE_EXPORT void navigationPreloadIsReady(ResourceResponse&&);
+    WEBCORE_EXPORT void navigationPreloadFailed(ResourceError&&);
 
 private:
     WEBCORE_EXPORT FetchEvent(JSC::JSGlobalObject&, const AtomString&, Init&&, IsTrusted);

Modified: trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp (295487 => 295488)


--- trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -99,6 +99,12 @@
 
     promise.resolve();
 
+    if (response->isAvailableNavigationPreload()) {
+        client->usePreload();
+        response->markAsDisturbed();
+        return;
+    }
+
     if (resourceResponse.isRedirection() && resourceResponse.httpHeaderFields().contains(HTTPHeaderName::Location)) {
         client->didReceiveRedirection(resourceResponse);
         return;
@@ -202,9 +208,10 @@
     init.handled = DOMPromise::create(jsDOMGlobalObject, *promise);
 
     auto event = FetchEvent::create(*globalScope.globalObject(), eventNames().fetchEvent, WTFMove(init), Event::IsTrusted::Yes);
-
-    if (isServiceWorkerNavigationPreloadEnabled)
+    if (isServiceWorkerNavigationPreloadEnabled) {
+        client->setFetchEvent(event.copyRef());
         event->setNavigationPreloadIdentifier(fetchIdentifier);
+    }
 
     CertificateInfo certificateInfo = globalScope.certificateInfo();
 

Modified: trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.h (295487 => 295488)


--- trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.h	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.h	2022-06-13 14:07:54 UTC (rev 295488)
@@ -61,6 +61,10 @@
     virtual void setCancelledCallback(Function<void()>&&) = 0;
     virtual void continueDidReceiveResponse() = 0;
     virtual void convertFetchToDownload() = 0;
+    virtual void setFetchEvent(Ref<FetchEvent>&&) = 0;
+    virtual void navigationPreloadIsReady(ResourceResponse&&) = 0;
+    virtual void navigationPreloadFailed(ResourceError&&) = 0;
+    virtual void usePreload() = 0;
 };
 
 void dispatchFetchEvent(Ref<Client>&&, ServiceWorkerGlobalScope&, ResourceRequest&&, String&& referrer, FetchOptions&&, FetchIdentifier, bool isServiceWorkerNavigationPreloadEnabled, String&& clientIdentifier, String&& resultingClientIdentifier);

Modified: trunk/Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp (295487 => 295488)


--- trunk/Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -269,6 +269,24 @@
     }, WorkerRunLoop::defaultMode());
 }
 
+void ServiceWorkerThreadProxy::navigationPreloadIsReady(SWServerConnectionIdentifier connectionIdentifier, FetchIdentifier fetchIdentifier, ResourceResponse&& response)
+{
+    ASSERT(!isMainThread());
+    postTaskForModeToWorkerOrWorkletGlobalScope([this, protectedThis = Ref { *this }, connectionIdentifier, fetchIdentifier, responseData = response.crossThreadData()] (auto&) mutable {
+        if (auto client = m_ongoingFetchTasks.get({ connectionIdentifier, fetchIdentifier }))
+            client->navigationPreloadIsReady(ResourceResponse::fromCrossThreadData(WTFMove(responseData)));
+    }, WorkerRunLoop::defaultMode());
+}
+
+void ServiceWorkerThreadProxy::navigationPreloadFailed(SWServerConnectionIdentifier connectionIdentifier, FetchIdentifier fetchIdentifier, ResourceError&& error)
+{
+    ASSERT(!isMainThread());
+    postTaskForModeToWorkerOrWorkletGlobalScope([this, protectedThis = Ref { *this }, connectionIdentifier, fetchIdentifier, error = WTFMove(error).isolatedCopy()] (auto&) mutable {
+        if (auto client = m_ongoingFetchTasks.get({ connectionIdentifier, fetchIdentifier }))
+            client->navigationPreloadFailed(WTFMove(error));
+    }, WorkerRunLoop::defaultMode());
+}
+
 void ServiceWorkerThreadProxy::continueDidReceiveFetchResponse(SWServerConnectionIdentifier connectionIdentifier, FetchIdentifier fetchIdentifier)
 {
     ASSERT(!isMainThread());

Modified: trunk/Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.h (295487 => 295488)


--- trunk/Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.h	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.h	2022-06-13 14:07:54 UTC (rev 295488)
@@ -79,6 +79,8 @@
     WEBCORE_EXPORT void convertFetchToDownload(SWServerConnectionIdentifier, FetchIdentifier);
     WEBCORE_EXPORT void continueDidReceiveFetchResponse(SWServerConnectionIdentifier, FetchIdentifier);
     WEBCORE_EXPORT void removeFetch(SWServerConnectionIdentifier, FetchIdentifier);
+    WEBCORE_EXPORT void navigationPreloadIsReady(SWServerConnectionIdentifier, FetchIdentifier, ResourceResponse&&);
+    WEBCORE_EXPORT void navigationPreloadFailed(SWServerConnectionIdentifier, FetchIdentifier, ResourceError&&);
 
     WEBCORE_EXPORT void fireMessageEvent(MessageWithMessagePorts&&, ServiceWorkerOrClientData&&);
 

Modified: trunk/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp (295487 => 295488)


--- trunk/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -1180,6 +1180,9 @@
     networkLoadMetrics.markComplete();
     networkLoadMetrics.responseBodyBytesReceived = 0;
     networkLoadMetrics.responseBodyDecodedSize = 0;
+
+    if (m_serviceWorkerFetchTask)
+        networkLoadMetrics.fetchStart = m_serviceWorkerFetchTask->startTime();
     send(Messages::WebResourceLoader::DidFinishResourceLoad { networkLoadMetrics });
 
     cleanup(LoadResult::Success);

Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp (295487 => 295488)


--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -72,7 +72,10 @@
     , m_fetchIdentifier(WebCore::FetchIdentifier::generate())
     , m_preloader(WTFMove(preloader))
 {
-    loadResponseFromPreloader();
+    callOnMainRunLoop([weakThis = WeakPtr { *this }] {
+        if (weakThis)
+            weakThis->loadResponseFromPreloader();
+    });
 }
 
 ServiceWorkerFetchTask::ServiceWorkerFetchTask(WebSWServerConnection& swServerConnection, NetworkResourceLoader& loader, ResourceRequest&& request, SWServerConnectionIdentifier serverConnectionIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, SWServerRegistration& registration, NetworkSession* session, bool isWorkerReady)
@@ -96,6 +99,11 @@
         parameters.request = m_currentRequest;
         m_preloader = makeUnique<ServiceWorkerNavigationPreloader>(*session, WTFMove(parameters), registration.navigationPreloadState(), loader.shouldCaptureExtraNetworkLoadMetrics());
         session->addNavigationPreloaderTask(*this);
+
+        m_preloader->waitForResponse([weakThis = WeakPtr { *this }] {
+            if (weakThis)
+                weakThis->preloadResponseIsReady();
+        });
     }
 }
 
@@ -157,6 +165,7 @@
         if (auto identifier = m_loader.parameters().options.clientIdentifier)
             clientIdentifier = identifier->toString();
     }
+
     bool isSent = sendToServiceWorker(Messages::WebSWContextManagerConnection::StartFetch { m_serverConnectionIdentifier, m_serviceWorkerIdentifier, m_fetchIdentifier, request, options, IPC::FormDataReference { m_currentRequest.httpBody() }, referrer, m_preloader && m_preloader->isServiceWorkerNavigationPreloadEnabled(), clientIdentifier, m_loader.resultingClientIdentifier() });
     ASSERT_UNUSED(isSent, isSent);
 }
@@ -295,6 +304,21 @@
     m_loader.serviceWorkerDidNotHandle(this);
 }
 
+void ServiceWorkerFetchTask::usePreload()
+{
+    if (m_isDone)
+        return;
+
+    ASSERT(m_preloader);
+    if (m_preloader) {
+        loadResponseFromPreloader();
+        return;
+    }
+
+    m_isDone = true;
+    m_loader.serviceWorkerDidNotHandle(this);
+}
+
 void ServiceWorkerFetchTask::cannotHandle()
 {
     SWFETCH_RELEASE_LOG("cannotHandle:");
@@ -371,26 +395,38 @@
         return;
 
     m_isLoadingFromPreloader = true;
+    m_preloader->waitForResponse([weakThis = WeakPtr { *this }] {
+        if (weakThis)
+            weakThis->preloadResponseIsReady();
+    });
+}
 
-    m_preloader->waitForResponse([weakThis = WeakPtr { *this }, this] {
-        if (!weakThis)
-            return;
-
-        if (!m_preloader->error().isNull()) {
-            // Let's copy the error as calling didFail might destroy m_preloader.
-            didFail(ResourceError { m_preloader->error() });
-            return;
+void ServiceWorkerFetchTask::preloadResponseIsReady()
+{
+    if (!m_isLoadingFromPreloader) {
+        if (m_preloader && m_preloader->isServiceWorkerNavigationPreloadEnabled()) {
+            if (!m_preloader->error().isNull())
+                sendToServiceWorker(Messages::WebSWContextManagerConnection::NavigationPreloadFailed { m_serverConnectionIdentifier, m_serviceWorkerIdentifier, m_fetchIdentifier, m_preloader->error() });
+            else
+                sendToServiceWorker(Messages::WebSWContextManagerConnection::NavigationPreloadIsReady { m_serverConnectionIdentifier, m_serviceWorkerIdentifier, m_fetchIdentifier, m_preloader->response() });
         }
+        return;
+    }
 
-        auto response = m_preloader->response();
-        if (response.isRedirection() && response.httpHeaderFields().contains(HTTPHeaderName::Location)) {
-            processRedirectResponse(WTFMove(response), ShouldSetSource::No);
-            return;
-        }
+    if (!m_preloader->error().isNull()) {
+        // Let's copy the error as calling didFail might destroy m_preloader.
+        didFail(ResourceError { m_preloader->error() });
+        return;
+    }
 
-        bool needsContinueDidReceiveResponseMessage = true;
-        processResponse(WTFMove(response), needsContinueDidReceiveResponseMessage, ShouldSetSource::No);
-    });
+    auto response = m_preloader->response();
+    if (response.isRedirection() && response.httpHeaderFields().contains(HTTPHeaderName::Location)) {
+        processRedirectResponse(WTFMove(response), ShouldSetSource::No);
+        return;
+    }
+
+    bool needsContinueDidReceiveResponseMessage = true;
+    processResponse(WTFMove(response), needsContinueDidReceiveResponseMessage, ShouldSetSource::No);
 }
 
 void ServiceWorkerFetchTask::loadBodyFromPreloader()
@@ -467,6 +503,11 @@
     return true;
 }
 
+MonotonicTime ServiceWorkerFetchTask::startTime() const
+{
+    return m_preloader ? m_preloader->startTime() : MonotonicTime { };
+}
+
 } // namespace WebKit
 
 #undef SWFETCH_RELEASE_LOG

Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h (295487 => 295488)


--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h	2022-06-13 14:07:54 UTC (rev 295488)
@@ -90,6 +90,8 @@
 
     bool convertToDownload(DownloadManager&, DownloadID, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
 
+    MonotonicTime startTime() const;
+
 private:
     enum class ShouldSetSource : bool { No, Yes };
     void didReceiveRedirectResponse(WebCore::ResourceResponse&&);
@@ -99,6 +101,7 @@
     void didFinish(const WebCore::NetworkLoadMetrics&);
     void didFail(const WebCore::ResourceError&);
     void didNotHandle();
+    void usePreload();
 
     void processRedirectResponse(WebCore::ResourceResponse&&, ShouldSetSource);
     void processResponse(WebCore::ResourceResponse&&, bool needsContinueDidReceiveResponseMessage, ShouldSetSource);
@@ -111,6 +114,7 @@
     void loadBodyFromPreloader();
     void cancelPreloadIfNecessary();
     NetworkSession* session();
+    void preloadResponseIsReady();
 
     template<typename Message> bool sendToServiceWorker(Message&&);
     template<typename Message> bool sendToClient(Message&&);

Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.messages.in (295487 => 295488)


--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.messages.in	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.messages.in	2022-06-13 14:07:54 UTC (rev 295488)
@@ -30,6 +30,7 @@
     DidReceiveData(IPC::SharedBufferReference data, int64_t encodedDataLength)
     DidReceiveFormData(IPC::FormDataReference data)
     DidFinish(WebCore::NetworkLoadMetrics metrics)
+    UsePreload()
 }
 
 #endif // ENABLE(SERVICE_WORKER)

Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.cpp (295487 => 295488)


--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -45,10 +45,10 @@
     , m_parameters(WTFMove(parameters))
     , m_state(state)
     , m_shouldCaptureExtraNetworkLoadMetrics(shouldCaptureExtraNetworkLoadMetrics())
+    , m_startTime(MonotonicTime::now())
 {
     RELEASE_LOG(ServiceWorker, "ServiceWorkerNavigationPreloader::ServiceWorkerNavigationPreloader %p", this);
-    if (!m_state.enabled || parameters.isMainFrameNavigation)
-        start();
+    start();
 }
 
 void ServiceWorkerNavigationPreloader::start()
@@ -164,6 +164,9 @@
 {
     RELEASE_LOG(ServiceWorker, "ServiceWorkerNavigationPreloader::didReceiveResponse %p", this);
 
+    if (response.isRedirection())
+        response.setTainting(ResourceResponse::Tainting::Opaqueredirect);
+
     if (response.httpStatusCode() == 304 && m_cacheEntry) {
         auto cacheEntry = WTFMove(m_cacheEntry);
         loadWithCacheEntry(*cacheEntry);
@@ -217,8 +220,6 @@
 
 void ServiceWorkerNavigationPreloader::waitForResponse(ResponseCallback&& callback)
 {
-    start();
-
     if (!m_error.isNull()) {
         callback();
         return;

Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.h (295487 => 295488)


--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.h	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.h	2022-06-13 14:07:54 UTC (rev 295488)
@@ -65,6 +65,8 @@
 
     bool convertToDownload(DownloadManager&, DownloadID, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
 
+    MonotonicTime startTime() const { return m_startTime; }
+
 private:
     // NetworkLoadClient.
     void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) final { }
@@ -100,6 +102,7 @@
     bool m_isStarted { false };
     bool m_isCancelled { false };
     bool m_shouldCaptureExtraNetworkLoadMetrics { false };
+    MonotonicTime m_startTime;
 };
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp (295487 => 295488)


--- trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -334,6 +334,22 @@
         serviceWorkerThreadProxy->convertFetchToDownload(serverConnectionIdentifier, fetchIdentifier);
 }
 
+void WebSWContextManagerConnection::navigationPreloadIsReady(SWServerConnectionIdentifier serverConnectionIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, FetchIdentifier fetchIdentifier, ResourceResponse&& response)
+{
+    assertIsCurrent(m_queue.get());
+
+    if (auto serviceWorkerThreadProxy = SWContextManager::singleton().serviceWorkerThreadProxyFromBackgroundThread(serviceWorkerIdentifier))
+        serviceWorkerThreadProxy->navigationPreloadIsReady(serverConnectionIdentifier, fetchIdentifier, WTFMove(response));
+}
+
+void WebSWContextManagerConnection::navigationPreloadFailed(SWServerConnectionIdentifier serverConnectionIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, FetchIdentifier fetchIdentifier, ResourceError&& error)
+{
+    assertIsCurrent(m_queue.get());
+
+    if (auto serviceWorkerThreadProxy = SWContextManager::singleton().serviceWorkerThreadProxyFromBackgroundThread(serviceWorkerIdentifier))
+        serviceWorkerThreadProxy->navigationPreloadFailed(serverConnectionIdentifier, fetchIdentifier, WTFMove(error));
+}
+
 void WebSWContextManagerConnection::postMessageToServiceWorkerClient(const ScriptExecutionContextIdentifier& destinationIdentifier, const MessageWithMessagePorts& message, ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin)
 {
     m_connectionToNetworkProcess->send(Messages::WebSWServerToContextConnection::PostMessageToServiceWorkerClient(destinationIdentifier, message, sourceIdentifier, sourceOrigin), 0);

Modified: trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h (295487 => 295488)


--- trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h	2022-06-13 14:07:54 UTC (rev 295488)
@@ -119,6 +119,8 @@
     void setThrottleState(bool isThrottleable);
     void convertFetchToDownload(WebCore::SWServerConnectionIdentifier, WebCore::ServiceWorkerIdentifier, WebCore::FetchIdentifier);
     void cancelFetchDownload(WebCore::ServiceWorkerIdentifier, WebCore::FetchIdentifier);
+    void navigationPreloadIsReady(WebCore::SWServerConnectionIdentifier, WebCore::ServiceWorkerIdentifier, WebCore::FetchIdentifier, WebCore::ResourceResponse&&);
+    void navigationPreloadFailed(WebCore::SWServerConnectionIdentifier, WebCore::ServiceWorkerIdentifier, WebCore::FetchIdentifier, WebCore::ResourceError&&);
 
     Ref<IPC::Connection> m_connectionToNetworkProcess;
     WebCore::RegistrableDomain m_registrableDomain;

Modified: trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.messages.in (295487 => 295488)


--- trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.messages.in	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.messages.in	2022-06-13 14:07:54 UTC (rev 295488)
@@ -46,6 +46,9 @@
     SetThrottleState(bool isThrottleable)
 
     ConvertFetchToDownload(WebCore::SWServerConnectionIdentifier serverConnectionIdentifier, WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, WebCore::FetchIdentifier identifier)
+
+    NavigationPreloadIsReady(WebCore::SWServerConnectionIdentifier serverConnectionIdentifier, WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, WebCore::FetchIdentifier identifier, WebCore::ResourceResponse response)
+    NavigationPreloadFailed(WebCore::SWServerConnectionIdentifier serverConnectionIdentifier, WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, WebCore::FetchIdentifier identifier, WebCore::ResourceError error)
 }
 
 #endif

Modified: trunk/Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.cpp (295487 => 295488)


--- trunk/Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.cpp	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.cpp	2022-06-13 14:07:54 UTC (rev 295488)
@@ -35,6 +35,7 @@
 #include "SharedBufferReference.h"
 #include "WebCoreArgumentCoders.h"
 #include "WebErrors.h"
+#include <WebCore/FetchEvent.h>
 #include <WebCore/ResourceError.h>
 #include <WebCore/ResourceResponse.h>
 #include <WebCore/SWContextManager.h>
@@ -225,6 +226,53 @@
     m_cancelledCallback = WTFMove(callback);
 }
 
+void WebServiceWorkerFetchTaskClient::setFetchEvent(Ref<WebCore::FetchEvent>&& event)
+{
+    m_event = WTFMove(event);
+
+    if (!m_preloadResponse.isNull()) {
+        m_event->navigationPreloadIsReady(WTFMove(m_preloadResponse));
+        m_event = nullptr;
+        return;
+    }
+
+    if (!m_preloadError.isNull()) {
+        m_event->navigationPreloadFailed(WTFMove(m_preloadError));
+        m_event = nullptr;
+    }
+}
+
+void WebServiceWorkerFetchTaskClient::navigationPreloadIsReady(ResourceResponse&& response)
+{
+    if (!m_event) {
+        m_preloadResponse = WTFMove(response);
+        return;
+    }
+
+    m_event->navigationPreloadIsReady(WTFMove(response));
+    m_event = nullptr;
+}
+
+void WebServiceWorkerFetchTaskClient::navigationPreloadFailed(ResourceError&& error)
+{
+    if (!m_event) {
+        m_preloadError = WTFMove(error);
+        return;
+    }
+    m_event->navigationPreloadFailed(WTFMove(error));
+    m_event = nullptr;
+}
+      
+void WebServiceWorkerFetchTaskClient::usePreload()
+{
+    if (!m_connection)
+        return;
+
+    m_connection->send(Messages::ServiceWorkerFetchTask::UsePreload { }, m_fetchIdentifier);
+
+    cleanup();
+}
+
 void WebServiceWorkerFetchTaskClient::continueDidReceiveResponse()
 {
     RELEASE_LOG(ServiceWorker, "ServiceWorkerFrameLoaderClient::continueDidReceiveResponse, has connection %d, didFinish %d, response type %ld", !!m_connection, m_didFinish, static_cast<long>(m_responseData.index()));
@@ -252,7 +300,7 @@
 void WebServiceWorkerFetchTaskClient::cleanup()
 {
     m_connection = nullptr;
-
+    m_event = nullptr;
     ensureOnMainRunLoop([serviceWorkerIdentifier = m_serviceWorkerIdentifier, serverConnectionIdentifier = m_serverConnectionIdentifier, fetchIdentifier = m_fetchIdentifier] {
         if (auto* proxy = SWContextManager::singleton().serviceWorkerThreadProxy(serviceWorkerIdentifier))
             proxy->removeFetch(serverConnectionIdentifier, fetchIdentifier);

Modified: trunk/Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.h (295487 => 295488)


--- trunk/Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.h	2022-06-13 12:12:37 UTC (rev 295487)
+++ trunk/Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.h	2022-06-13 14:07:54 UTC (rev 295488)
@@ -28,7 +28,7 @@
 #if ENABLE(SERVICE_WORKER)
 
 #include "Connection.h"
-#include <WebCore/FetchIdentifier.h>
+#include <WebCore/FetchEvent.h>
 #include <WebCore/FetchLoader.h>
 #include <WebCore/FetchLoaderClient.h>
 #include <WebCore/NetworkLoadMetrics.h>
@@ -60,6 +60,10 @@
     void continueDidReceiveResponse() final;
     void convertFetchToDownload() final;
     void setCancelledCallback(Function<void()>&&) final;
+    void setFetchEvent(Ref<WebCore::FetchEvent>&&);
+    void navigationPreloadIsReady(WebCore::ResourceResponse&&) final;
+    void navigationPreloadFailed(WebCore::ResourceError&&) final;
+    void usePreload() final;
 
     void cleanup();
 
@@ -90,7 +94,10 @@
     WebCore::NetworkLoadMetrics m_networkLoadMetrics;
     bool m_didFinish { false };
     bool m_isDownload { false };
+    RefPtr<WebCore::FetchEvent> m_event;
     Function<void()> m_cancelledCallback;
+    WebCore::ResourceResponse m_preloadResponse;
+    WebCore::ResourceError m_preloadError;
 };
 
 } // namespace WebKit
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to