fix setting and propagating of abort reason

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>
This commit is contained in:
gterzian 2025-06-06 21:10:31 +07:00
parent 99bbef833a
commit 2f2e962ae0
No known key found for this signature in database
GPG key ID: E290318CF2FC84D3
3 changed files with 43 additions and 5 deletions

View file

@ -26,7 +26,7 @@ impl AbortController {
/// <https://dom.spec.whatwg.org/#dom-abortcontroller-abortcontroller>
fn new_inherited(signal: &AbortSignal) -> AbortController {
// Note: continuation of the constructor steps.
// Set thiss signal to signal.
AbortController {
reflector_: Reflector::new(),

View file

@ -91,7 +91,7 @@ impl AbortSignal {
let abort_reason = reason.get();
// Set signals abort reason to reason if it is given;
if !abort_reason.is_undefined() {
if !abort_reason.is_null() {
self.abort_reason.set(abort_reason);
} else {
// otherwise to a new "AbortError" DOMException.
@ -133,6 +133,17 @@ impl AbortSignal {
) {
match algorithm {
AbortAlgorithm::StreamPiping(pipe) => {
// Note: the streams spec says to "If signal is aborted, perform abortAlgorithm",
// which bypasses the signal abort concept,
// and bypasses the steps in that concept that set the default reason
// (see "otherwise to a new "AbortError" DOMException.")
// So we add it here even though it remains unspecified,
// because the `/stream/piping/abort.any.js` test rely on this mechanism.
if self.abort_reason.get().is_undefined() {
rooted!(in(*cx) let mut rooted_error = UndefinedValue());
Error::Abort.to_jsval(cx, &global, rooted_error.handle_mut(), can_gc);
self.abort_reason.set(rooted_error.get())
}
rooted!(in(*cx) let mut reason = UndefinedValue());
reason.set(self.abort_reason.get());
pipe.abort_with_reason(cx, global, reason.handle(), realm, can_gc);
@ -168,7 +179,7 @@ impl AbortSignal {
/// <https://dom.spec.whatwg.org/#abortsignal-aborted>
pub(crate) fn aborted(&self) -> bool {
// An AbortSignal object is aborted when its abort reason is not undefined.
!self.abort_reason.get().is_undefined()
!self.abort_reason.get().is_null()
}
}

View file

@ -182,6 +182,15 @@ impl PipeTo {
// Let error be signals abort reason.
self.abort_reason.set(error.get());
// Note: setting the error now,
// will result in a rejection of the pipe promise, with this error.
// Unless any shutdown action raise their own error,
// in which case this error will be overwritten by the shutdown action error.
self.shutdown_error.set(error.get());
rooted!(in(*cx) let mut error = self.shutdown_error.get());
assert!(!error.is_undefined());
// Let actions be an empty ordered set.
// Note: the actions are defined, and performed, inside `shutdown_with_an_action`.
@ -329,10 +338,28 @@ impl Callback for PipeTo {
// Finalize, passing along error if it was given.
if !result.is_undefined() {
// All actions either resolve with undefined,
// Most actions either resolve with undefined,
// or reject with an error,
// and the error should be used when finalizing.
self.shutdown_error.set(result.get());
// One exception is the `Abort` action,
// which resolves with a list of undefined values.
rooted!(in(*cx) let object = result.to_object());
rooted!(in(*cx) let mut done = UndefinedValue());
let property = unsafe {
get_dictionary_property(
*cx,
object.handle(),
"0",
done.handle_mut(),
can_gc,
)
};
if let Ok(false) = property {
// If `result` isn't undefined, or a list,
// then it is an error
// and should overwrite the current shutdown error.
self.shutdown_error.set(result.get());
}
}
self.finalize(cx, &global, can_gc);
},