diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp index daa506c4005..92598eb8743 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp @@ -110,6 +110,29 @@ WebIDL::ExceptionOr ReadableStream::get_reader(ReadableStr return ReadableStreamReader { TRY(acquire_readable_stream_byob_reader(*this)) }; } +WebIDL::ExceptionOr> ReadableStream::pipe_through(ReadableWritablePair transform, StreamPipeOptions const& options) +{ + // 1. If ! IsReadableStreamLocked(this) is true, throw a TypeError exception. + if (is_readable_stream_locked(*this)) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Failed to execute 'pipeThrough' on 'ReadableStream': Cannot pipe a locked stream"sv }; + + // 2. If ! IsWritableStreamLocked(transform["writable"]) is true, throw a TypeError exception. + if (is_writable_stream_locked(*transform.writable)) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Failed to execute 'pipeThrough' on 'ReadableStream': parameter 1's 'writable' is locked"sv }; + + // 3. Let signal be options["signal"] if it exists, or undefined otherwise. + auto signal = options.signal.has_value() ? JS::Value(options.signal.value().ptr()) : JS::js_undefined(); + + // 4. Let promise be ! ReadableStreamPipeTo(this, transform["writable"], options["preventClose"], options["preventAbort"], options["preventCancel"], signal). + auto promise = MUST(readable_stream_pipe_to(*this, *transform.writable, options.prevent_close, options.prevent_abort, options.prevent_cancel, signal)); + + // 5. Set promise.[[PromiseIsHandled]] to true. + WebIDL::mark_promise_as_handled(*promise); + + // 6. Return transform["readable"]. + return JS::NonnullGCPtr { *transform.readable }; +} + WebIDL::ExceptionOr> ReadableStream::pipe_to(WritableStream& destination, StreamPipeOptions const& options) { auto& realm = this->realm(); diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.h b/Userland/Libraries/LibWeb/Streams/ReadableStream.h index 18ac8ac6575..fa911f8dae3 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.h +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.h @@ -27,6 +27,11 @@ struct ReadableStreamGetReaderOptions { Optional mode; }; +struct ReadableWritablePair { + JS::GCPtr readable; + JS::GCPtr writable; +}; + struct StreamPipeOptions { bool prevent_close { false }; bool prevent_abort { false }; @@ -70,6 +75,7 @@ public: bool locked() const; WebIDL::ExceptionOr> cancel(JS::Value reason); WebIDL::ExceptionOr get_reader(ReadableStreamGetReaderOptions const& = {}); + WebIDL::ExceptionOr> pipe_through(ReadableWritablePair transform, StreamPipeOptions const& = {}); WebIDL::ExceptionOr> pipe_to(WritableStream& destination, StreamPipeOptions const& = {}); WebIDL::ExceptionOr tee(); diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.idl b/Userland/Libraries/LibWeb/Streams/ReadableStream.idl index 418bc65481a..c62d3f97f56 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.idl +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.idl @@ -4,6 +4,11 @@ #import #import +dictionary ReadableWritablePair { + required ReadableStream readable; + required WritableStream writable; +}; + dictionary StreamPipeOptions { boolean preventClose = false; boolean preventAbort = false; @@ -30,7 +35,7 @@ interface ReadableStream { Promise cancel(optional any reason); ReadableStreamReader getReader(optional ReadableStreamGetReaderOptions options = {}); - // FIXME: ReadableStream pipeThrough(ReadableWritablePair transform, optional StreamPipeOptions options = {}); + ReadableStream pipeThrough(ReadableWritablePair transform, optional StreamPipeOptions options = {}); Promise pipeTo(WritableStream destination, optional StreamPipeOptions options = {}); sequence tee();