From 7ad32f944f53d460f0ac305f7f68876139f9a3f8 Mon Sep 17 00:00:00 2001 From: Gregory Terzian <2792687+gterzian@users.noreply.github.com> Date: Tue, 5 Aug 2025 05:42:25 +0800 Subject: [PATCH] script: allow for undefined chunks in stream piping (#38470) Current code uses `undefined` as chunk value to identify the closing of a stream, but this breaks once you start streaming a chunk that is actually `undefined`, as shown in https://github.com/servo/servo/pull/38466. This PR re-implement the logic in a way that allows for chunks to be `undefined`. Testing: Should maintain `streams/piping` WPT pass rates. Also makes the `undefined` case of [`/encoding/streams/encode-bad-chunks.any.js`](https://github.com/servo/servo/blob/c59ee57b5d1ad0d6c2c6db10e15e3c53d243d0f2/tests/wpt/tests/encoding/streams/encode-bad-chunks.any.js#L29), but that is only noticeable in https://github.com/servo/servo/pull/38466 Fixes: None, but noted in https://github.com/servo/servo/pull/38466 Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> --- components/script/dom/readablestream.rs | 30 ++++++------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs index adc45449d1e..b8dda723c7f 100644 --- a/components/script/dom/readablestream.rs +++ b/components/script/dom/readablestream.rs @@ -249,28 +249,7 @@ impl Callback for PipeTo { // If dest.[[state]] is "writable", // and ! WritableStreamCloseQueuedOrInFlight(dest) is false, if dest.is_writable() && !dest.close_queued_or_in_flight() { - let has_done = { - if !result.is_object() { - false - } else { - rooted!(in(*cx) let object = result.to_object()); - rooted!(in(*cx) let mut done = UndefinedValue()); - unsafe { - get_dictionary_property( - *cx, - object.handle(), - "done", - done.handle_mut(), - can_gc, - ) - .unwrap() - } - } - }; - // If any chunks have been read but not yet written, write them to dest. - let contained_bytes = self.write_chunk(cx, &global, result, can_gc); - - if !contained_bytes && !has_done { + let Ok(done) = get_read_promise_done(cx, &result, can_gc) else { // This is the case that the microtask ran in reaction // to the closed promise of the reader, // so we should wait for subsequent chunks, @@ -278,6 +257,11 @@ impl Callback for PipeTo { // (reader is closed, but there are still pending reads). // Shutdown will happen when the last chunk has been received. return; + }; + + if !done { + // If any chunks have been read but not yet written, write them to dest. + self.write_chunk(cx, &global, result, can_gc); } } } @@ -446,7 +430,7 @@ impl PipeTo { get_dictionary_property(*cx, object.handle(), "value", bytes.handle_mut(), can_gc) .expect("Chunk should have a value.") }; - if !bytes.is_undefined() && has_value { + if has_value { // Write the chunk. let write_promise = self.writer.write(cx, global, bytes.handle(), can_gc); self.pending_writes.borrow_mut().push_back(write_promise);