diff --git a/Libraries/LibWeb/Streams/AbstractOperations.cpp b/Libraries/LibWeb/Streams/AbstractOperations.cpp index ec44d475aa6..40b03dacc5f 100644 --- a/Libraries/LibWeb/Streams/AbstractOperations.cpp +++ b/Libraries/LibWeb/Streams/AbstractOperations.cpp @@ -353,15 +353,12 @@ GC::Ref readable_stream_pipe_to(ReadableStream& source, Writabl // FIXME: Currently a naive implementation that uses ReadableStreamDefaultReader::read_all_chunks() to read all chunks // from the source and then through the callback success_steps writes those chunks to the destination. - auto chunk_steps = GC::create_function(realm.heap(), [&realm, writer](ByteBuffer buffer) { - auto array_buffer = JS::ArrayBuffer::create(realm, move(buffer)); - auto chunk = JS::Uint8Array::create(realm, array_buffer->byte_length(), *array_buffer); - + auto chunk_steps = GC::create_function(realm.heap(), [&realm, writer](JS::Value chunk) { auto promise = writable_stream_default_writer_write(writer, chunk); WebIDL::resolve_promise(realm, promise, JS::js_undefined()); }); - auto success_steps = GC::create_function(realm.heap(), [promise, &realm, reader, writer](ByteBuffer) { + auto success_steps = GC::create_function(realm.heap(), [promise, &realm, reader, writer]() { // Make sure we close the acquired writer. WebIDL::resolve_promise(realm, writable_stream_default_writer_close(*writer), JS::js_undefined()); readable_stream_default_reader_release(*reader); diff --git a/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp b/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp index 551449c6db3..8ab80faecb1 100644 --- a/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp +++ b/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp @@ -212,20 +212,40 @@ void ReadableStreamDefaultReader::read_all_bytes(GC::Ref chunk_steps, GC::Ref success_steps, GC::Ref failure_steps) +void ReadableStreamDefaultReader::read_all_chunks(GC::Ref chunk_steps, GC::Ref success_steps, GC::Ref failure_steps) { // AD-HOC: Some spec steps direct us to "read all chunks" from a stream, but there isn't an AO defined to do that. - // We implement those steps by using the "read all bytes" definition, with a custom callback to receive - // each chunk that is read. - auto& realm = this->realm(); - auto& vm = realm.vm(); + // We implement those steps by continuously making default read requests, which is an identity transformation, + // with a custom callback to receive each chunk that is read. This is done until the controller signals + // that there are no more chunks to consume. + // This function is based on "read_all_bytes" above. + auto promise_capability = read(); - // 1. Let readRequest be a new read request with the following items: - // NOTE: items and steps in ReadLoopReadRequest. - auto read_request = heap().allocate(vm, realm, *this, success_steps, failure_steps, chunk_steps); + WebIDL::react_to_promise( + promise_capability, + GC::create_function(heap(), [this, chunk_steps, success_steps, failure_steps](JS::Value value) -> WebIDL::ExceptionOr { + auto& vm = this->vm(); - // 2. Perform ! ReadableStreamDefaultReaderRead(this, readRequest). - readable_stream_default_reader_read(*this, read_request); + VERIFY(value.is_object()); + auto& value_object = value.as_object(); + + auto done = MUST(JS::iterator_complete(vm, value_object)); + + if (!done) { + auto chunk = MUST(JS::iterator_value(vm, value_object)); + chunk_steps->function()(chunk); + + read_all_chunks(chunk_steps, success_steps, failure_steps); + } else { + success_steps->function()(); + } + + return JS::js_undefined(); + }), + GC::create_function(heap(), [failure_steps](JS::Value error) -> WebIDL::ExceptionOr { + failure_steps->function()(error); + return JS::js_undefined(); + })); } // FIXME: This function is a promise-based wrapper around "read all bytes". The spec changed this function to not use promises diff --git a/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.h b/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.h index 9639b7433c1..8e37bf476e7 100644 --- a/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.h +++ b/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.h @@ -75,13 +75,23 @@ class ReadableStreamDefaultReader final public: static WebIDL::ExceptionOr> construct_impl(JS::Realm&, GC::Ref); + // AD-HOC: Callback functions for read_all_chunks + // successSteps, which is an algorithm accepting a JavaScript value + using ReadAllOnSuccessSteps = GC::Function; + + // failureSteps, which is an algorithm accepting a JavaScript value + using ReadAllOnFailureSteps = GC::Function; + + // AD-HOC: callback triggered on every chunk received from the stream. + using ReadAllOnChunkSteps = GC::Function; + virtual ~ReadableStreamDefaultReader() override = default; GC::Ref read(); void read_a_chunk(Fetch::Infrastructure::IncrementalReadLoopReadRequest& read_request); void read_all_bytes(GC::Ref, GC::Ref); - void read_all_chunks(GC::Ref, GC::Ref, GC::Ref); + void read_all_chunks(GC::Ref, GC::Ref, GC::Ref); GC::Ref read_all_bytes_deprecated(); void release_lock();