-
Notifications
You must be signed in to change notification settings - Fork 336
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
Add abort reason to abort fetch #1343
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I think this integration is more complex and it might be best to build on top of @noamr's #1329.
In particular, the problem is this line:
Terminate the ongoing fetch with the aborted flag set.
That in turn is used to cancel the stream with an "AbortError
" deep in the overall fetch algorithm. What we want to do instead is use the reason there.
fetch.bs
Outdated
<li><p>If <var>error</var> is not given, let <var>error</var> be an | ||
"<code><a exception>AbortError</a></code>" {{DOMException}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error is always given I think, but it can be undefined. I think the text here and in Streams suggest we should have this primitive in DOM.
Something like
To get an error for an abort reason, given a JavaScript value reason, run these steps:
- If reason is undefined, then return a new "
AbortError
"DOMException
.- Return reason.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative might be to pass the signal on and then we define
The error of an
AbortSignal
object signal is ...
That might make it a bit easier to use. I.e., callers can say "throw signal's error".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But can it ever be undefined? It seems both AbortController#abort
and static AbortSignal.abort
sets the reason if undefined.
I think that's not needed because the response body is errored in https://whatpr.org/fetch/1343.html#abort-fetch, and this PR already gives the abort reason to the procedure. The ongoing fetch is terminated but the error objects in "if aborted" steps don't matter as long as #abort-fetch is already called. |
Ah yes, see also #1187. It doesn't make a whole lot of sense to me that we have two places to cover the same requirement. And the place this PR is addressing it in is the place I propose we remove to avoid redundancy. |
@smaug---- raised an interesting question. What happens if the signal enters a service worker? We'd have to serialize/deserialize the reason, right? That's also why the "Terminate the ongoing fetch with the aborted flag set." aspect is important here. |
That seems ideal, and kind of nice as a developer communication channel. But, the plumbing might get pretty complicated, and it might not be worth the extra spec/implementation/test work. The alternative is just saying that cross-realm aborting is special and we censor any abort reasons to " At a first glance that would require storing the serialized form of the fetch error on the request (?) object, and then in places like https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm step 24.3.19 deserializing and using that to signal abort. As an example of the kind of fun we'd have to deal with, recall that deserialization can fail if there's not enough memory to allocate the appropriate ArrayBuffer. So we'd have to handle that case. |
What we do for transferring abort reasons in streams is that we try to serialise them, but if the platform doesn't know how to serialise it we end up with an empty object. Since ECMAScript knows how to serialise Error types this works reasonably well for streams. But somehow it seems worse to end up with an empty object as an abort reason in fetch. So I have a preference for censoring it to an |
I guess when either serialization or deserialization ends up throwing we can pass on undefined and then do the undefined -> new "AbortError" DOMException trick. It would be nice if this was aligned with Streams though. I'm not entirely sure how the plumbing for this would work and that's probably due to the message passing that needs to happen being rather implicit. Thoughts:
|
I think the cleanest way to handle this is making
To transfer an Making
I would find it weird if transferring I guess we could not make
It won't necessarily throw. You may still get back an empty object, because it's merely serializing all the own properties. class MyError {
get message() {
return "Oops!";
}
}
const original = new MyError();
original.message; // -> "Oops!"
const clone = structuredClone(original);
clone.message; // -> undefined |
I think in the case where serialization and deserialization succeed we shouldn't temper with I'm not sure about adding public APIs for serializing/transferring |
Is this (i.e., aborting without reason) currently specified? https://fetch.spec.whatwg.org/#http-fetch handles a request, but AbortSignal is not on it so I don't know how to tell the fetch is aborted to the service worker. |
It's not well-defined at the moment, but it's intended to "work". See web-platform-tests/wpt#6484 (comment) for a great explanation by @jakearchibald. There's additional context in #523 and w3c/ServiceWorker#1178. The gist of it is that it is based upon the hand-wavy termination concept and the "aborted flag". Now, #1329 should improve that setup, but looking at this again it seems that service workers need more attention there. That is, how do we pass the state on to service workers? Perhaps "handle fetch" should get a controller as well? |
In that case can we keep being hand-wavy about service workers for now, and fix it later altogether? |
Note that currently you can infer from the text what is supposed to happen, albeit not in a great way. E.g., it is somewhat clear the |
@yutakahirano also note that @noamr is making great progress on #1329 and per our discussion on Matrix we have a general idea of how to forward the termination to service workers. After which this should be relatively straightforward. |
My mental model for the service worker interception is that you are transferring the request from the initiator context to the service worker. Hence it feels natural that
If #1329 will be landed soon I'm fine with waiting for the change. |
The spec PR for this (whatwg/fetch#1343) hasn't been finalized yet because some questions regarding service worker integration are not settled yet, but everything else seems settled, and it seems best to not wait for another Deno version to support abort reasons in the fetch API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with nits, very nice!
Co-authored-by: Domenic Denicola <[email protected]>
Hi @annevk, would you be able to take a look at this when you have time? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks so much for pushing this forward! I think there are still some things to improve with how fetch()
and the fetch algorithm interact, but overall this is looking rather good.
fetch.bs
Outdated
@@ -231,6 +231,9 @@ lt="authentication entry">authentication entries</a> (for HTTP authentication). | |||
|
|||
<dt><dfn for="fetch controller">report timing steps</dfn> (default null) | |||
<dd>Null or an algorithm accepting a <a for=/>global object</a>. | |||
|
|||
<dt><dfn for="fetch controller">serialized abort reason</dfn> (default null) | |||
<dd>Null or a serialization from [$StructuredSerialize$]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: might want to add a source comment here about this being a Record.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with nit!
…and deal with realms a bit better
Apologies, my last feedback round was misguided. There was no reason to switch from null to undefined as the null is not exposed to JS. And as @domenic noted serialization and deserialization are different operations so at most two algorithms could share more code. So I've reverted the null to undefined change. I have implemented some code sharing for deserialization and as part of that I found a bug. The networking layer doesn't have a "this" so for now I've gone with an implementation-defined realm and a comment that we really need to clean all of that up in the future. I think it's good to go now though. Anyone any final feedback on this? It seems the tests are ready to land and I think we can assume implementation support as this was always part of the plan. |
Looks good to me -- thank you, @annevk! |
I found some time to look at it again, another LGTM From me. |
Thanks all! |
Add test cases to check the functionality of AbortSignal's abort reason when aborting fetch, including serialization and that the service worker can observe the reason. See whatwg/fetch#1343 for accompanying spec changes.
… reason, a=testonly Automatic update from web-platform-tests Fetch: Add tests for AbortSignal's abort reason (#35374) Add test cases to check the functionality of AbortSignal's abort reason when aborting fetch, including serialization and that the service worker can observe the reason. See whatwg/fetch#1343 for accompanying spec changes. -- wpt-commits: 0e5f85c08e05fb1b9b67fb12c4d7c0de77a4ee9b wpt-pr: 35374
… reason, a=testonly Automatic update from web-platform-tests Fetch: Add tests for AbortSignal's abort reason (#35374) Add test cases to check the functionality of AbortSignal's abort reason when aborting fetch, including serialization and that the service worker can observe the reason. See whatwg/fetch#1343 for accompanying spec changes. -- wpt-commits: 0e5f85c08e05fb1b9b67fb12c4d7c0de77a4ee9b wpt-pr: 35374
Following on from whatwg/dom#1027, this PR uses the AbortSignal's abort reason in the abort fetch algorithm.
@annevk Does this look okay to you?
/cc @yutakahirano, @domenic
(See WHATWG Working Mode: Changes for more details.)
Preview | Diff
Preview | Diff