diff options
Diffstat (limited to 'components/script/dom/writablestream.rs')
-rw-r--r-- | components/script/dom/writablestream.rs | 146 |
1 files changed, 143 insertions, 3 deletions
diff --git a/components/script/dom/writablestream.rs b/components/script/dom/writablestream.rs index bbc5d6316b6..c8a91cd7475 100644 --- a/components/script/dom/writablestream.rs +++ b/components/script/dom/writablestream.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::collections::VecDeque; use std::mem; use std::ptr::{self}; @@ -15,6 +15,7 @@ use js::rust::{ HandleObject as SafeHandleObject, HandleValue as SafeHandleValue, MutableHandleValue as SafeMutableHandleValue, }; +use script_bindings::codegen::GenericBindings::MessagePortBinding::MessagePortMethods; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::QueuingStrategyBinding::QueuingStrategy; @@ -22,16 +23,20 @@ use crate::dom::bindings::codegen::Bindings::UnderlyingSinkBinding::UnderlyingSi use crate::dom::bindings::codegen::Bindings::WritableStreamBinding::WritableStreamMethods; use crate::dom::bindings::conversions::ConversionResult; use crate::dom::bindings::error::{Error, Fallible}; -use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto}; +use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::countqueuingstrategy::{extract_high_water_mark, extract_size_algorithm}; +use crate::dom::domexception::{DOMErrorName, DOMException}; use crate::dom::globalscope::GlobalScope; +use crate::dom::messageport::MessagePort; use crate::dom::promise::Promise; use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler}; +use crate::dom::readablestream::get_type_and_value_from_message; use crate::dom::writablestreamdefaultcontroller::{ UnderlyingSinkType, WritableStreamDefaultController, }; use crate::dom::writablestreamdefaultwriter::WritableStreamDefaultWriter; +use crate::js::conversions::ToJSValConvertible; use crate::realms::{InRealm, enter_realm}; use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; @@ -175,7 +180,7 @@ impl WritableStream { } } - fn new_with_proto( + pub(crate) fn new_with_proto( global: &GlobalScope, proto: Option<SafeHandleObject>, can_gc: CanGc, @@ -834,6 +839,58 @@ impl WritableStream { // Set stream.[[backpressure]] to backpressure. self.set_backpressure(backpressure); } + + /// <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable> + pub(crate) fn setup_cross_realm_transform_writable( + &self, + cx: SafeJSContext, + port: &MessagePort, + can_gc: CanGc, + ) { + let port_id = port.message_port_id(); + let global = self.global(); + + // Perform ! InitializeWritableStream(stream). + // Done in `new_inherited`. + + // Let sizeAlgorithm be an algorithm that returns 1. + // Re-ordered because of the need to pass it to `new`. + let size_algorithm = extract_size_algorithm(&QueuingStrategy::default(), can_gc); + + // Note: other algorithms defined in the controller at call site. + + // Let backpressurePromise be a new promise. + let backpressure_promise = Rc::new(RefCell::new(Some(Promise::new(&global, can_gc)))); + + // Let controller be a new WritableStreamDefaultController. + let controller = WritableStreamDefaultController::new( + &global, + UnderlyingSinkType::Transfer { + backpressure_promise: backpressure_promise.clone(), + port: Dom::from_ref(port), + }, + &UnderlyingSink::empty(), + 1.0, + size_algorithm, + can_gc, + ); + + // Add a handler for port’s message event with the following steps: + // Add a handler for port’s messageerror event with the following steps: + rooted!(in(*cx) let cross_realm_transform_writable = CrossRealmTransformWritable { + controller: Dom::from_ref(&controller), + backpressure_promise: backpressure_promise.clone(), + }); + global.note_cross_realm_transform_writable(&cross_realm_transform_writable, port_id); + + // Enable port’s port message queue. + port.Start(); + + // Perform ! SetUpWritableStreamDefaultController + controller + .setup(cx, &global, self, &None, can_gc) + .expect("Setup for transfer cannot fail"); + } } impl WritableStreamMethods<crate::DomTypeHolder> for WritableStream { @@ -967,3 +1024,86 @@ impl WritableStreamMethods<crate::DomTypeHolder> for WritableStream { self.aquire_default_writer(cx, &global, can_gc) } } + +impl js::gc::Rootable for CrossRealmTransformWritable {} + +/// <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable> +/// A wrapper to handle `message` and `messageerror` events +/// for the port used by the transfered stream. +#[derive(Clone, JSTraceable, MallocSizeOf)] +#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] +pub(crate) struct CrossRealmTransformWritable { + /// The controller used in the algorithm. + controller: Dom<WritableStreamDefaultController>, + + /// The `backpressurePromise` used in the algorithm. + #[ignore_malloc_size_of = "Rc is hard"] + backpressure_promise: Rc<RefCell<Option<Rc<Promise>>>>, +} + +impl CrossRealmTransformWritable { + /// <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable> + /// Add a handler for port’s message event with the following steps: + #[allow(unsafe_code)] + pub(crate) fn handle_message( + &self, + cx: SafeJSContext, + global: &GlobalScope, + message: SafeHandleValue, + _realm: InRealm, + can_gc: CanGc, + ) { + rooted!(in(*cx) let mut value = UndefinedValue()); + let type_string = + unsafe { get_type_and_value_from_message(cx, message, value.handle_mut(), can_gc) }; + + // If type is "pull", + // Done below as the steps are the same for both types. + + // Otherwise, if type is "error", + if type_string == "error" { + // Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, value). + self.controller + .error_if_needed(cx, value.handle(), global, can_gc); + } + + let backpressure_promise = self.backpressure_promise.borrow_mut().take(); + + // Note: the below steps are for both "pull" and "error" types. + // If backpressurePromise is not undefined, + if let Some(promise) = backpressure_promise { + // Resolve backpressurePromise with undefined. + promise.resolve_native(&(), can_gc); + + // Set backpressurePromise to undefined. + // Done above with `take`. + } + } + + /// <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable> + /// Add a handler for port’s messageerror event with the following steps: + #[allow(unsafe_code)] + pub(crate) fn handle_error( + &self, + cx: SafeJSContext, + global: &GlobalScope, + port: &MessagePort, + _realm: InRealm, + can_gc: CanGc, + ) { + // Let error be a new "DataCloneError" DOMException. + let error = DOMException::new(global, DOMErrorName::DataCloneError, can_gc); + rooted!(in(*cx) let mut rooted_error = UndefinedValue()); + unsafe { error.to_jsval(*cx, rooted_error.handle_mut()) }; + + // Perform ! CrossRealmTransformSendError(port, error). + port.cross_realm_transform_send_error(rooted_error.handle(), can_gc); + + // Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, error). + self.controller + .error_if_needed(cx, rooted_error.handle(), global, can_gc); + + // Disentangle port. + global.disentangle_port(port); + } +} |