tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 053625368df5b2794fbaa778ba2185d63f8e4ea6
parent e9e6d32de264b2dbf913ca5fe092af86a7ebfc88
Author: Shunya Shishido <sisidovski@chromium.org>
Date:   Thu,  6 Nov 2025 21:34:53 +0000

Bug 1997719 [wpt PR 55810] - Delay SW loader deletion until fetch clone is complete, a=testonly

Automatic update from web-platform-tests
Delay SW loader deletion until fetch clone is complete

When using `race-network-and-fetch-handler`, the
ServiceWorkerMainResourceLoader could be destroyed after the network
response is received, but before the fetch handler has finished cloning
the response body. This could lead to a race condition where the loader
is deleted prematurely.

This change ensures that the loader's lifetime is extended until the
response body has been fully cloned for the fetch handler or the mojo
disconnection to the ServiceWorker. A callback is introduced to signal
the completion of the cloning process or disconnection, and the deletion
logic is updated to wait for this signal before invalidating the loader.

This behavior is gated behind the
`kServiceWorkerStaticRouterRaceRequestFix2` feature flag.

Change-Id: If7ec62b18c99c8fc13faf657a44969a42bf7f82a
Bug: 340949948
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7079632
Reviewed-by: Rakina Zata Amni <rakina@chromium.org>
Reviewed-by: Yoshisato Yanagisawa <yyanagisawa@chromium.org>
Commit-Queue: Shunya Shishido <sisidovski@chromium.org>
Reviewed-by: Keita Suzuki <suzukikeita@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1538932}

--

wpt-commits: f81c4ab37c38e951d924c4f65dcb7d995d9bd5ac
wpt-pr: 55810

Diffstat:
Mtesting/web-platform/tests/service-workers/service-worker/resources/static-router-race-network-and-fetch-handler-sw.js | 33+++++++++++++++++++--------------
Mtesting/web-platform/tests/service-workers/service-worker/static-router-race-network-and-fetch-handler.https.html | 29+++++++++++++++++++++++++++--
2 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/static-router-race-network-and-fetch-handler-sw.js b/testing/web-platform/tests/service-workers/service-worker/resources/static-router-race-network-and-fetch-handler-sw.js @@ -27,23 +27,28 @@ self.addEventListener('activate', e => { e.waitUntil(clients.claim()); }); -self.addEventListener('fetch', function(event) { - recordRequest(event.request); - const url = new URL(event.request.url); - - - // Force slow response - if (url.searchParams.has('sw_slow')) { - const start = Date.now(); - while (true) { - if (Date.now() - start > 200) { - break; +self.addEventListener('fetch', async function(event) { + try { + recordRequest(event.request); + const url = new URL(event.request.url); + // Force slow response + if (url.searchParams.has('sw_slow')) { + const start = Date.now(); + while (true) { + if (Date.now() - start > 200) { + break; + } } } + const nonce = url.searchParams.get('nonce'); + event.respondWith(new Response(nonce)); + // Call `fetch(e.request)` but it's not consumed. + if (url.searchParams.has('call_fetch')) { + await fetch(event.request); + } + } catch (e) { + recordError(e) } - - const nonce = url.searchParams.get('nonce'); - event.respondWith(new Response(nonce)); }); self.addEventListener('message', function(event) { diff --git a/testing/web-platform/tests/service-workers/service-worker/static-router-race-network-and-fetch-handler.https.html b/testing/web-platform/tests/service-workers/service-worker/static-router-race-network-and-fetch-handler.https.html @@ -22,8 +22,9 @@ promise_test(async t => { const iframe = await createIframe(t, `${FRAME_SRC}?nonce=${rnd}&server_slow`); // Expect the response from the fetch handler. assert_equals(iframe.contentWindow.document.body.innerText, rnd); - const {requests} = await get_info_from_worker(worker); + const {requests, errors} = await get_info_from_worker(worker); assert_equals(requests.length, 1); + assert_equals(errors.length, 0); }, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the fetch handler response is faster than the server response'); promise_test(async t => { @@ -33,13 +34,37 @@ promise_test(async t => { // Expect the response from the netowrk request. assert_equals(iframe.contentWindow.document.body.innerText, "Network with GET request"); // Ensure the fetch handler is also executed. - const {requests} = await get_info_from_worker(worker); + const {requests, errors} = await get_info_from_worker(worker); assert_equals(requests.length, 1); + assert_equals(errors.length, 0); }, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the server reseponse is faster than the fetch handler'); promise_test(async t => { const rnd = randomString(); const worker = await registerAndActivate(t, ROUTER_KEY, SW_SRC); + const iframe = await createIframe(t, `${FRAME_SRC}?nonce=${rnd}&server_slow&call_fetch`); + // Expect the response from the fetch handler. + assert_equals(iframe.contentWindow.document.body.innerText, rnd); + const {requests, errors} = await get_info_from_worker(worker); + assert_equals(requests.length, 1); + assert_equals(errors.length, 0); +}, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the fetch handler response is faster than the server response while fetch() is triggered inside the fetch handler'); + +promise_test(async t => { + const rnd = randomString(); + const worker = await registerAndActivate(t, ROUTER_KEY, SW_SRC); + const iframe = await createIframe(t, `${FRAME_SRC}?nonce=${rnd}&sw_slow&call_fetch`); + // Expect the response from the netowrk request. + assert_equals(iframe.contentWindow.document.body.innerText, "Network with GET request"); + // Ensure the fetch handler is also executed. + const {requests, errors} = await get_info_from_worker(worker); + assert_equals(requests.length, 1); + assert_equals(errors.length, 0); +}, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the server reseponse is faster than the fetch handler while fetch() is triggered inside the fetch handler'); + +promise_test(async t => { + const rnd = randomString(); + const worker = await registerAndActivate(t, ROUTER_KEY, SW_SRC); const iframe = await createIframe(t, FRAME_SRC); // Expect the response from the fetch handler. const response = await iframe.contentWindow.fetch(`?nonce=${rnd}&server_slow`);