Sfoglia il codice sorgente

LibWeb: Add an ad-hoc ReadableStreamDefaultReader::read_all_chunks AO

The ReadableStreamPipeTo AO requires reading all chunks from a stream.
There actually isn't an AO defined to do that, so the "read all bytes"
implementation was changed to provide each chunk in a vector in commit
12cfa08a093d0d60406d353232328ca60eff0bf5.

This change makes reading all bytes a bit more uncomfortable in normal
use cases, as we now have to manually join the vector we receive. This
can also cause churn with huge allocations.

So instead, let's just provide an ad-hoc callback to receive each chunk
as they arrive.
Timothy Flynn 1 anno fa
parent
commit
6c6fb224ec

+ 23 - 1
Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp

@@ -65,12 +65,13 @@ void ReadableStreamDefaultReader::visit_edges(Cell::Visitor& visitor)
 }
 
 // https://streams.spec.whatwg.org/#read-loop
-ReadLoopReadRequest::ReadLoopReadRequest(JS::VM& vm, JS::Realm& realm, ReadableStreamDefaultReader& reader, SuccessSteps success_steps, FailureSteps failure_steps)
+ReadLoopReadRequest::ReadLoopReadRequest(JS::VM& vm, JS::Realm& realm, ReadableStreamDefaultReader& reader, SuccessSteps success_steps, FailureSteps failure_steps, ChunkSteps chunk_steps)
     : m_vm(vm)
     , m_realm(realm)
     , m_reader(reader)
     , m_success_steps(move(success_steps))
     , m_failure_steps(move(failure_steps))
+    , m_chunk_steps(move(chunk_steps))
 {
 }
 
@@ -89,6 +90,11 @@ void ReadLoopReadRequest::on_chunk(JS::Value chunk)
     // 2. Append the bytes represented by chunk to bytes.
     m_byte_chunks.append(buffer);
 
+    if (m_chunk_steps) {
+        // FIXME: Can we move the buffer out of the `chunk`? Unclear if that is safe.
+        m_chunk_steps(MUST(ByteBuffer::copy(buffer)));
+    }
+
     // FIXME: As the spec suggests, implement this non-recursively - instead of directly. It is not too big of a deal currently
     //        as we enqueue the entire blob buffer in one go, meaning that we only recurse a single time. Once we begin queuing
     //        up more than one chunk at a time, we may run into stack overflow problems.
@@ -195,6 +201,22 @@ void ReadableStreamDefaultReader::read_all_bytes(ReadLoopReadRequest::SuccessSte
     readable_stream_default_reader_read(*this, read_request);
 }
 
+void ReadableStreamDefaultReader::read_all_chunks(ReadLoopReadRequest::ChunkSteps chunk_steps, ReadLoopReadRequest::SuccessSteps success_steps, ReadLoopReadRequest::FailureSteps 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();
+
+    // 1. Let readRequest be a new read request with the following items:
+    //    NOTE: items and steps in ReadLoopReadRequest.
+    auto read_request = heap().allocate_without_realm<ReadLoopReadRequest>(vm, realm, *this, move(success_steps), move(failure_steps), move(chunk_steps));
+
+    // 2. Perform ! ReadableStreamDefaultReaderRead(this, readRequest).
+    readable_stream_default_reader_read(*this, read_request);
+}
+
 // FIXME: This function is a promise-based wrapper around "read all bytes". The spec changed this function to not use promises
 //        in https://github.com/whatwg/streams/commit/f894acdd417926a2121710803cef593e15127964 - however, it seems that the
 //        FileAPI blob specification has not been updated to match, see: https://github.com/w3c/FileAPI/issues/187.

+ 6 - 1
Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.h

@@ -42,7 +42,10 @@ public:
     // failureSteps, which is an algorithm accepting a JavaScript value
     using FailureSteps = JS::SafeFunction<void(JS::Value error)>;
 
-    ReadLoopReadRequest(JS::VM& vm, JS::Realm& realm, ReadableStreamDefaultReader& reader, SuccessSteps success_steps, FailureSteps failure_steps);
+    // AD-HOC: callback triggered on every chunk received from the stream.
+    using ChunkSteps = JS::SafeFunction<void(ByteBuffer)>;
+
+    ReadLoopReadRequest(JS::VM& vm, JS::Realm& realm, ReadableStreamDefaultReader& reader, SuccessSteps success_steps, FailureSteps failure_steps, ChunkSteps chunk_steps = {});
 
     virtual void on_chunk(JS::Value chunk) override;
 
@@ -59,6 +62,7 @@ private:
     Vector<ByteBuffer> m_byte_chunks;
     SuccessSteps m_success_steps;
     FailureSteps m_failure_steps;
+    ChunkSteps m_chunk_steps;
 };
 
 // https://streams.spec.whatwg.org/#readablestreamdefaultreader
@@ -76,6 +80,7 @@ public:
     JS::NonnullGCPtr<JS::Promise> read();
 
     void read_all_bytes(ReadLoopReadRequest::SuccessSteps, ReadLoopReadRequest::FailureSteps);
+    void read_all_chunks(ReadLoopReadRequest::ChunkSteps, ReadLoopReadRequest::SuccessSteps, ReadLoopReadRequest::FailureSteps);
     JS::NonnullGCPtr<WebIDL::Promise> read_all_bytes_deprecated();
 
     void release_lock();