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
12cfa08a09.

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.
This commit is contained in:
Timothy Flynn 2024-04-30 06:52:29 -04:00 committed by Andreas Kling
parent f5799f7d2c
commit 6c6fb224ec
Notes: sideshowbarker 2024-07-16 22:34:39 +09:00
2 changed files with 29 additions and 2 deletions

View File

@ -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.

View File

@ -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();