From 72ccfa3a77ed9e1a23ce96ccfdd9c8e19f487e6f Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Wed, 9 Apr 2025 11:56:29 -0400 Subject: [PATCH] LibWeb: Implement an AO to close writable streams with error propagation --- .../LibWeb/Streams/AbstractOperations.cpp | 29 +++++++++++++++++++ Libraries/LibWeb/Streams/AbstractOperations.h | 1 + 2 files changed, 30 insertions(+) diff --git a/Libraries/LibWeb/Streams/AbstractOperations.cpp b/Libraries/LibWeb/Streams/AbstractOperations.cpp index 1960bd6a409..9e14361459a 100644 --- a/Libraries/LibWeb/Streams/AbstractOperations.cpp +++ b/Libraries/LibWeb/Streams/AbstractOperations.cpp @@ -4092,6 +4092,35 @@ GC::Ref writable_stream_default_writer_close(WritableStreamDefa return writable_stream_close(*stream); } +// https://streams.spec.whatwg.org/#writable-stream-default-writer-close-with-error-propagation +GC::Ref writable_stream_default_writer_close_with_error_propagation(WritableStreamDefaultWriter& writer) +{ + auto& realm = writer.realm(); + + // 1. Let stream be writer.[[stream]]. + auto stream = writer.stream(); + + // 2. Assert: stream is not undefined. + VERIFY(stream); + + // 3. Let state be stream.[[state]]. + auto state = stream->state(); + + // 4. If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state is "closed", return a promise resolved with undefined. + if (writable_stream_close_queued_or_in_flight(*stream) || state == WritableStream::State::Closed) + return WebIDL::create_resolved_promise(realm, JS::js_undefined()); + + // 5. If state is "errored", return a promise rejected with stream.[[storedError]]. + if (state == WritableStream::State::Errored) + return WebIDL::create_rejected_promise(realm, stream->stored_error()); + + // 6. Assert: state is "writable" or "erroring". + VERIFY(state == WritableStream::State::Writable || state == WritableStream::State::Erroring); + + // 7. Return ! WritableStreamDefaultWriterClose(writer). + return writable_stream_default_writer_close(writer); +} + // https://streams.spec.whatwg.org/#writable-stream-default-writer-ensure-closed-promise-rejected void writable_stream_default_writer_ensure_closed_promise_rejected(WritableStreamDefaultWriter& writer, JS::Value error) { diff --git a/Libraries/LibWeb/Streams/AbstractOperations.h b/Libraries/LibWeb/Streams/AbstractOperations.h index 91e5f711646..94817cb223d 100644 --- a/Libraries/LibWeb/Streams/AbstractOperations.h +++ b/Libraries/LibWeb/Streams/AbstractOperations.h @@ -135,6 +135,7 @@ void writable_stream_update_backpressure(WritableStream&, bool backpressure); GC::Ref writable_stream_default_writer_abort(WritableStreamDefaultWriter&, JS::Value reason); GC::Ref writable_stream_default_writer_close(WritableStreamDefaultWriter&); +GC::Ref writable_stream_default_writer_close_with_error_propagation(WritableStreamDefaultWriter&); void writable_stream_default_writer_ensure_closed_promise_rejected(WritableStreamDefaultWriter&, JS::Value error); void writable_stream_default_writer_ensure_ready_promise_rejected(WritableStreamDefaultWriter&, JS::Value error); Optional writable_stream_default_writer_get_desired_size(WritableStreamDefaultWriter const&);