Skip to content

Add race-network-and-cache source to static routing api. #1764

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 82 additions & 20 deletions docs/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,7 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/

A {{ServiceWorkerGlobalScope}} object has an associated <dfn for="ServiceWorkerGlobalScope">race response map</dfn> which is an [=ordered map=] where the [=map/keys=] are [=/requests=] and the [=map/values=] are [=race response=].

A <dfn id="dfn-race-response">race response</dfn> is a [=struct=] used to contain the network response when {{RouterSourceEnum/"race-network-and-fetch-handler"}} performs. It has a <dfn for="race response">value</dfn>, which is a [=/response=], "<code>pending</code>", or null.
A <dfn id="dfn-race-response">race response</dfn> is a [=struct=] used to contain the network response when {{RouterSourceEnum/"race-network-and-fetch-handler"}} or {{RouterSourceEnum/"race-network-and-cache"}} performs. It has a <dfn for="race response">value</dfn>, which is a [=/response=], "<code>pending</code>", or null.

Note: {{ServiceWorkerGlobalScope}} object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully <a>registered</a>, 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=].

Expand Down Expand Up @@ -1591,14 +1591,16 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/

dictionary RouterSourceDict {
DOMString cacheName;
DOMString raceNetworkAndCacheCacheName;
};

enum RunningStatus { "running", "not-running" };
enum RouterSourceEnum {
"cache",
"fetch-event",
"network",
"race-network-and-fetch-handler"
"race-network-and-fetch-handler",
"race-network-and-cache"
};
</pre>

Expand Down Expand Up @@ -3220,43 +3222,73 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
1. Return null.
1. Else if |source| is {{RouterSourceEnum/"cache"}}, or |source|["{{RouterSourceDict/cacheName}}"] [=map/exists=], then:
1. If |shouldSoftUpdate| is true, then [=in parallel=] run the [=Soft Update=] algorithm with |registration|.
1. [=map/For each=] |cacheName| &#x2192; |cache| of the |registration|'s [=service worker registration/storage key=]'s [=name to cache map=].
1. If |source|["{{RouterSourceDict/cacheName}}"] [=map/exists=] and |source|["{{RouterSourceDict/cacheName}}"] [=string/is=] not |cacheName|, [=continue=].
1. Let |requestResponses| be the result of running [=Query Cache=] with |request|, a new {{CacheQueryOptions}}, and |cache|.
1. If |requestResponses| is an empty [=list=], return null.
1. Else:
1. Let |requestResponse| be the first element of |requestResponses|.
1. Let |response| be |requestResponse|'s response.
1. Let |globalObject| be |activeWorker|'s [=service worker/global object=].
1. If |globalObject| is null:
1. Set |globalObject| to the result of running [=Setup ServiceWorkerGlobalScope=] with |activeWorker|.
1. If |globalObject| is null, return null.

Note: This only creates a ServiceWorkerGlobalScope because CORS checks require that. It is not expected that implementations will actually create a ServiceWorkerGlobalScope here.

1. If |response|'s [=response/type=] is "`opaque`", and [=cross-origin resource policy check=] with |globalObject|'s [=environment settings object/origin=], |globalObject|, "", and |response|'s [=filtered response/internal response=] returns <b>blocked</b>, then return null.
1. Return |response|.
1. Return null.
1. Let |response| be the result of running [=Query Static Router Cache for Response=] with |request|, |source|, "{{RouterSourceDict/cacheName}}", and |registration|.
1. If |response| is null, return null.
1. Return |response|.
1. Else if |source| is {{RouterSourceEnum/"race-network-and-fetch-handler"}}, and |request|'s [=request/method=] is \`<code>GET</code>\` then:
1. If |shouldSoftUpdate| is true, then [=in parallel=] run the [=Soft Update=] algorithm with |registration|.
1. Let |queue| be an empty [=queue=] of [=/response=].
1. Let |raceFetchController| be null.
1. Let |raceResponse| be a [=race response=] whose [=race response/value=] is "<code>pending</code>".
1. Let |networkFetchCompleted| be false.
1. Let |fetchHandlerCompleted| be false.
1. Run the following substeps [=in parallel=], but [=abort when=] |fetchController|'s [=fetch controller/state=] is "<code>terminated</code>" or "<code>aborted</code>":
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. Set |networkFetchCompleted| to true.
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. Set |networkFetchCompleted| to true.
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. Set |fetchHandlerCompleted| to true.
1. Wait until any of the following are true:
1. |queue| is not empty.
1. Both |networkFetchCompleted| and |fetchHandlerCompleted| are true.
1. If |queue| is empty, then:
1. If |raceResponse|'s [=race response/value=] is a [=/response=], return |raceResponse|'s [=race response/value=].
1. If |raceResponse|'s [=race response/value=] is a [=network error=], return a [=network error=].
1. Return null.
1. Return the result of [=dequeue=] |queue|.
1. If |source| is {{RouterSourceEnum/"race-network-and-cache"}}, or |source|["{{RouterSourceDict/raceNetworkAndCacheCacheName}}"] [=map/exists=], and |request|'s [=request/method=] is \`<code>GET</code>\`, then:
1. If |shouldSoftUpdate| is true, then [=in parallel=] run the [=Soft Update=] algorithm with |registration|.
1. Let |queue| be an empty [=queue=] of [=/response=].
1. Let |raceFetchController| be null.
1. Let |raceResponse| be a [=race response=] whose [=race response/value=] is "<code>pending</code>".
1. Let |networkFetchCompleted| be false.
1. Let |cacheLookupCompleted| be false.
1. Run the following substeps [=in parallel=], but [=abort when=] |fetchController|'s [=fetch controller/state=] is "<code>terminated</code>" or "<code>aborted</code>":
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. Set |networkFetchCompleted| to true.
1. [=If aborted=] and |raceFetchController| is not null, then:
1. If |raceFetchController|'s [=fetch controller/state=] is not "<code>terminated</code>", [=fetch controller/abort=] |raceFetchController|.
1. Set |raceResponse| to a [=race response=] whose [=race response/value=] is null.
1. Set |networkFetchCompleted| to true.
1. Resolve |preloadResponse| with undefined.
1. Run the following substeps [=in parallel=]:
1. Let |response| be the result of running [=Query Static Router Cache for Response=] with |request|, |source|, "{{RouterSourceDict/raceNetworkAndCacheCacheName}}", and |registration|.
1. If |response| is not null:
1. [=queue/Enqueue=] |response| to |queue|.
1. If |raceFetchController| is not null, [=fetch controller/abort=] |raceFetchController|.
1. Set |cacheLookupCompleted| to true.
1. Wait until any of the following are true:
1. |queue| is not empty.
1. Both |networkFetchCompleted| and |cacheLookupCompleted| are true.
1. If |queue| is empty, then:
1. If |raceResponse|'s [=race response/value=] is a [=/response=], return |raceResponse|'s [=race response/value=].
1. If |raceResponse|'s [=race response/value=] is a [=network error=], return a [=network error=].
1. Return null.
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 \`<code>GET</code>\`, |registration|'s [=active worker=]'s [=set of event types to handle=] [=set/contains=] <code>fetch</code>, and |registration|'s [=active worker=]'s [=all fetch listeners are empty flag=] is not set then:
Expand Down Expand Up @@ -4097,6 +4129,36 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
1. If |entry|'s [=race response/value=] is [=/response=], return |entry|'s [=race response/value=].
1. Return null.
</section>

<section algorithm>
<h3 id="query-static-router-cache-for-response-algorithm"><dfn>Query Static Router Cache for Response</dfn></h3>

: Input
:: |request|, a [=/request=]
:: |source|, a [=map=]
:: |cacheNameKey|, a [=string=]
:: |registration|, a [=/service worker registration=]
: Output
:: a [=/response=] or null

1. [=map/For each=] |cacheName| &#x2192; |cache| of the |registration|'s [=service worker registration/storage key=]'s [=name to cache map=].
1. If |source|[|cacheNameKey|] [=map/exists=] and |source|[|cacheNameKey|] [=string/is=] not |cacheName|, [=continue=].
1. Let |requestResponses| be the result of running [=Query Cache=] with |request|, a new {{CacheQueryOptions}}, and |cache|.
1. If |requestResponses| is an empty [=list=], return null.
1. Else:
1. Let |requestResponse| be the first element of |requestResponses|.
1. Let |response| be |requestResponse|'s response.
1. Let |globalObject| be |activeWorker|'s [=service worker/global object=].
1. If |globalObject| is null:
1. Set |globalObject| to the result of running [=Setup ServiceWorkerGlobalScope=] with |activeWorker|.
1. If |globalObject| is null, return null.

Note: This only creates a ServiceWorkerGlobalScope because CORS checks require that. It is not expected that implementations will actually create a ServiceWorkerGlobalScope here.

1. If |response|'s [=response/type=] is "`opaque`", and [=cross-origin resource policy check=] with |globalObject|'s [=environment settings object/origin=], |globalObject|, "", and |response|'s [=filtered response/internal response=] returns <b>blocked</b>, then return null.
1. Return |response|.
1. Return null.
</section>
</section>

<section>
Expand Down