/* * Copyright (c) 2022, Linus Groh * Copyright (c) 2023, Matthew Olsson * Copyright (c) 2023-2025, Shannon Booth * Copyright (c) 2023-2024, Kenneth Myhra * Copyright (c) 2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include namespace Web::Streams { // https://streams.spec.whatwg.org/#close-sentinel static JS::Value create_close_sentinel() { // The close sentinel is a unique value enqueued into [[queue]], in lieu of a chunk, to signal that the stream is // closed. It is only used internally, and is never exposed to web developers. return JS::js_special_empty_value(); } // https://streams.spec.whatwg.org/#close-sentinel static bool is_close_sentinel(JS::Value value) { return value.is_special_empty_value(); } // https://streams.spec.whatwg.org/#acquire-writable-stream-default-writer WebIDL::ExceptionOr> acquire_writable_stream_default_writer(WritableStream& stream) { auto& realm = stream.realm(); // 1. Let writer be a new WritableStreamDefaultWriter. auto writer = realm.create(realm); // 2. Perform ? SetUpWritableStreamDefaultWriter(writer, stream). TRY(set_up_writable_stream_default_writer(writer, stream)); // 3. Return writer. return writer; } // https://streams.spec.whatwg.org/#create-writable-stream WebIDL::ExceptionOr> create_writable_stream(JS::Realm& realm, GC::Ref start_algorithm, GC::Ref write_algorithm, GC::Ref close_algorithm, GC::Ref abort_algorithm, double high_water_mark, GC::Ref size_algorithm) { // 1. Assert: ! IsNonNegativeNumber(highWaterMark) is true. VERIFY(is_non_negative_number(JS::Value { high_water_mark })); // 2. Let stream be a new WritableStream. auto stream = realm.create(realm); // 3. Perform ! InitializeWritableStream(stream). initialize_writable_stream(stream); // 4. Let controller be a new WritableStreamDefaultController. auto controller = realm.create(realm); // 5. Perform ? SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm). TRY(set_up_writable_stream_default_controller(stream, controller, start_algorithm, write_algorithm, close_algorithm, abort_algorithm, high_water_mark, size_algorithm)); // 6. Return stream. return stream; } // https://streams.spec.whatwg.org/#initialize-writable-stream void initialize_writable_stream(WritableStream& stream) { // 1. Set stream.[[state]] to "writable". stream.set_state(WritableStream::State::Writable); // 2. Set stream.[[storedError]], stream.[[writer]], stream.[[controller]], stream.[[inFlightWriteRequest]], // stream.[[closeRequest]], stream.[[inFlightCloseRequest]], and stream.[[pendingAbortRequest]] to undefined. stream.set_stored_error(JS::js_undefined()); stream.set_writer({}); stream.set_controller({}); stream.set_in_flight_write_request({}); stream.set_close_request({}); stream.set_in_flight_close_request({}); stream.set_pending_abort_request({}); // 3. Set stream.[[writeRequests]] to a new empty list. stream.write_requests().clear(); // 4. Set stream.[[backpressure]] to false. stream.set_backpressure(false); } // https://streams.spec.whatwg.org/#is-writable-stream-locked bool is_writable_stream_locked(WritableStream const& stream) { // 1. If stream.[[writer]] is undefined, return false. if (!stream.writer()) return false; // 2. Return true. return true; } // https://streams.spec.whatwg.org/#set-up-writable-stream-default-writer WebIDL::ExceptionOr set_up_writable_stream_default_writer(WritableStreamDefaultWriter& writer, WritableStream& stream) { // FIXME: Exactly when we should effectively be using the relevant realm of `this` is to be clarified by the spec. // For now, we do so as needed by WPT tests. See: https://github.com/whatwg/streams/issues/1213 auto& realm = HTML::relevant_realm(writer); // 1. If ! IsWritableStreamLocked(stream) is true, throw a TypeError exception. if (is_writable_stream_locked(stream)) return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Stream is locked"sv }; // 2. Set writer.[[stream]] to stream. writer.set_stream(stream); // 3. Set stream.[[writer]] to writer. stream.set_writer(writer); // 4. Let state be stream.[[state]]. auto state = stream.state(); // 5. If state is "writable", if (state == WritableStream::State::Writable) { // 1. If ! WritableStreamCloseQueuedOrInFlight(stream) is false and stream.[[backpressure]] is true, set // writer.[[readyPromise]] to a new promise. if (!writable_stream_close_queued_or_in_flight(stream) && stream.backpressure()) { writer.set_ready_promise(WebIDL::create_promise(realm)); } // 2. Otherwise, set writer.[[readyPromise]] to a promise resolved with undefined. else { writer.set_ready_promise(WebIDL::create_resolved_promise(realm, JS::js_undefined())); } // 3. Set writer.[[closedPromise]] to a new promise. writer.set_closed_promise(WebIDL::create_promise(realm)); } // 6. Otherwise, if state is "erroring", else if (state == WritableStream::State::Erroring) { // 1. Set writer.[[readyPromise]] to a promise rejected with stream.[[storedError]]. writer.set_ready_promise(WebIDL::create_rejected_promise(realm, stream.stored_error())); // 2. Set writer.[[readyPromise]].[[PromiseIsHandled]] to true. WebIDL::mark_promise_as_handled(*writer.ready_promise()); // 3. Set writer.[[closedPromise]] to a new promise. writer.set_closed_promise(WebIDL::create_promise(realm)); } // 7. Otherwise, if state is "closed", else if (state == WritableStream::State::Closed) { // 1. Set writer.[[readyPromise]] to a promise resolved with undefined. writer.set_ready_promise(WebIDL::create_resolved_promise(realm, JS::js_undefined())); // 2. Set writer.[[closedPromise]] to a promise resolved with undefined. writer.set_closed_promise(WebIDL::create_resolved_promise(realm, JS::js_undefined())); } // 8. Otherwise, else { // 1. Assert: state is "errored". VERIFY(state == WritableStream::State::Errored); // 2. Let storedError be stream.[[storedError]]. auto stored_error = stream.stored_error(); // 3. Set writer.[[readyPromise]] to a promise rejected with storedError. writer.set_ready_promise(WebIDL::create_rejected_promise(realm, stored_error)); // 4. Set writer.[[readyPromise]].[[PromiseIsHandled]] to true. WebIDL::mark_promise_as_handled(*writer.ready_promise()); // 5. Set writer.[[closedPromise]] to a promise rejected with storedError. writer.set_closed_promise(WebIDL::create_rejected_promise(realm, stored_error)); // 6. Set writer.[[closedPromise]].[[PromiseIsHandled]] to true. WebIDL::mark_promise_as_handled(*writer.closed_promise()); } return {}; } // https://streams.spec.whatwg.org/#writable-stream-abort GC::Ref writable_stream_abort(WritableStream& stream, JS::Value reason) { auto& realm = stream.realm(); // 1. If stream.[[state]] is "closed" or "errored", return a promise resolved with undefined. if (first_is_one_of(stream.state(), WritableStream::State::Closed, WritableStream::State::Errored)) return WebIDL::create_resolved_promise(realm, JS::js_undefined()); // 2. Signal abort on stream.[[controller]].[[signal]] with reason. stream.controller()->signal()->signal_abort(reason); // 3. Let state be stream.[[state]]. auto state = stream.state(); // 4. If state is "closed" or "errored", return a promise resolved with undefined. if (state == WritableStream::State::Closed || state == WritableStream::State::Errored) return WebIDL::create_resolved_promise(realm, JS::js_undefined()); // 5. If stream.[[pendingAbortRequest]] is not undefined, return stream.[[pendingAbortRequest]]'s promise. if (stream.pending_abort_request().has_value()) return stream.pending_abort_request()->promise; // 6. Assert: state is "writable" or "erroring". VERIFY(state == WritableStream::State::Writable || state == WritableStream::State::Erroring); // 7. Let wasAlreadyErroring be false. auto was_already_erroring = false; // 8. If state is "erroring", if (state == WritableStream::State::Erroring) { // 1. Set wasAlreadyErroring to true. was_already_erroring = true; // 2. Set reason to undefined. reason = JS::js_undefined(); } // 9. Let promise be a new promise. auto promise = WebIDL::create_promise(realm); // 10. Set stream.[[pendingAbortRequest]] to a new pending abort request whose promise is promise, reason is reason, // and was already erroring is wasAlreadyErroring. stream.set_pending_abort_request(PendingAbortRequest { promise, reason, was_already_erroring }); // 11. If wasAlreadyErroring is false, perform ! WritableStreamStartErroring(stream, reason). if (!was_already_erroring) writable_stream_start_erroring(stream, reason); // 12. Return promise. return promise; } // https://streams.spec.whatwg.org/#writable-stream-close GC::Ref writable_stream_close(WritableStream& stream) { auto& realm = stream.realm(); // 1. Let state be stream.[[state]]. auto state = stream.state(); // 2. If state is "closed" or "errored", return a promise rejected with a TypeError exception. if (state == WritableStream::State::Closed || state == WritableStream::State::Errored) { auto message = state == WritableStream::State::Closed ? "Cannot close a closed stream"sv : "Cannot close an errored stream"sv; auto exception = JS::TypeError::create(realm, message); return WebIDL::create_rejected_promise(realm, exception); } // 3. Assert: state is "writable" or "erroring". VERIFY(state == WritableStream::State::Writable || state == WritableStream::State::Erroring); // 4. Assert: ! WritableStreamCloseQueuedOrInFlight(stream) is false. VERIFY(!writable_stream_close_queued_or_in_flight(stream)); // 5. Let promise be a new promise. auto promise = WebIDL::create_promise(realm); // 6. Set stream.[[closeRequest]] to promise. stream.set_close_request(promise); // 7. Let writer be stream.[[writer]]. auto writer = stream.writer(); // 8. If writer is not undefined, and stream.[[backpressure]] is true, and state is "writable", resolve // writer.[[readyPromise]] with undefined. if (writer && stream.backpressure() && state == WritableStream::State::Writable) WebIDL::resolve_promise(realm, *writer->ready_promise(), JS::js_undefined()); // 9. Perform ! WritableStreamDefaultControllerClose(stream.[[controller]]). writable_stream_default_controller_close(*stream.controller()); // 10. Return promise. return promise; } // https://streams.spec.whatwg.org/#writable-stream-add-write-request GC::Ref writable_stream_add_write_request(WritableStream& stream) { auto& realm = stream.realm(); // 1. Assert: ! IsWritableStreamLocked(stream) is true. VERIFY(is_writable_stream_locked(stream)); // 2. Assert: stream.[[state]] is "writable". VERIFY(stream.state() == WritableStream::State::Writable); // 3. Let promise be a new promise. auto promise = WebIDL::create_promise(realm); // 4. Append promise to stream.[[writeRequests]]. stream.write_requests().append(promise); // 5. Return promise. return promise; } // https://streams.spec.whatwg.org/#writable-stream-close-queued-or-in-flight bool writable_stream_close_queued_or_in_flight(WritableStream const& stream) { // 1. If stream.[[closeRequest]] is undefined and stream.[[inFlightCloseRequest]] is undefined, return false. if (!stream.close_request() && !stream.in_flight_close_request()) return false; // 2. Return true. return true; } // https://streams.spec.whatwg.org/#writable-stream-deal-with-rejection void writable_stream_deal_with_rejection(WritableStream& stream, JS::Value error) { // 1. Let state be stream.[[state]]. auto state = stream.state(); // 2. If state is "writable", if (state == WritableStream::State::Writable) { // 1. Perform ! WritableStreamStartErroring(stream, error). writable_stream_start_erroring(stream, error); // 2. Return. return; } // 3. Assert: state is "erroring". VERIFY(state == WritableStream::State::Erroring); // 4. Perform ! WritableStreamFinishErroring(stream). writable_stream_finish_erroring(stream); } // https://streams.spec.whatwg.org/#writable-stream-finish-erroring void writable_stream_finish_erroring(WritableStream& stream) { auto& realm = stream.realm(); // 1. Assert: stream.[[state]] is "erroring". VERIFY(stream.state() == WritableStream::State::Erroring); // 2. Assert: ! WritableStreamHasOperationMarkedInFlight(stream) is false. VERIFY(!writable_stream_has_operation_marked_in_flight(stream)); // 3. Set stream.[[state]] to "errored". stream.set_state(WritableStream::State::Errored); // 4. Perform ! stream.[[controller]].[[ErrorSteps]](). stream.controller()->error_steps(); // 5. Let storedError be stream.[[storedError]]. auto stored_error = stream.stored_error(); // 6. For each writeRequest of stream.[[writeRequests]]: for (auto write_request : stream.write_requests()) { // 1. Reject writeRequest with storedError. WebIDL::reject_promise(realm, *write_request, stored_error); } // 7. Set stream.[[writeRequests]] to an empty list. stream.write_requests().clear(); // 8. If stream.[[pendingAbortRequest]] is undefined, if (!stream.pending_abort_request().has_value()) { // 1. Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream). writable_stream_reject_close_and_closed_promise_if_needed(stream); // 2. Return. return; } // 9. Let abortRequest be stream.[[pendingAbortRequest]]. // 10. Set stream.[[pendingAbortRequest]] to undefined. auto abort_request = stream.pending_abort_request().release_value(); // 11. If abortRequest’s was already erroring is true, if (abort_request.was_already_erroring) { // 1. Reject abortRequest’s promise with storedError. WebIDL::reject_promise(realm, abort_request.promise, stored_error); // 2. Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream). writable_stream_reject_close_and_closed_promise_if_needed(stream); // 3. Return. return; } // 12. Let promise be ! stream.[[controller]].[[AbortSteps]](abortRequest’s reason). auto promise = stream.controller()->abort_steps(abort_request.reason); WebIDL::react_to_promise(promise, // 13. Upon fulfillment of promise, GC::create_function(realm.heap(), [&realm, &stream, abort_promise = abort_request.promise](JS::Value) -> WebIDL::ExceptionOr { // 1. Resolve abortRequest’s promise with undefined. WebIDL::resolve_promise(realm, abort_promise, JS::js_undefined()); // 2. Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream). writable_stream_reject_close_and_closed_promise_if_needed(stream); return JS::js_undefined(); }), // 14. Upon rejection of promise with reason reason, GC::create_function(realm.heap(), [&realm, &stream, abort_promise = abort_request.promise](JS::Value reason) -> WebIDL::ExceptionOr { // 1. Reject abortRequest’s promise with reason. WebIDL::reject_promise(realm, abort_promise, reason); // 2. Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream). writable_stream_reject_close_and_closed_promise_if_needed(stream); return JS::js_undefined(); })); } // https://streams.spec.whatwg.org/#writable-stream-finish-in-flight-close void writable_stream_finish_in_flight_close(WritableStream& stream) { auto& realm = stream.realm(); // 1. Assert: stream.[[inFlightCloseRequest]] is not undefined. VERIFY(stream.in_flight_close_request()); // 2. Resolve stream.[[inFlightCloseRequest]] with undefined. WebIDL::resolve_promise(realm, *stream.in_flight_close_request(), JS::js_undefined()); // 3. Set stream.[[inFlightCloseRequest]] to undefined. stream.set_in_flight_close_request({}); // 4. Let state be stream.[[state]]. auto state = stream.state(); // 5. Assert: stream.[[state]] is "writable" or "erroring". VERIFY(state == WritableStream::State::Writable || state == WritableStream::State::Erroring); // 6. If state is "erroring", if (state == WritableStream::State::Erroring) { // 1. Set stream.[[storedError]] to undefined. stream.set_stored_error(JS::js_undefined()); // 2. If stream.[[pendingAbortRequest]] is not undefined, if (stream.pending_abort_request().has_value()) { // 1. Resolve stream.[[pendingAbortRequest]]'s promise with undefined. // 2. Set stream.[[pendingAbortRequest]] to undefined. WebIDL::resolve_promise(realm, stream.pending_abort_request().release_value().promise, JS::js_undefined()); } } // 7. Set stream.[[state]] to "closed". stream.set_state(WritableStream::State::Closed); // 8. Let writer be stream.[[writer]]. auto writer = stream.writer(); // 9. If writer is not undefined, resolve writer.[[closedPromise]] with undefined. if (writer) WebIDL::resolve_promise(realm, *writer->closed_promise(), JS::js_undefined()); // 10. Assert: stream.[[pendingAbortRequest]] is undefined. VERIFY(!stream.pending_abort_request().has_value()); // 11. Assert: stream.[[storedError]] is undefined. VERIFY(stream.stored_error().is_undefined()); } // https://streams.spec.whatwg.org/#writable-stream-finish-in-flight-close-with-error void writable_stream_finish_in_flight_close_with_error(WritableStream& stream, JS::Value error) { auto& realm = stream.realm(); // 1. Assert: stream.[[inFlightCloseRequest]] is not undefined. VERIFY(stream.in_flight_close_request()); // 2. Reject stream.[[inFlightCloseRequest]] with error. WebIDL::reject_promise(realm, *stream.in_flight_close_request(), error); // 3. Set stream.[[inFlightCloseRequest]] to undefined. stream.set_in_flight_close_request({}); // 4. Assert: stream.[[state]] is "writable" or "erroring". VERIFY(first_is_one_of(stream.state(), WritableStream::State::Writable, WritableStream::State::Erroring)); // 5. If stream.[[pendingAbortRequest]] is not undefined, if (stream.pending_abort_request().has_value()) { // 1. Reject stream.[[pendingAbortRequest]]'s promise with error. // 2. Set stream.[[pendingAbortRequest]] to undefined. WebIDL::reject_promise(realm, stream.pending_abort_request().release_value().promise, error); } // 6. Perform ! WritableStreamDealWithRejection(stream, error). writable_stream_deal_with_rejection(stream, error); } // https://streams.spec.whatwg.org/#writable-stream-finish-in-flight-write void writable_stream_finish_in_flight_write(WritableStream& stream) { auto& realm = stream.realm(); // 1. Assert: stream.[[inFlightWriteRequest]] is not undefined. VERIFY(stream.in_flight_write_request()); // 2. Resolve stream.[[inFlightWriteRequest]] with undefined. WebIDL::resolve_promise(realm, *stream.in_flight_write_request(), JS::js_undefined()); // 3. Set stream.[[inFlightWriteRequest]] to undefined. stream.set_in_flight_write_request({}); } // https://streams.spec.whatwg.org/#writable-stream-finish-in-flight-write-with-error void writable_stream_finish_in_flight_write_with_error(WritableStream& stream, JS::Value error) { auto& realm = stream.realm(); // 1. Assert: stream.[[inFlightWriteRequest]] is not undefined. VERIFY(stream.in_flight_write_request()); // 2. Reject stream.[[inFlightWriteRequest]] with error. WebIDL::reject_promise(realm, *stream.in_flight_write_request(), error); // 3. Set stream.[[inFlightWriteRequest]] to undefined. stream.set_in_flight_write_request({}); // 4. Assert: stream.[[state]] is "writable" or "erroring". VERIFY(first_is_one_of(stream.state(), WritableStream::State::Writable, WritableStream::State::Erroring)); // 5. Perform ! WritableStreamDealWithRejection(stream, error). writable_stream_deal_with_rejection(stream, error); } // https://streams.spec.whatwg.org/#writable-stream-has-operation-marked-in-flight bool writable_stream_has_operation_marked_in_flight(WritableStream const& stream) { // 1. If stream.[[inFlightWriteRequest]] is undefined and stream.[[inFlightCloseRequest]] is undefined, return false. if (!stream.in_flight_write_request() && !stream.in_flight_close_request()) return false; // 2. Return true. return true; } // https://streams.spec.whatwg.org/#writable-stream-mark-close-request-in-flight void writable_stream_mark_close_request_in_flight(WritableStream& stream) { // 1. Assert: stream.[[inFlightCloseRequest]] is undefined. VERIFY(!stream.in_flight_close_request()); // 2. Assert: stream.[[closeRequest]] is not undefined. VERIFY(stream.close_request()); // 3. Set stream.[[inFlightCloseRequest]] to stream.[[closeRequest]]. stream.set_in_flight_close_request(stream.close_request()); // 4. Set stream.[[closeRequest]] to undefined. stream.set_close_request({}); } // https://streams.spec.whatwg.org/#writable-stream-mark-first-write-request-in-flight void writable_stream_mark_first_write_request_in_flight(WritableStream& stream) { // 1. Assert: stream.[[inFlightWriteRequest]] is undefined. VERIFY(!stream.in_flight_write_request()); // 2. Assert: stream.[[writeRequests]] is not empty. VERIFY(!stream.write_requests().is_empty()); // 3. Let writeRequest be stream.[[writeRequests]][0]. // 4. Remove writeRequest from stream.[[writeRequests]]. auto write_request = stream.write_requests().take_first(); // 5. Set stream.[[inFlightWriteRequest]] to writeRequest. stream.set_in_flight_write_request(write_request); } // https://streams.spec.whatwg.org/#writable-stream-reject-close-and-closed-promise-if-needed void writable_stream_reject_close_and_closed_promise_if_needed(WritableStream& stream) { auto& realm = stream.realm(); // 1. Assert: stream.[[state]] is "errored". VERIFY(stream.state() == WritableStream::State::Errored); // 2. If stream.[[closeRequest]] is not undefined, if (stream.close_request()) { // 1. Assert: stream.[[inFlightCloseRequest]] is undefined. VERIFY(!stream.in_flight_close_request()); // 2. Reject stream.[[closeRequest]] with stream.[[storedError]]. WebIDL::reject_promise(realm, *stream.close_request(), stream.stored_error()); // 3. Set stream.[[closeRequest]] to undefined. stream.set_close_request({}); } // 3. Let writer be stream.[[writer]]. auto writer = stream.writer(); // 4. If writer is not undefined, if (writer) { // 1. Reject writer.[[closedPromise]] with stream.[[storedError]]. WebIDL::reject_promise(realm, *writer->closed_promise(), stream.stored_error()); // 2. Set writer.[[closedPromise]].[[PromiseIsHandled]] to true. WebIDL::mark_promise_as_handled(*writer->closed_promise()); } } // https://streams.spec.whatwg.org/#writable-stream-start-erroring void writable_stream_start_erroring(WritableStream& stream, JS::Value reason) { // 1. Assert: stream.[[storedError]] is undefined. VERIFY(stream.stored_error().is_undefined()); // 2. Assert: stream.[[state]] is "writable". VERIFY(stream.state() == WritableStream::State::Writable); // 3. Let controller be stream.[[controller]]. auto controller = stream.controller(); // 4. Assert: controller is not undefined. VERIFY(controller); // 5. Set stream.[[state]] to "erroring". stream.set_state(WritableStream::State::Erroring); // 6. Set stream.[[storedError]] to reason. stream.set_stored_error(reason); // 7. Let writer be stream.[[writer]]. auto writer = stream.writer(); // 8. If writer is not undefined, perform ! WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason). if (writer) writable_stream_default_writer_ensure_ready_promise_rejected(*writer, reason); // 9. If ! WritableStreamHasOperationMarkedInFlight(stream) is false and controller.[[started]] is true, // perform ! WritableStreamFinishErroring(stream). if (!writable_stream_has_operation_marked_in_flight(stream) && controller->started()) writable_stream_finish_erroring(stream); } // https://streams.spec.whatwg.org/#writable-stream-update-backpressure void writable_stream_update_backpressure(WritableStream& stream, bool backpressure) { auto& realm = stream.realm(); // 1. Assert: stream.[[state]] is "writable". VERIFY(stream.state() == WritableStream::State::Writable); // 2. Assert: ! WritableStreamCloseQueuedOrInFlight(stream) is false. VERIFY(!writable_stream_close_queued_or_in_flight(stream)); // 3. Let writer be stream.[[writer]]. auto writer = stream.writer(); // 4. If writer is not undefined and backpressure is not stream.[[backpressure]], if (writer && backpressure != stream.backpressure()) { // 1. If backpressure is true, set writer.[[readyPromise]] to a new promise. if (backpressure) { writer->set_ready_promise(WebIDL::create_promise(realm)); } // 2. Otherwise, else { // 1. Assert: backpressure is false. // 2. Resolve writer.[[readyPromise]] with undefined. WebIDL::resolve_promise(realm, *writer->ready_promise(), JS::js_undefined()); } } // 5. Set stream.[[backpressure]] to backpressure. stream.set_backpressure(backpressure); } // https://streams.spec.whatwg.org/#writable-stream-default-writer-abort GC::Ref writable_stream_default_writer_abort(WritableStreamDefaultWriter& writer, JS::Value reason) { // 1. Let stream be writer.[[stream]]. auto stream = writer.stream(); // 2. Assert: stream is not undefined. VERIFY(stream); // 3. Return ! WritableStreamAbort(stream, reason). return writable_stream_abort(*stream, reason); } // https://streams.spec.whatwg.org/#writable-stream-default-writer-close GC::Ref writable_stream_default_writer_close(WritableStreamDefaultWriter& writer) { // 1. Let stream be writer.[[stream]]. auto stream = writer.stream(); // 2. Assert: stream is not undefined. VERIFY(stream); // 3. Return ! WritableStreamClose(stream). return writable_stream_close(*stream); } // https://streams.spec.whatwg.org/#writable-stream-default-writer-close-with-error-propagation GC::Ref writable_stream_default_writer_close_with_error_propagation(WritableStreamDefaultWriter& writer) { auto& realm = writer.realm(); // 1. Let stream be writer.[[stream]]. auto stream = writer.stream(); // 2. Assert: stream is not undefined. VERIFY(stream); // 3. Let state be stream.[[state]]. auto state = stream->state(); // 4. If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state is "closed", return a promise resolved with undefined. if (writable_stream_close_queued_or_in_flight(*stream) || state == WritableStream::State::Closed) return WebIDL::create_resolved_promise(realm, JS::js_undefined()); // 5. If state is "errored", return a promise rejected with stream.[[storedError]]. if (state == WritableStream::State::Errored) return WebIDL::create_rejected_promise(realm, stream->stored_error()); // 6. Assert: state is "writable" or "erroring". VERIFY(state == WritableStream::State::Writable || state == WritableStream::State::Erroring); // 7. Return ! WritableStreamDefaultWriterClose(writer). return writable_stream_default_writer_close(writer); } // https://streams.spec.whatwg.org/#writable-stream-default-writer-ensure-closed-promise-rejected void writable_stream_default_writer_ensure_closed_promise_rejected(WritableStreamDefaultWriter& writer, JS::Value error) { auto& realm = writer.realm(); // 1. If writer.[[closedPromise]].[[PromiseState]] is "pending", reject writer.[[closedPromise]] with error. if (as(*writer.closed_promise()->promise()).state() == JS::Promise::State::Pending) { WebIDL::reject_promise(realm, *writer.closed_promise(), error); } // 2. Otherwise, set writer.[[closedPromise]] to a promise rejected with error. else { writer.set_closed_promise(WebIDL::create_rejected_promise(realm, error)); } // 3. Set writer.[[closedPromise]].[[PromiseIsHandled]] to true. WebIDL::mark_promise_as_handled(*writer.closed_promise()); } // https://streams.spec.whatwg.org/#writable-stream-default-writer-ensure-ready-promise-rejected void writable_stream_default_writer_ensure_ready_promise_rejected(WritableStreamDefaultWriter& writer, JS::Value error) { auto& realm = writer.realm(); // 1. If writer.[[readyPromise]].[[PromiseState]] is "pending", reject writer.[[readyPromise]] with error. if (as(*writer.ready_promise()->promise()).state() == JS::Promise::State::Pending) { WebIDL::reject_promise(realm, *writer.ready_promise(), error); } // 2. Otherwise, set writer.[[readyPromise]] to a promise rejected with error. else { writer.set_ready_promise(WebIDL::create_rejected_promise(realm, error)); } // 3. Set writer.[[readyPromise]].[[PromiseIsHandled]] to true. WebIDL::mark_promise_as_handled(*writer.ready_promise()); } // https://streams.spec.whatwg.org/#writable-stream-default-writer-get-desired-size Optional writable_stream_default_writer_get_desired_size(WritableStreamDefaultWriter const& writer) { // 1. Let stream be writer.[[stream]]. auto stream = writer.stream(); // 2. Let state be stream.[[state]]. auto state = stream->state(); // 3. If state is "errored" or "erroring", return null. if (state == WritableStream::State::Errored || state == WritableStream::State::Erroring) return {}; // 4. If state is "closed", return 0. if (state == WritableStream::State::Closed) return 0.0; // 5. Return ! WritableStreamDefaultControllerGetDesiredSize(stream.[[controller]]). return writable_stream_default_controller_get_desired_size(*stream->controller()); } // https://streams.spec.whatwg.org/#writable-stream-default-writer-release void writable_stream_default_writer_release(WritableStreamDefaultWriter& writer) { auto& realm = writer.realm(); // 1. Let stream be writer.[[stream]]. auto stream = writer.stream(); // 2. Assert: stream is not undefined. VERIFY(stream); // 3. Assert: stream.[[writer]] is writer. VERIFY(stream->writer().ptr() == &writer); // 4. Let releasedError be a new TypeError. auto released_error = JS::TypeError::create(realm, "Writer's stream lock has been released"sv); // 5. Perform ! WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError). writable_stream_default_writer_ensure_ready_promise_rejected(writer, released_error); // 6. Perform ! WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError). writable_stream_default_writer_ensure_closed_promise_rejected(writer, released_error); // 7. Set stream.[[writer]] to undefined. stream->set_writer({}); // 8. Set writer.[[stream]] to undefined. writer.set_stream({}); } // https://streams.spec.whatwg.org/#writable-stream-default-writer-write GC::Ref writable_stream_default_writer_write(WritableStreamDefaultWriter& writer, JS::Value chunk) { auto& realm = writer.realm(); // 1. Let stream be writer.[[stream]]. auto stream = writer.stream(); // 2. Assert: stream is not undefined. VERIFY(stream); // 3. Let controller be stream.[[controller]]. auto controller = stream->controller(); // 4. Let chunkSize be ! WritableStreamDefaultControllerGetChunkSize(controller, chunk). auto chunk_size = writable_stream_default_controller_get_chunk_size(*controller, chunk); // 5. If stream is not equal to writer.[[stream]], return a promise rejected with a TypeError exception. if (stream.ptr() != writer.stream().ptr()) { auto exception = JS::TypeError::create(realm, "Writer's locked stream changed during write"sv); return WebIDL::create_rejected_promise(realm, exception); } // 6. Let state be stream.[[state]]. auto state = stream->state(); // 7. If state is "errored", return a promise rejected with stream.[[storedError]]. if (state == WritableStream::State::Errored) return WebIDL::create_rejected_promise(realm, stream->stored_error()); // 8. If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state is "closed", return a promise rejected with a TypeError exception indicating that the stream is closing or closed. if (writable_stream_close_queued_or_in_flight(*stream) || state == WritableStream::State::Closed) { auto exception = JS::TypeError::create(realm, "Cannot write to a writer whose stream is closing or already closed"sv); return WebIDL::create_rejected_promise(realm, exception); } // 9. If state is "erroring", return a promise rejected with stream.[[storedError]]. if (state == WritableStream::State::Erroring) return WebIDL::create_rejected_promise(realm, stream->stored_error()); // 10. Assert: state is "writable". VERIFY(state == WritableStream::State::Writable); // 11. Let promise be ! WritableStreamAddWriteRequest(stream). auto promise = writable_stream_add_write_request(*stream); // 12. Perform ! WritableStreamDefaultControllerWrite(controller, chunk, chunkSize). writable_stream_default_controller_write(*controller, chunk, chunk_size); // 13. Return promise. return promise; } // https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller WebIDL::ExceptionOr set_up_writable_stream_default_controller(WritableStream& stream, WritableStreamDefaultController& controller, GC::Ref start_algorithm, GC::Ref write_algorithm, GC::Ref close_algorithm, GC::Ref abort_algorithm, double high_water_mark, GC::Ref size_algorithm) { auto& realm = stream.realm(); // 1. Assert: stream implements WritableStream. // 2. Assert: stream.[[controller]] is undefined. VERIFY(!stream.controller()); // 3. Set controller.[[stream]] to stream. controller.set_stream(stream); // 4. Set stream.[[controller]] to controller. stream.set_controller(controller); // 5. Perform ! ResetQueue(controller). reset_queue(controller); // 6. Set controller.[[signal]] to a new AbortSignal. controller.set_signal(realm.create(realm)); // 7. Set controller.[[started]] to false. controller.set_started(false); // 8. Set controller.[[strategySizeAlgorithm]] to sizeAlgorithm. controller.set_strategy_size_algorithm(size_algorithm); // 9. Set controller.[[strategyHWM]] to highWaterMark. controller.set_strategy_hwm(high_water_mark); // 10. Set controller.[[writeAlgorithm]] to writeAlgorithm. controller.set_write_algorithm(write_algorithm); // 11. Set controller.[[closeAlgorithm]] to closeAlgorithm. controller.set_close_algorithm(close_algorithm); // 12. Set controller.[[abortAlgorithm]] to abortAlgorithm. controller.set_abort_algorithm(abort_algorithm); // 13. Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller). auto backpressure = writable_stream_default_controller_get_backpressure(controller); // 14. Perform ! WritableStreamUpdateBackpressure(stream, backpressure). writable_stream_update_backpressure(stream, backpressure); // 15. Let startResult be the result of performing startAlgorithm. (This may throw an exception.) auto start_result = TRY(start_algorithm->function()()); // 16. Let startPromise be a promise resolved with startResult. auto start_promise = WebIDL::create_resolved_promise(realm, start_result); WebIDL::react_to_promise(start_promise, // 17. Upon fulfillment of startPromise, GC::create_function(realm.heap(), [&controller, &stream](JS::Value) -> WebIDL::ExceptionOr { // 1. Assert: stream.[[state]] is "writable" or "erroring". VERIFY(first_is_one_of(stream.state(), WritableStream::State::Writable, WritableStream::State::Erroring)); // 2. Set controller.[[started]] to true. controller.set_started(true); // 3. Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller). writable_stream_default_controller_advance_queue_if_needed(controller); return JS::js_undefined(); }), // 18. Upon rejection of startPromise with reason r, GC::create_function(realm.heap(), [&stream, &controller](JS::Value reason) -> WebIDL::ExceptionOr { // 1. Assert: stream.[[state]] is "writable" or "erroring". VERIFY(first_is_one_of(stream.state(), WritableStream::State::Writable, WritableStream::State::Erroring)); // 2. Set controller.[[started]] to true. controller.set_started(true); // 3. Perform ! WritableStreamDealWithRejection(stream, r). writable_stream_deal_with_rejection(stream, reason); return JS::js_undefined(); })); return {}; } // https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller-from-underlying-sink WebIDL::ExceptionOr set_up_writable_stream_default_controller_from_underlying_sink(WritableStream& stream, JS::Value underlying_sink_value, UnderlyingSink& underlying_sink, double high_water_mark, GC::Ref size_algorithm) { auto& realm = stream.realm(); // 1. Let controller be a new WritableStreamDefaultController. auto controller = realm.create(realm); // 2. Let startAlgorithm be an algorithm that returns undefined. auto start_algorithm = GC::create_function(realm.heap(), []() -> WebIDL::ExceptionOr { return JS::js_undefined(); }); // 3. Let writeAlgorithm be an algorithm that returns a promise resolved with undefined. auto write_algorithm = GC::create_function(realm.heap(), [&realm](JS::Value) { return WebIDL::create_resolved_promise(realm, JS::js_undefined()); }); // 4. Let closeAlgorithm be an algorithm that returns a promise resolved with undefined. auto close_algorithm = GC::create_function(realm.heap(), [&realm]() { return WebIDL::create_resolved_promise(realm, JS::js_undefined()); }); // 5. Let abortAlgorithm be an algorithm that returns a promise resolved with undefined. auto abort_algorithm = GC::create_function(realm.heap(), [&realm](JS::Value) { return WebIDL::create_resolved_promise(realm, JS::js_undefined()); }); // 6. If underlyingSinkDict["start"] exists, then set startAlgorithm to an algorithm which returns the result of // invoking underlyingSinkDict["start"] with argument list « controller », exception behavior "rethrow", and // callback this value underlyingSink. if (underlying_sink.start) { start_algorithm = GC::create_function(realm.heap(), [controller, underlying_sink_value, callback = underlying_sink.start]() -> WebIDL::ExceptionOr { return TRY(WebIDL::invoke_callback(*callback, underlying_sink_value, WebIDL::ExceptionBehavior::Rethrow, { { controller } })); }); } // 7. If underlyingSinkDict["write"] exists, then set writeAlgorithm to an algorithm which takes an argument chunk // and returns the result of invoking underlyingSinkDict["write"] with argument list « chunk, controller » and // callback this value underlyingSink. if (underlying_sink.write) { write_algorithm = GC::create_function(realm.heap(), [controller, underlying_sink_value, callback = underlying_sink.write](JS::Value chunk) { return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, { { chunk, controller } }); }); } // 8. If underlyingSinkDict["close"] exists, then set closeAlgorithm to an algorithm which returns the result of // invoking underlyingSinkDict["close"] with argument list «» and callback this value underlyingSink. if (underlying_sink.close) { close_algorithm = GC::create_function(realm.heap(), [underlying_sink_value, callback = underlying_sink.close]() { return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, {}); }); } // 9. If underlyingSinkDict["abort"] exists, then set abortAlgorithm to an algorithm which takes an argument reason // and returns the result of invoking underlyingSinkDict["abort"] with argument list « reason » and callback this // value underlyingSink. if (underlying_sink.abort) { abort_algorithm = GC::create_function(realm.heap(), [underlying_sink_value, callback = underlying_sink.abort](JS::Value reason) { return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, { { reason } }); }); } // 10. Perform ? SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm). TRY(set_up_writable_stream_default_controller(stream, controller, start_algorithm, write_algorithm, close_algorithm, abort_algorithm, high_water_mark, size_algorithm)); return {}; } // https://streams.spec.whatwg.org/#writable-stream-default-controller-advance-queue-if-needed void writable_stream_default_controller_advance_queue_if_needed(WritableStreamDefaultController& controller) { // 1. Let stream be controller.[[stream]]. auto stream = controller.stream(); // 2. If controller.[[started]] is false, return. if (!controller.started()) return; // 3. If stream.[[inFlightWriteRequest]] is not undefined, return. if (stream->in_flight_write_request()) return; // 4. Let state be stream.[[state]]. auto state = stream->state(); // 5. Assert: state is not "closed" or "errored". VERIFY(state != WritableStream::State::Closed && state != WritableStream::State::Errored); // 6. If state is "erroring", if (state == WritableStream::State::Erroring) { // 1. Perform ! WritableStreamFinishErroring(stream). writable_stream_finish_erroring(stream); // 2. Return. return; } // 7. If controller.[[queue]] is empty, return. if (controller.queue().is_empty()) return; // 8. Let value be ! PeekQueueValue(controller). auto value = peek_queue_value(controller); // 9. If value is the close sentinel, perform ! WritableStreamDefaultControllerProcessClose(controller). if (is_close_sentinel(value)) { writable_stream_default_controller_process_close(controller); } // 10. Otherwise, perform ! WritableStreamDefaultControllerProcessWrite(controller, value). else { writable_stream_default_controller_process_write(controller, value); } } // https://streams.spec.whatwg.org/#writable-stream-default-controller-clear-algorithms void writable_stream_default_controller_clear_algorithms(WritableStreamDefaultController& controller) { // 1. Set controller.[[writeAlgorithm]] to undefined. controller.set_write_algorithm({}); // 2. Set controller.[[closeAlgorithm]] to undefined. controller.set_close_algorithm({}); // 3. Set controller.[[abortAlgorithm]] to undefined. controller.set_abort_algorithm({}); // 4. Set controller.[[strategySizeAlgorithm]] to undefined. controller.set_strategy_size_algorithm({}); } // https://streams.spec.whatwg.org/#writable-stream-default-controller-close void writable_stream_default_controller_close(WritableStreamDefaultController& controller) { // 1. Perform ! EnqueueValueWithSize(controller, close sentinel, 0). MUST(enqueue_value_with_size(controller, create_close_sentinel(), JS::Value(0.0))); // 2. Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller). writable_stream_default_controller_advance_queue_if_needed(controller); } // https://streams.spec.whatwg.org/#writable-stream-default-controller-error void writable_stream_default_controller_error(WritableStreamDefaultController& controller, JS::Value error) { // 1. Let stream be controller.[[stream]]. auto stream = controller.stream(); // 2. Assert: stream.[[state]] is "writable". VERIFY(stream->state() == WritableStream::State::Writable); // 3. Perform ! WritableStreamDefaultControllerClearAlgorithms(controller). writable_stream_default_controller_clear_algorithms(controller); // 4. Perform ! WritableStreamStartErroring(stream, error). writable_stream_start_erroring(stream, error); } // https://streams.spec.whatwg.org/#writable-stream-default-controller-error-if-needed void writable_stream_default_controller_error_if_needed(WritableStreamDefaultController& controller, JS::Value error) { // 1. If controller.[[stream]].[[state]] is "writable", perform ! WritableStreamDefaultControllerError(controller, error). if (controller.stream()->state() == WritableStream::State::Writable) writable_stream_default_controller_error(controller, error); } // https://streams.spec.whatwg.org/#writable-stream-default-controller-get-backpressure bool writable_stream_default_controller_get_backpressure(WritableStreamDefaultController const& controller) { // 1. Let desiredSize be ! WritableStreamDefaultControllerGetDesiredSize(controller). auto desired_size = writable_stream_default_controller_get_desired_size(controller); // 2. Return true if desiredSize ≤ 0, or false otherwise. return desired_size <= 0.0; } // https://streams.spec.whatwg.org/#writable-stream-default-controller-get-chunk-size JS::Value writable_stream_default_controller_get_chunk_size(WritableStreamDefaultController& controller, JS::Value chunk) { // 1. If controller.[[strategySizeAlgorithm]] is undefined, then: if (!controller.strategy_size_algorithm()) { // 1. Assert: controller.[[stream]].[[state]] is not "writable". VERIFY(controller.stream()->state() != WritableStream::State::Writable); // 2. Return 1. return JS::Value { 1.0 }; } // 2. Let returnValue be the result of performing controller.[[strategySizeAlgorithm]], passing in chunk, and interpreting the result as a completion record. auto return_value = controller.strategy_size_algorithm()->function()(chunk); // 3. If returnValue is an abrupt completion, if (return_value.is_abrupt()) { // 1. Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, returnValue.[[Value]]). writable_stream_default_controller_error_if_needed(controller, return_value.release_value()); // 2. Return 1. return JS::Value { 1.0 }; } // 4. Return returnValue.[[Value]]. return return_value.release_value(); } // https://streams.spec.whatwg.org/#writable-stream-default-controller-get-desired-size double writable_stream_default_controller_get_desired_size(WritableStreamDefaultController const& controller) { // 1. Return controller.[[strategyHWM]] − controller.[[queueTotalSize]]. return controller.strategy_hwm() - controller.queue_total_size(); } // https://streams.spec.whatwg.org/#writable-stream-default-controller-process-close void writable_stream_default_controller_process_close(WritableStreamDefaultController& controller) { // 1. Let stream be controller.[[stream]]. auto stream = controller.stream(); // 2. Perform ! WritableStreamMarkCloseRequestInFlight(stream). writable_stream_mark_close_request_in_flight(stream); // 3. Perform ! DequeueValue(controller). dequeue_value(controller); // 4. Assert: controller.[[queue]] is empty. VERIFY(controller.queue().is_empty()); // 5. Let sinkClosePromise be the result of performing controller.[[closeAlgorithm]]. auto sink_close_promise = controller.close_algorithm()->function()(); // 6. Perform ! WritableStreamDefaultControllerClearAlgorithms(controller). writable_stream_default_controller_clear_algorithms(controller); WebIDL::react_to_promise(sink_close_promise, // 7. Upon fulfillment of sinkClosePromise, GC::create_function(controller.heap(), [stream](JS::Value) -> WebIDL::ExceptionOr { // 1. Perform ! WritableStreamFinishInFlightClose(stream). writable_stream_finish_in_flight_close(stream); return JS::js_undefined(); }), // 8. Upon rejection of sinkClosePromise with reason reason, GC::create_function(controller.heap(), [stream](JS::Value reason) -> WebIDL::ExceptionOr { // 1. Perform ! WritableStreamFinishInFlightCloseWithError(stream, reason). writable_stream_finish_in_flight_close_with_error(stream, reason); return JS::js_undefined(); })); } // https://streams.spec.whatwg.org/#writable-stream-default-controller-process-write void writable_stream_default_controller_process_write(WritableStreamDefaultController& controller, JS::Value chunk) { // 1. Let stream be controller.[[stream]]. auto stream = controller.stream(); // 2. Perform ! WritableStreamMarkFirstWriteRequestInFlight(stream). writable_stream_mark_first_write_request_in_flight(stream); // 3. Let sinkWritePromise be the result of performing controller.[[writeAlgorithm]], passing in chunk. auto sink_write_promise = controller.write_algorithm()->function()(chunk); WebIDL::react_to_promise(sink_write_promise, // 4. Upon fulfillment of sinkWritePromise, GC::create_function(controller.heap(), [&controller, stream](JS::Value) -> WebIDL::ExceptionOr { // 1. Perform ! WritableStreamFinishInFlightWrite(stream). writable_stream_finish_in_flight_write(stream); // 2. Let state be stream.[[state]]. auto state = stream->state(); // 3. Assert: state is "writable" or "erroring". VERIFY(state == WritableStream::State::Writable || state == WritableStream::State::Erroring); // 4. Perform ! DequeueValue(controller). dequeue_value(controller); // 5. If ! WritableStreamCloseQueuedOrInFlight(stream) is false and state is "writable", if (!writable_stream_close_queued_or_in_flight(stream) && state == WritableStream::State::Writable) { // 1. Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller). auto backpressure = writable_stream_default_controller_get_backpressure(controller); // 2. Perform ! WritableStreamUpdateBackpressure(stream, backpressure). writable_stream_update_backpressure(stream, backpressure); } // 6 .Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller). writable_stream_default_controller_advance_queue_if_needed(controller); return JS::js_undefined(); }), // 5. Upon rejection of sinkWritePromise with reason, GC::create_function(controller.heap(), [&controller, stream](JS::Value reason) -> WebIDL::ExceptionOr { // 1. If stream.[[state]] is "writable", perform ! WritableStreamDefaultControllerClearAlgorithms(controller). if (stream->state() == WritableStream::State::Writable) writable_stream_default_controller_clear_algorithms(controller); // 2. Perform ! WritableStreamFinishInFlightWriteWithError(stream, reason). writable_stream_finish_in_flight_write_with_error(stream, reason); return JS::js_undefined(); })); } // https://streams.spec.whatwg.org/#writable-stream-default-controller-write void writable_stream_default_controller_write(WritableStreamDefaultController& controller, JS::Value chunk, JS::Value chunk_size) { auto& vm = controller.vm(); // 1. Let enqueueResult be EnqueueValueWithSize(controller, chunk, chunkSize). auto enqueue_result = enqueue_value_with_size(controller, chunk, chunk_size); // 2. If enqueueResult is an abrupt completion, if (enqueue_result.is_exception()) { auto throw_completion = Bindings::throw_dom_exception_if_needed(vm, [&] { return enqueue_result; }).throw_completion(); // 1. Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueResult.[[Value]]). writable_stream_default_controller_error_if_needed(controller, throw_completion.release_value()); // 2. Return. return; } // 3. Let stream be controller.[[stream]]. auto stream = controller.stream(); // 4. If ! WritableStreamCloseQueuedOrInFlight(stream) is false and stream.[[state]] is "writable", if (!writable_stream_close_queued_or_in_flight(stream) && stream->state() == WritableStream::State::Writable) { // 1. Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller). auto backpressure = writable_stream_default_controller_get_backpressure(controller); // 2. Perform ! WritableStreamUpdateBackpressure(stream, backpressure). writable_stream_update_backpressure(stream, backpressure); } // 5. Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller). writable_stream_default_controller_advance_queue_if_needed(controller); } }