From 9d0700e770e1d32f275c3cd3c9fc5314a4268895 Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Sat, 2 Dec 2023 20:13:34 +1300 Subject: [PATCH] LibWeb: Fix IDL getter for ReadableByteStreamController byobRequest We were previously only returning the controllers current [[byobRequest]] instead of taking into account pending pull intos. Rename the getter function which would return the controllers [[byobRequest]] slot to `raw_byob_request` to differentiate it from the IDL getter. This also leaves a FIXME for a spec step which we are also not currently implementing correctly. --- .../LibWeb/Streams/AbstractOperations.cpp | 39 +++++++++++++++++-- .../LibWeb/Streams/AbstractOperations.h | 1 + .../Streams/ReadableByteStreamController.cpp | 8 ++++ .../Streams/ReadableByteStreamController.h | 9 ++++- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp index 14fcb45135..9715ad712e 100644 --- a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp +++ b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp @@ -505,7 +505,7 @@ void readable_byte_stream_controller_fill_head_pull_into_descriptor(ReadableByte VERIFY(controller.pending_pull_intos().is_empty() || &controller.pending_pull_intos().first() == &pull_into_descriptor); // 2. Assert: controller.[[byobRequest]] is null. - VERIFY(!controller.byob_request()); + VERIFY(!controller.raw_byob_request()); // 3. Set pullIntoDescriptor’s bytes filled to bytes filled + size. pull_into_descriptor.bytes_filled += size; @@ -1057,6 +1057,38 @@ bool readable_stream_default_controller_should_call_pull(ReadableStreamDefaultCo return false; } +// https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollergetbyobrequest +JS::GCPtr readable_byte_stream_controller_get_byob_request(JS::NonnullGCPtr controller) +{ + auto& vm = controller->vm(); + auto& realm = controller->realm(); + + // 1. If controller.[[byobRequest]] is null and controller.[[pendingPullIntos]] is not empty, + if (!controller->raw_byob_request() && !controller->pending_pull_intos().is_empty()) { + // 1. Let firstDescriptor be controller.[[pendingPullIntos]][0]. + auto const& first_descriptor = controller->pending_pull_intos().first(); + + // 2. Let view be ! Construct(%Uint8Array%, « firstDescriptor’s buffer, firstDescriptor’s byte offset + firstDescriptor’s bytes filled, firstDescriptor’s byte length − firstDescriptor’s bytes filled »). + auto view = MUST(JS::construct(vm, *realm.intrinsics().uint8_array_constructor(), first_descriptor.buffer, JS::Value(first_descriptor.byte_offset + first_descriptor.bytes_filled), JS::Value(first_descriptor.byte_length - first_descriptor.bytes_filled))); + + // 3. Let byobRequest be a new ReadableStreamBYOBRequest. + auto byob_request = realm.heap().allocate(realm, realm); + + // 4. Set byobRequest.[[controller]] to controller. + byob_request->set_controller(controller); + + // 5. Set byobRequest.[[view]] to view. + auto array_buffer_view = vm.heap().allocate(realm, view); + byob_request->set_view(array_buffer_view); + + // 6. Set controller.[[byobRequest]] to byobRequest. + controller->set_byob_request(byob_request); + } + + // 2. Return controller.[[byobRequest]]. + return controller->raw_byob_request(); +} + // https://streams.spec.whatwg.org/#readable-stream-default-controller-clear-algorithms void readable_stream_default_controller_clear_algorithms(ReadableStreamDefaultController& controller) { @@ -1813,7 +1845,8 @@ WebIDL::ExceptionOr readable_stream_enqueue(ReadableStreamController& cont // FIXME: 2. Assert: chunk is an ArrayBufferView. // 3. Let byobView be the current BYOB request view for stream. - auto byob_view = readable_byte_controller->byob_request(); + // FIXME: This is not what the spec means by 'current BYOB request view' + auto byob_view = readable_byte_controller->raw_byob_request(); // 4. If byobView is non-null, and chunk.[[ViewedArrayBuffer]] is byobView.[[ViewedArrayBuffer]], then: if (byob_view) { @@ -2112,7 +2145,7 @@ WebIDL::ExceptionOr readable_byte_stream_controller_enqueue_cloned_chunk_t PullIntoDescriptor readable_byte_stream_controller_shift_pending_pull_into(ReadableByteStreamController& controller) { // 1. Assert: controller.[[byobRequest]] is null. - VERIFY(!controller.byob_request()); + VERIFY(!controller.raw_byob_request()); // 2. Let descriptor be controller.[[pendingPullIntos]][0]. // 3. Remove descriptor from controller.[[pendingPullIntos]]. diff --git a/Userland/Libraries/LibWeb/Streams/AbstractOperations.h b/Userland/Libraries/LibWeb/Streams/AbstractOperations.h index cfa401de28..d36df644a9 100644 --- a/Userland/Libraries/LibWeb/Streams/AbstractOperations.h +++ b/Userland/Libraries/LibWeb/Streams/AbstractOperations.h @@ -78,6 +78,7 @@ WebIDL::ExceptionOr set_up_readable_stream_default_controller_from_underly WebIDL::ExceptionOr set_up_readable_stream_controller_with_byte_reading_support(ReadableStream&, Optional&& = {}, Optional&& = {}, double high_water_mark = 0); WebIDL::ExceptionOr set_up_readable_byte_stream_controller(ReadableStream&, ReadableByteStreamController&, StartAlgorithm&&, PullAlgorithm&&, CancelAlgorithm&&, double high_water_mark, JS::Value auto_allocate_chunk_size); WebIDL::ExceptionOr set_up_readable_byte_stream_controller_from_underlying_source(ReadableStream&, JS::Value underlying_source, UnderlyingSource const& underlying_source_dict, double high_water_mark); +JS::GCPtr readable_byte_stream_controller_get_byob_request(JS::NonnullGCPtr); WebIDL::ExceptionOr readable_stream_enqueue(ReadableStreamController& controller, JS::Value chunk); WebIDL::ExceptionOr readable_byte_stream_controller_enqueue(ReadableByteStreamController& controller, JS::Value chunk); diff --git a/Userland/Libraries/LibWeb/Streams/ReadableByteStreamController.cpp b/Userland/Libraries/LibWeb/Streams/ReadableByteStreamController.cpp index eaf9a65404..e8875d1c28 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableByteStreamController.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableByteStreamController.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -22,6 +23,13 @@ Optional ReadableByteStreamController::desired_size() const return readable_byte_stream_controller_get_desired_size(*this); } +// https://streams.spec.whatwg.org/#rbs-controller-byob-request +JS::GCPtr ReadableByteStreamController::byob_request() +{ + // 1. Return ! ReadableByteStreamControllerGetBYOBRequest(this). + return readable_byte_stream_controller_get_byob_request(*this); +} + // https://streams.spec.whatwg.org/#rbs-controller-close WebIDL::ExceptionOr ReadableByteStreamController::close() { diff --git a/Userland/Libraries/LibWeb/Streams/ReadableByteStreamController.h b/Userland/Libraries/LibWeb/Streams/ReadableByteStreamController.h index af84ee5485..70485eb3e3 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableByteStreamController.h +++ b/Userland/Libraries/LibWeb/Streams/ReadableByteStreamController.h @@ -77,10 +77,15 @@ class ReadableByteStreamController : public Bindings::PlatformObject { public: virtual ~ReadableByteStreamController() override = default; - JS::GCPtr byob_request() const { return m_byob_request; } - JS::GCPtr byob_request() { return m_byob_request; } + // IDL getter, returns current [[byobRequest]] (if any), and otherwise the [[byobRequest]] for the next pending pull into request + JS::GCPtr byob_request(); + void set_byob_request(JS::GCPtr request) { m_byob_request = request; } + // Raw [[byobRequest]] slot + JS::GCPtr raw_byob_request() const { return m_byob_request; } + JS::GCPtr raw_byob_request() { return m_byob_request; } + Optional desired_size() const; WebIDL::ExceptionOr close(); void error(JS::Value error);