Skip to content
Merged
Changes from 17 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
93 changes: 84 additions & 9 deletions docs/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1079,7 +1079,9 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
};
</pre>

A {{ServiceWorkerGlobalScope}} object represents the global execution context of a [=/service worker=]. A {{ServiceWorkerGlobalScope}} object has an associated <dfn export for="ServiceWorkerGlobalScope">service worker</dfn> (a [=/service worker=]). A {{ServiceWorkerGlobalScope}} object has an associated <dfn for="ServiceWorkerGlobalScope">force bypass cache for import scripts flag</dfn>. It is initially unset.
A {{ServiceWorkerGlobalScope}} object represents the global execution context of a [=/service worker=]. A {{ServiceWorkerGlobalScope}} object has an associated <dfn export for="ServiceWorkerGlobalScope">service worker</dfn> (a [=/service worker=]). A {{ServiceWorkerGlobalScope}} object has an associated <dfn for="ServiceWorkerGlobalScope">force bypass cache for import scripts flag</dfn>. 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=]. It is initially unset.
Comment thread
sisidovski marked this conversation as resolved.
Outdated

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.

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 @@ -1578,7 +1580,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"
};
</pre>

<section>
Expand Down Expand Up @@ -3106,19 +3113,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 "<code>serviceworker</code>".
1. If |request|'s [=request/destination=] is either "<code>embed</code>" or "<code>object</code>", then:
1. Return null.
Expand Down Expand Up @@ -3154,7 +3157,28 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
1. If |client| is not null, |response|'s [=response/type=] is "`opaque`", and [=cross-origin resource policy check=] with |request|'s [=request/origin=], |client|, "", and |response|'s [=filtered response/internal response=] returns <b>blocked</b>, then return null.
1. Return |response|.
1. Return null.
1. If |request| is a <a>non-subresource request</a>, |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:
1. Else if |source| is {{RouterSourceEnum/"race-network-and-fetch-handler"}}, and |request|'s [=request/method=] is \`<code>GET</code>\` then:
1. Let |queue| be an empty [=queue=] of [=/response=].
1. Let |raceFetchController| be null.
Comment thread
yoshisatoyanagisawa marked this conversation as resolved.
1. Set |raceResponse|'s [=race response/value=] to "<code>pending</code>".
1. [=map/Set=] |activeWorker|'s [=service worker/global object=]'s [=race response map=][|request|] to |raceResponse|.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be simpler if the race response map is associates with activeWorker (i.e. a service worker) rather than its global scope? Especially as at this point in the algorithm the worker hasn't been started yet, so global object might very well be null.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. How about keep the global scope having the map, and move this [=map/set=] to the step 16.2 in Create Fetch Event and Dispatch? At this point, Run Service Worker was already called to we can expect the global object is ready.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated as above. Let me know if this doesn't solve your concern.

1. Run the following substeps [=in parallel=], but [=abort when=] |controller|'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|.
Comment thread
sisidovski marked this conversation as resolved.
1. Otherwise, set |raceResponse|'s [=race response/value=] to a [=network error=].
1. [=If aborted=] and |raceFetchController| is not null, then:
Comment thread
sisidovski marked this conversation as resolved.
1. [=fetch controller/abort=] |raceFetchController|.
Comment thread
sisidovski marked this conversation as resolved.
Outdated
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. If |request| is a <a>non-subresource request</a>, |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:

Note: If the above is true except |registration|'s [=active worker=]'s <a>set of event types to handle</a> **does not** contain <code>fetch</code>, then the user agent may wish to show a console warning, as the developer's intent isn't clear.

Expand All @@ -3176,9 +3200,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|.
</section>

<section algorithm>
<h3 id="create-fetch-event-and-dispatch-algorithm"><dfn>Create Fetch Event and Dispatch</dfn></h3>
: 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.
Comment thread
sisidovski marked this conversation as resolved.
1. Let |client| be |request|'s [=request/client=].
1. Let |activeWorker| be |registration|'s <a>active worker</a>.
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.
Expand Down Expand Up @@ -3231,11 +3280,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|].
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step is needed to remove the map entry, which is not consumed by Fetch. The fetch handler may not have fetch(e.request) e.g. fallback, offline etc. Otherwise map entries are infinitely added.

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 "<code>pending</code>"
Comment thread
sisidovski marked this conversation as resolved.
Outdated
1. If |raceResponse|'s [=race response/value=] is [=/response=], return |raceResponse|'s [=race response/value=].
Comment thread
sisidovski marked this conversation as resolved.
Outdated
1. Return null.
1. If |handleFetchFailed| is true, then:
1. If |eventHandled| is not null, then [=reject=] |eventHandled| with a "{{NetworkError}}" {{DOMException}} in |workerRealm|.
Expand Down Expand Up @@ -3873,6 +3926,28 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
1. Return true.
1. Return false.
</section>

<section algorithm>
<h3 id="lookup-race-response-algorithm"><dfn export>Lookup Race Response</dfn></h3>

: Input
:: |request|, a [=/request=]
: Output
:: a [=/response=], or null.
Comment thread
sisidovski marked this conversation as resolved.
Outdated

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 <a>Match Service Worker Registration</a> given |storage key| and |url|.
1. If |registration| is null or |registration|'s <a>active worker</a> is null, return null.
1. Else, let |activeWorker| be |registration|'s <a>active worker</a>.
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 "<code>pending</code>"
1. If |entry|'s [=race response/value=] is [=/response=], return |entry|'s [=race response/value=].
1. Return null.
</section>
</section>

<section>
Expand Down