diff options
author | Luca Casonato <hello@lcas.dev> | 2021-06-26 11:17:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-26 11:17:05 +0200 |
commit | 22e7b0f585fb3715ef1894b2c26a0e3cbbd43e9e (patch) | |
tree | 164afa9ed31212b5df8d0d79a6929dde5eb8302e /core/bindings.rs | |
parent | 1f4cdc067a4e26921ee53d58751bb60279d3cab2 (diff) |
fix: MessagePort in message for postMessage transfers (#11103)
Diffstat (limited to 'core/bindings.rs')
-rw-r--r-- | core/bindings.rs | 135 |
1 files changed, 125 insertions, 10 deletions
diff --git a/core/bindings.rs b/core/bindings.rs index a0a3a1cc4..c96a8559c 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -11,6 +11,7 @@ use crate::PromiseId; use crate::ZeroCopyBuf; use log::debug; use rusty_v8 as v8; +use serde::Deserialize; use serde::Serialize; use serde_v8::to_v8; use std::convert::TryFrom; @@ -35,6 +36,9 @@ lazy_static::lazy_static! { function: queue_microtask.map_fn_to() }, v8::ExternalReference { + function: create_host_object.map_fn_to() + }, + v8::ExternalReference { function: encode.map_fn_to() }, v8::ExternalReference { @@ -130,6 +134,7 @@ pub fn initialize_context<'s>( set_func(scope, core_val, "getPromiseDetails", get_promise_details); set_func(scope, core_val, "getProxyDetails", get_proxy_details); set_func(scope, core_val, "memoryUsage", memory_usage); + set_func(scope, core_val, "createHostObject", create_host_object); // Direct bindings on `window`. set_func(scope, global, "queueMicrotask", queue_microtask); @@ -514,9 +519,11 @@ fn decode( }; } -struct SerializeDeserialize {} +struct SerializeDeserialize<'a> { + host_objects: Option<v8::Local<'a, v8::Array>>, +} -impl v8::ValueSerializerImpl for SerializeDeserialize { +impl<'a> v8::ValueSerializerImpl for SerializeDeserialize<'a> { #[allow(unused_variables)] fn throw_data_clone_error<'s>( &mut self, @@ -526,30 +533,104 @@ impl v8::ValueSerializerImpl for SerializeDeserialize { let error = v8::Exception::error(scope, message); scope.throw_exception(error); } + + fn write_host_object<'s>( + &mut self, + scope: &mut v8::HandleScope<'s>, + object: v8::Local<'s, v8::Object>, + value_serializer: &mut dyn v8::ValueSerializerHelper, + ) -> Option<bool> { + if let Some(host_objects) = self.host_objects { + for i in 0..host_objects.length() { + let value = host_objects.get_index(scope, i).unwrap(); + if value == object { + value_serializer.write_uint32(i); + return Some(true); + } + } + } + let message = v8::String::new(scope, "Unsupported object type").unwrap(); + self.throw_data_clone_error(scope, message); + None + } } -impl v8::ValueDeserializerImpl for SerializeDeserialize {} +impl<'a> v8::ValueDeserializerImpl for SerializeDeserialize<'a> { + fn read_host_object<'s>( + &mut self, + scope: &mut v8::HandleScope<'s>, + value_deserializer: &mut dyn v8::ValueDeserializerHelper, + ) -> Option<v8::Local<'s, v8::Object>> { + if let Some(host_objects) = self.host_objects { + let mut i = 0; + if !value_deserializer.read_uint32(&mut i) { + return None; + } + let maybe_value = host_objects.get_index(scope, i); + if let Some(value) = maybe_value { + return value.to_object(scope); + } + } + + let message = + v8::String::new(scope, "Failed to deserialize host object").unwrap(); + let error = v8::Exception::error(scope, message); + scope.throw_exception(error); + None + } +} fn serialize( scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { - let serialize_deserialize = Box::new(SerializeDeserialize {}); + let value = args.get(0); + + let options: Option<SerializeDeserializeOptions> = + match serde_v8::from_v8(scope, args.get(1)) { + Ok(opts) => opts, + Err(_) => { + throw_type_error(scope, "Invalid argument 2"); + return; + } + }; + + let options = + options.unwrap_or(SerializeDeserializeOptions { host_objects: None }); + + let host_objects = match options.host_objects { + Some(value) => match v8::Local::<v8::Array>::try_from(value.v8_value) { + Ok(host_objects) => Some(host_objects), + Err(_) => { + throw_type_error(scope, "host_objects not an array"); + return; + } + }, + None => None, + }; + + let serialize_deserialize = Box::new(SerializeDeserialize { host_objects }); let mut value_serializer = v8::ValueSerializer::new(scope, serialize_deserialize); - match value_serializer.write_value(scope.get_current_context(), args.get(0)) { + match value_serializer.write_value(scope.get_current_context(), value) { Some(true) => { let vector = value_serializer.release(); let zbuf: ZeroCopyBuf = vector.into(); rv.set(to_v8(scope, zbuf).unwrap()); } _ => { - throw_type_error(scope, "Invalid argument"); + throw_type_error(scope, "Failed to serialize response"); } } } +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct SerializeDeserializeOptions<'a> { + host_objects: Option<serde_v8::Value<'a>>, +} + fn deserialize( scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, @@ -558,15 +639,37 @@ fn deserialize( let zero_copy: ZeroCopyBuf = match serde_v8::from_v8(scope, args.get(0)) { Ok(zbuf) => zbuf, Err(_) => { - throw_type_error(scope, "Invalid argument"); + throw_type_error(scope, "Invalid argument 1"); return; } }; - let buf = &zero_copy; - let serialize_deserialize = Box::new(SerializeDeserialize {}); + let options: Option<SerializeDeserializeOptions> = + match serde_v8::from_v8(scope, args.get(1)) { + Ok(opts) => opts, + Err(_) => { + throw_type_error(scope, "Invalid argument 2"); + return; + } + }; + + let options = + options.unwrap_or(SerializeDeserializeOptions { host_objects: None }); + + let host_objects = match options.host_objects { + Some(value) => match v8::Local::<v8::Array>::try_from(value.v8_value) { + Ok(host_objects) => Some(host_objects), + Err(_) => { + throw_type_error(scope, "host_objects not an array"); + return; + } + }, + None => None, + }; + + let serialize_deserialize = Box::new(SerializeDeserialize { host_objects }); let mut value_deserializer = - v8::ValueDeserializer::new(scope, serialize_deserialize, buf); + v8::ValueDeserializer::new(scope, serialize_deserialize, &zero_copy); let value = value_deserializer.read_value(scope.get_current_context()); match value { @@ -592,6 +695,18 @@ fn queue_microtask( }; } +fn create_host_object( + scope: &mut v8::HandleScope, + _args: v8::FunctionCallbackArguments, + mut rv: v8::ReturnValue, +) { + let template = v8::ObjectTemplate::new(scope); + template.set_internal_field_count(1); + if let Some(obj) = template.new_instance(scope) { + rv.set(obj.into()); + }; +} + /// Called by V8 during `JsRuntime::instantiate_module`. /// /// This function borrows `ModuleMap` from the isolate slot, |