summaryrefslogtreecommitdiff
path: root/core/bindings.rs
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2021-06-26 11:17:05 +0200
committerGitHub <noreply@github.com>2021-06-26 11:17:05 +0200
commit22e7b0f585fb3715ef1894b2c26a0e3cbbd43e9e (patch)
tree164afa9ed31212b5df8d0d79a6929dde5eb8302e /core/bindings.rs
parent1f4cdc067a4e26921ee53d58751bb60279d3cab2 (diff)
fix: MessagePort in message for postMessage transfers (#11103)
Diffstat (limited to 'core/bindings.rs')
-rw-r--r--core/bindings.rs135
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,