When talking about network requests that potentially involve ServiceWorkers, there's really 2 phases of operation:
- When a ServiceWorker may be involved. Step 3 of HTTP fetch (https://fetch.spec.whatwg.org/#http-fetch) calls out to the ServiceWorker spec at https://w3c.github.io/ServiceWorker/#handle-fetch to potentially intercept the request and never go to the network.
- When the request is definitely going to the network which is at the subsequent step 4 of HTTP fetch (https://fetch.spec.whatwg.org/#http-fetch).
State-wise, we use the load flag of nsIChannel::LOAD_BYPASS_SERVICE_WORKER when originating a request and per spec the load should never be intercepted by a ServiceWorker, or after we've decided that a ServiceWorker should potentially be involved because nsINetworkInterceptController.shouldPrepareForIntercept has returned true but we reset interception because the ServiceWorker didn't handle the fetch, and so we redirect to a network channel and need to make sure we don't try and involve the SW a 2nd time.
While it is appropriate to make sure WebExtensions are able to intercept requests to ServiceWorkers for phase 1, I think it makes sense that only the
webRequest API or similar handle that case. It seems like the network proxy API at https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/onRequest only wants to be involved during phase 2.
I think the fundamental problem here is that we're in phase 1 until nsHttpChannel::Connect() is called, which is the code that calls ShouldIntercept(). However, the proxy code is invoked during nsHttpChannel::AsyncOpenFinal() which happens strictly before that. Specifically, AsyncOpenFinal is succeeded by BeginConnect(), BeginConnectActual(), ContinueBeginConnectWithResult(), PrepareToConnect(), OnBeforeConnect(), ContinueOnBeforeConnect(), and only then Connect().
I wonder if the nsHttpChannel state machine should perhaps be calling ShouldPrepareForIntercept earlier? (needinfo for :mayhemer) It's not clear that many of the steps preceding Connect() make sense if a ServiceWorker will be consulted, and it's not clear that there's a way for the proxy logic to filter out the request without knowing the result of ShouldPrepareForIntercept.