Open Bug 1928887 Opened 20 days ago Updated 16 days ago

Asynchronous call of FetchEvent.respondWith silently fails

Categories

(Core :: DOM: Service Workers, defect)

Firefox 133
defect

Tracking

()

UNCONFIRMED

People

(Reporter: pigido6116, Unassigned, NeedInfo)

Details

Steps to reproduce:

In the latest Firefox Developer Edition (133.0b3), start a Service Worker which calls FetchEvent.respondWith asynchronously (example code below).

Actual results:

It failed silently. No error was raised.

Expected results:

It should have failed with an error message.

As far as I can tell, Service Worker spec defines that FetchEvent.respondWith cannot be called in an asynchronous context and if it is, it will release the thread. It's very confusing for the thread to be released silently because afterwards, the browser defaults to calling the internet directly and so it appears no different from normal.

In Chromium, the error thrown in this case is "InvalidStateError: Failed to execute 'respondWith' on 'FetchEvent': The event handler is already finished.".

Component: Untriaged → DOM: Service Workers
Product: Firefox → Core

Example Service Worker code for reproduction

self.addEventListener("install", async event => {
  console.log("V1 installing…");
});

self.addEventListener("fetch", async event => {
  console.log("fetching");
  
  let exPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(true);
    }, 0);
  });
  //await exPromise;
 
  console.log("request", event.request);
  let response;
  if (event.request.url === "http://localhost:8000/blahblah") {
    response = fetch("https://cdn.jwplayer.com/libraries/Xt5rBv5b.js");
  } else {
    response = fetch(event.request);
  }
  console.log("response", response);
  event.respondWith(response);
});

self.addEventListener("activate", event => {
  console.log("V1 now ready to handle fetches!");
  
  event.waitUntil(self.clients.claim());
});

self.addEventListener("message", async event => {
  console.log(event.data)
});

If fetch("blahblah") is called in the client, the JavaScript library is fetched and returned as expected. Now, uncomment //await exPromise; and fetch("blahblah") will 404 because await releases the thread before the JavaScript library can be fetched and returned. This releasing of the thread is expected per Service Worker spec but Firefox releases the thread silently. Chromium will throw "InvalidStateError: Failed to execute 'respondWith' on 'FetchEvent': The event handler is already finished."

As you mentioned, this is expected behavior, covered by Web Platform Tests which all browsers currently pass: https://wpt.fyi/results/service-workers/service-worker/fetch-event-async-respond-with.https.html?label=master&label=experimental&aligned&q=fetch-event-async-respond-with.https.html

How did you check Firefox does not throw error here? Note that Firefox doesn't show console messages into usual devtools console tab right now, you may need to confirm by inspecting service worker separately in about:debugging.

Flags: needinfo?(pigido6116)

Indeed we definitely throw consistent with the spec:

void FetchEvent::RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv) {
  if (!GetDispatchFlag() || mWaitToRespond) {
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return;
  }
You need to log in before you can comment on or make changes to this bug.