diff --git a/docs/index.bs b/docs/index.bs
index b0db5169..a27c39d5 100644
--- a/docs/index.bs
+++ b/docs/index.bs
@@ -1082,7 +1082,9 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
};
- A {{ServiceWorkerGlobalScope}} object represents the global execution context of a [=/service worker=]. A {{ServiceWorkerGlobalScope}} object has an associated service worker (a [=/service worker=]). A {{ServiceWorkerGlobalScope}} object has an associated force bypass cache for import scripts flag. It is initially unset.
+ A {{ServiceWorkerGlobalScope}} object represents the global execution context of a [=/service worker=]. A {{ServiceWorkerGlobalScope}} object has an associated service worker (a [=/service worker=]). A {{ServiceWorkerGlobalScope}} object has an associated force bypass cache for import scripts flag. A {{ServiceWorkerGlobalScope}} object has an associated race response map which is an [=ordered map=] where the [=map/keys=] are [=/requests=] and the [=map/values=] are [=race response=]. It is initially unset.
+
+ A race response is a [=struct=] used to contain the network response when {{RouterSourceEnum/"race-network-and-fetch-handler"}} performs. It has a value, which is a [=/response=], "pending", or null.
Note: {{ServiceWorkerGlobalScope}} object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a [=/service worker=] is started, kept alive and killed by their relationship to events, not [=/service worker clients=]. Any type of synchronous requests must not be initiated inside of a [=/service worker=].
@@ -1581,7 +1583,12 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
};
enum RunningStatus { "running", "not-running" };
- enum RouterSourceEnum { "cache", "fetch-event", "network" };
+ enum RouterSourceEnum {
+ "cache",
+ "fetch-event",
+ "network",
+ "race-network-and-fetch-handler"
+ };
@@ -3142,19 +3149,15 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
:: |controller|, a [=fetch controller=]
:: |useHighResPerformanceTimers|, a boolean
: Output
- :: |response|, a [=/response=]
+ :: a [=/response=]
- 1. Let |handleFetchFailed| be false.
- 1. Let |respondWithEntered| be false.
- 1. Let |eventCanceled| be false.
- 1. Let |response| be null.
1. Let |registration| be null.
1. Let |client| be |request|'s [=request/client=].
1. Let |reservedClient| be |request|'s [=request/reserved client=].
1. Let |preloadResponse| be a new [=promise=].
1. Let |workerRealm| be null.
- 1. Let |eventHandled| be null.
1. Let |timingInfo| be a new [=service worker timing info=].
+ 1. Let |raceResponse| be a [=race response=] whose [=race response/value=] is null.
1. Assert: |request|'s [=request/destination=] is not "serviceworker".
1. If |request|'s [=request/destination=] is either "embed" or "object", then:
1. Return null.
@@ -3202,6 +3205,26 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
1. If |response|'s [=response/type=] is "`opaque`", and [=cross-origin resource policy check=] with |settingsObject|'s [=environment settings object/origin=], |settingsObject|, "", and |response|'s [=filtered response/internal response=] returns blocked, then return null.
1. Return |response|.
1. Return null.
+ 1. Else if |source| is {{RouterSourceEnum/"race-network-and-fetch-handler"}}, and |request|'s [=request/method=] is \`GET\` then:
+ 1. Let |queue| be an empty [=queue=] of [=/response=].
+ 1. Let |raceFetchController| be null.
+ 1. Set |raceResponse|'s [=race response/value=] to "pending".
+ 1. Run the following substeps [=in parallel=], but [=abort when=] |controller|'s [=fetch controller/state=] is "terminated" or "aborted":
+ 1. Set |raceFetchController| to the result of calling [=fetch=] given |request|, with [=fetch/processResponse=] set to the following steps given a [=/response=] |raceNetworkRequestResponse|:
+ 1. If |raceNetworkRequestResponse|'s [=response/status=] is [=ok status=], then:
+ 1. Set |raceResponse|'s [=race response/value=] to |raceNetworkRequestResponse|.
+ 1. [=queue/Enqueue=] |raceNetworkRequestResponse| to |queue|.
+ 1. Otherwise, set |raceResponse|'s [=race response/value=] to a [=network error=].
+ 1. [=If aborted=] and |raceFetchController| is not null, then:
+ 1. [=fetch controller/Abort=] |raceFetchController|.
+ 1. Set |raceResponse| to a [=race response=] whose [=race response/value=] is null.
+ 1. Resolve |preloadResponse| with undefined.
+ 1. Run the following substeps [=in parallel=]:
+ 1. Let |fetchHandlerResponse| be the result of [=Create Fetch Event and Dispatch=] with |request|, |registration|, |useHighResPerformanceTimers|, |timingInfo|, |workerRealm|, |reservedClient|, |preloadResponse|, and |raceResponse|.
+ 1. If |fetchHandlerResponse| is not null and not a [=network error=], and |raceFetchController| is not null, [=fetch controller/abort=] |raceFetchController|.
+ 1. [=queue/Enqueue=] |fetchHandlerResponse| to |queue|.
+ 1. Wait until |queue| is not empty.
+ 1. Return the result of [=dequeue=] |queue|.
1. Assert: |source| is "{{RouterSourceEnum/fetch-event}}"
1. If |request| is a [=navigation request=], |registration|'s [=navigation preload enabled flag=] is set, |request|'s [=request/method=] is \`GET\`, |registration|'s [=active worker=]'s [=set of event types to handle=] [=set/contains=] fetch, and |registration|'s [=active worker=]'s [=all fetch listeners are empty flag=] is not set then:
@@ -3225,6 +3248,34 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
1. Let |deserializedError| be the result of [=deserialize a serialized abort reason=] given null and |workerRealm|.
1. [=fetch controller/Abort=] |preloadFetchController| with |deserializedError|.
1. Else, resolve |preloadResponse| with undefined.
+ 1. Return the result of [=Create Fetch Event and Dispatch=] with |request|, |registration|, |useHighResPerformanceTimers|, |timingInfo|, |workerRealm|, |reservedClient|, |preloadResponse|, and |raceResponse|.
+
+
+
+ Create Fetch Event and Dispatch
+ : Input
+ :: |request|, a [=/request=]
+ :: |registration|, a [=/service worker registration=]
+ :: |useHighResPerformanceTimers|, a boolean
+ :: |timingInfo|, a [=service worker timing info=]
+ :: |workerRealm|, a [=relevant realm=] of the [=service worker/global object=]
+ :: |reservedClient|, a [=request/reserved client=]
+ :: |preloadResponse|, a [=promise=]
+ :: |raceResponse|, a [=race response=]
+ : Output
+ :: a [=/response=]
+
+ 1. Let |response| be null.
+ 1. Let |eventCanceled| be false.
+ 1. Let |client| be |request|'s [=request/client=].
+ 1. Let |activeWorker| be |registration|'s active worker.
+ 1. Let |eventHandled| be null.
+ 1. Let |handleFetchFailed| be false.
+ 1. Let |respondWithEntered| be false.
+ 1. Let |shouldSoftUpdate| be true if any of the following are true, and false otherwise:
+ * |request| is a [=non-subresource request=].
+ * |request| is a [=subresource request=] and |registration| is [=stale=].
+ 1. Let |raceResponseMap| be |activeWorker|'s [=service worker/global object=]'s [=race response map=].
1. If the result of running the [=Should Skip Event=] algorithm with "fetch" and |activeWorker| is true, then:
1. If |shouldSoftUpdate| is true, then [=in parallel=] run the [=Soft Update=] algorithm with |registration|.
1. Return null.
@@ -3241,6 +3292,7 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
1. Else:
1. Set |workerRealm| to the [=relevant realm=] of the |activeWorker|'s [=service worker/global object=].
1. Set |eventHandled| to [=a new promise=] in |workerRealm|.
+ 1. If |raceResponse| is not null, [=map/set=] |raceResponseMap|[|request|] to |raceResponse|.
1. [=Queue a task=] |task| to run the following substeps:
1. Let |e| be the result of creating an event with {{FetchEvent}}.
1. Let |controller| be a [=new=] {{AbortController}} object with |workerRealm|.
@@ -3277,11 +3329,15 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
1. Wait for |task| to have executed or for |handleFetchFailed| to be true.
1. If |shouldSoftUpdate| is true, then [=in parallel=] run the [=Soft Update=] algorithm with |registration|.
+ 1. If |raceResponseMap|[|request|] [=map/exists=], [=map/remove=] |raceResponseMap|[|request|].
1. If |respondWithEntered| is false, then:
1. If |eventCanceled| is true, then:
1. If |eventHandled| is not null, then [=reject=] |eventHandled| with a "{{NetworkError}}" {{DOMException}} in |workerRealm|.
2. Return a [=network error=].
1. If |eventHandled| is not null, then [=resolve=] |eventHandled|.
+ 1. If |raceResponse|'s [=race response/value=] is not null, then:
+ 1. Wait until |raceResponse|'s [=race response/value=] is not "pending".
+ 1. If |raceResponse|'s [=race response/value=] is a [=/response=], return |raceResponse|'s [=race response/value=].
1. Return null.
1. If |handleFetchFailed| is true, then:
1. If |eventHandled| is not null, then [=reject=] |eventHandled| with a "{{NetworkError}}" {{DOMException}} in |workerRealm|.
@@ -3922,6 +3978,28 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
1. Return true.
1. Return false.
+
+
+ Lookup Race Response
+
+ : Input
+ :: |request|, a [=/request=]
+ : Output
+ :: a [=/response=] or null
+
+ 1. If |request|'s [=request/reserved client=] is null, return null.
+ 1. Let |storage key| be the result of running [=obtain a storage key=] given |request|'s [=request/reserved client=].
+ 1. Let |registration| be the result of running Match Service Worker Registration given |storage key| and |url|.
+ 1. If |registration| is null or |registration|'s active worker is null, return null.
+ 1. Else, let |activeWorker| be |registration|'s active worker.
+ 1. Let |map| be |activeWorker|'s [=service worker/global object=]'s [=race response map=].
+ 1. If |map|[|request|] [=map/exists=], then:
+ 1. Let |entry| be |map|[|request|].
+ 1. [=map/Remove=] |map|[|request|].
+ 1. Wait until |entry|'s [=race response/value=] is not "pending"
+ 1. If |entry|'s [=race response/value=] is [=/response=], return |entry|'s [=race response/value=].
+ 1. Return null.
+