Skip to content
Merged
Changes from 12 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,7 @@ 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 strings and the [=map/values=] are <a>promises</a>. It is initially unset.

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 +1578,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 +3111,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 null.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Here it would be: Set |raceResponse| to a [=race response=] whose [=race response/value=] is 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.

I believe this is Let?

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 +3155,25 @@ 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. 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. Set |raceResponse| to [=a new promise=].
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I'm not sure promises work well here. Promises can only store JavaScript or IDL objects, like Response, but you are instead resolving them with a response. That isn't allowed.

You could try to wrap the response into a Response. I guess that would mean creating a new Response whose response is set to the response. But as explained in a comment later on, I don't think that is the right architecture. In general, I don't think using promises (which are main thread objects, very tied to JavaScript) inside this background-thread processing is a good idea.

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.

Tried to update not to use promise here. Does that look better?

1. If |raceNetworkRequestResponse|'s [=response/status=] is [=ok status=], then:
1. Resolve |raceResponse| with |raceNetworkRequestResponse|.
Comment thread
sisidovski marked this conversation as resolved.
Outdated
1. [=queue/enqueue=] |raceNetworkRequestResponse| to |queue|.
Comment thread
sisidovski marked this conversation as resolved.
Outdated
1. Otherwise, reject |raceResponse| with a `TypeError`.
Comment thread
sisidovski marked this conversation as resolved.
Outdated
1. [=If aborted=] and |raceFetchController| is not null, [=fetch controller/abort=] |raceFetchController|.
1. Resolve |preloadResponse| with undefined.
1. Run the following substeps [=in parallel=]:
1. Let |fetchHandlerResponse| to the result of [=Create Fetch Event and Dispatch=] with |request|, |registration|, |useHighResPerformanceTimers|, |timingInfo|, |workerRealm|, |reservedClient|, |preloadResponse|, and |raceResponse|.
Comment thread
sisidovski marked this conversation as resolved.
Outdated
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,6 +3195,30 @@ 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=].
Comment thread
sisidovski marked this conversation as resolved.
Outdated
:: |workerRealm|, a [=relevant realm=] of the [=service worker/global object=].
Comment thread
sisidovski marked this conversation as resolved.
Outdated
:: |reservedClient|, a [=request/reserved client=].
Comment thread
sisidovski marked this conversation as resolved.
Outdated
:: |preloadResponse| a [=promise=].
Comment thread
sisidovski marked this conversation as resolved.
Outdated
:: |raceResponse| a [=promise=].
Comment thread
sisidovski marked this conversation as resolved.
Outdated
: 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=].
Expand All @@ -3195,6 +3238,11 @@ 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, then:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is it possible raceResponse will be set to a promise in step 13.4.3.1.1 of Handle Fetch, but never resolved with a response by step 13.4.3.1.2.1? Or, it will be rejected because of the fetch abort that occurs in step 13.4.4?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Now it might be "pending", I think? The map does not say it is allowed to contain "pending", but maybe it should be expanded to allow that?

1. Let |map| be |activeWorker|'s [=service worker/global object=]'s [=race response map=].
1. Let |token| be the result of [=generating a random UUID=].
1. [=map/Set=] |map|[|token|] to |raceResponse|.
1. Set |request|'s [=request/service-workers race token=] to |token|.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is it possible to just make the map keyed by requests, instead of strings? Then you don't need this token setup.

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.

Is it possible to get the map entry by using a struct (or object) as a key? If so that would be feasible.
On the other hand, the implementation side may become a bit difficult due to the type inconsistency of request.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Yes. In specs maps can be keyed by anything. There's no need to change the implementation; as long as the spec is observably equivalent, it is OK for them to depart.

But, be sure to distinguish between requests and Requests in the spec...

1. [=Queue a task=] |task| to run the following substeps:
1. Let |e| be the result of <a>creating an event</a> with {{FetchEvent}}.
1. Let |controller| be a [=new=] {{AbortController}} object with |workerRealm|.
Expand Down Expand Up @@ -3236,6 +3284,10 @@ spec: storage; urlPrefix: https://storage.spec.whatwg.org/
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| is not null, then:
1. [=promise/React=] 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.

You can't return from inside the react steps. Also, as discussed above, there is a type mismatch here: promises can only hold JavaScript objects, and you need to return a response, not a Response.

1. If |raceResponse| was fulfilled with value |v|, return |v|.
1. If |raceResponse| was rejected, return [=network error=].
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 +3925,29 @@ 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
:: |key|, a string
:: |reservedClient|, [=request/reserved client=]
:: |url|, [=request/url=]
: Output
:: a [=promise=].

1. If |reservedClient| is null, return null.
1. Let |storage key| be the result of running [=obtain a storage key=] given |reservedClient|.
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|[|key|] [=map/exist=], then:
1. Let |entry| be |map|[|key|].
1. [=map/Remove=] |map|[|key|].
1. Return |entry|.
1. Otherwise, return null.
</section>
</section>

<section>
Expand Down