aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/structuredclone.rs
diff options
context:
space:
mode:
authorGregory Terzian <gterzian@users.noreply.github.com>2017-02-19 17:08:03 +0800
committerGregory Terzian <gterzian@users.noreply.github.com>2017-03-22 09:52:35 +0800
commit5c4f0be04872f5f2e8736b15a2169f9479509a0e (patch)
treefb29ded994dfe0624f3f235fc701c64d13c6fbf0 /components/script/dom/bindings/structuredclone.rs
parentec84560e7f87d594df6701563fa3aa2b6e45e826 (diff)
downloadservo-5c4f0be04872f5f2e8736b15a2169f9479509a0e.tar.gz
servo-5c4f0be04872f5f2e8736b15a2169f9479509a0e.zip
support structured cloning for Blob
Diffstat (limited to 'components/script/dom/bindings/structuredclone.rs')
-rw-r--r--components/script/dom/bindings/structuredclone.rs137
1 files changed, 113 insertions, 24 deletions
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs
index bb744ee022d..ed3cf6aa6e2 100644
--- a/components/script/dom/bindings/structuredclone.rs
+++ b/components/script/dom/bindings/structuredclone.rs
@@ -5,12 +5,17 @@
//! This module implements structured cloning, as defined by [HTML]
//! (https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data).
+use dom::bindings::conversions::root_from_handleobject;
use dom::bindings::error::{Error, Fallible};
+use dom::bindings::js::Root;
+use dom::bindings::reflector::DomObject;
+use dom::blob::{Blob, BlobImpl};
use dom::globalscope::GlobalScope;
-use js::jsapi::{Handle, HandleObject, HandleValue, MutableHandleValue};
-use js::jsapi::{Heap, JSContext};
+use js::jsapi::{Handle, HandleObject, HandleValue, MutableHandleValue, JSAutoCompartment, JSContext};
use js::jsapi::{JSStructuredCloneCallbacks, JSStructuredCloneReader, JSStructuredCloneWriter};
use js::jsapi::{JS_ClearPendingException, JSObject, JS_ReadStructuredClone};
+use js::jsapi::{JS_ReadBytes, JS_WriteBytes};
+use js::jsapi::{JS_ReadUint32Pair, JS_WriteUint32Pair};
use js::jsapi::{JS_STRUCTURED_CLONE_VERSION, JS_WriteStructuredClone};
use js::jsapi::{MutableHandleObject, TransferableOwnership};
use libc::size_t;
@@ -18,47 +23,127 @@ use std::os::raw;
use std::ptr;
use std::slice;
+// TODO: Should we add Min and Max const to https://github.com/servo/rust-mozjs/blob/master/src/consts.rs?
+// TODO: Determine for sure which value Min and Max should have.
+// NOTE: Current values found at https://dxr.mozilla.org/mozilla-central/
+// rev/ff04d410e74b69acfab17ef7e73e7397602d5a68/js/public/StructuredClone.h#323
+#[repr(u32)]
+enum StructuredCloneTags {
+ /// To support additional types, add new tags with values incremented from the last one before Max.
+ Min = 0xFFFF8000,
+ DomBlob = 0xFFFF8001,
+ Max = 0xFFFFFFFF,
+}
+
+#[cfg(target_pointer_width = "64")]
+unsafe fn write_length(w: *mut JSStructuredCloneWriter,
+ length: usize) {
+ let high: u32 = (length >> 32) as u32;
+ let low: u32 = length as u32;
+ assert!(JS_WriteUint32Pair(w, high, low));
+}
+
+#[cfg(target_pointer_width = "32")]
+unsafe fn write_length(w: *mut JSStructuredCloneWriter,
+ length: usize) {
+ assert!(JS_WriteUint32Pair(w, length as u32, 0));
+}
+
+#[cfg(target_pointer_width = "64")]
+unsafe fn read_length(r: *mut JSStructuredCloneReader)
+ -> usize {
+ let mut high: u32 = 0;
+ let mut low: u32 = 0;
+ assert!(JS_ReadUint32Pair(r, &mut high as *mut u32, &mut low as *mut u32));
+ return (low << high) as usize;
+}
+
+#[cfg(target_pointer_width = "32")]
+unsafe fn read_length(r: *mut JSStructuredCloneReader)
+ -> usize {
+ let mut length: u32 = 0;
+ let mut zero: u32 = 0;
+ assert!(JS_ReadUint32Pair(r, &mut length as *mut u32, &mut zero as *mut u32));
+ return length as usize;
+}
+
+unsafe fn read_blob(cx: *mut JSContext,
+ r: *mut JSStructuredCloneReader)
+ -> *mut JSObject {
+ let blob_length = read_length(r);
+ let type_str_length = read_length(r);
+ let mut blob_buffer = vec![0u8; blob_length];
+ assert!(JS_ReadBytes(r, blob_buffer.as_mut_ptr() as *mut raw::c_void, blob_length));
+ let mut type_str_buffer = vec![0u8; type_str_length];
+ assert!(JS_ReadBytes(r, type_str_buffer.as_mut_ptr() as *mut raw::c_void, type_str_length));
+ let type_str = String::from_utf8_unchecked(type_str_buffer);
+ let target_global = GlobalScope::from_context(cx);
+ let blob = Blob::new(&target_global, BlobImpl::new_from_bytes(blob_buffer), type_str);
+ return blob.reflector().get_jsobject().get()
+}
+
+unsafe fn write_blob(blob: Root<Blob>,
+ w: *mut JSStructuredCloneWriter)
+ -> Result<(), ()> {
+ let blob_vec = try!(blob.get_bytes());
+ let blob_length = blob_vec.len();
+ let type_string_bytes = blob.get_type_string().as_bytes().to_vec();
+ let type_string_length = type_string_bytes.len();
+ assert!(JS_WriteUint32Pair(w, StructuredCloneTags::DomBlob as u32, 0));
+ write_length(w, blob_length);
+ write_length(w, type_string_length);
+ assert!(JS_WriteBytes(w, blob_vec.as_ptr() as *const raw::c_void, blob_length));
+ assert!(JS_WriteBytes(w, type_string_bytes.as_ptr() as *const raw::c_void, type_string_length));
+ return Ok(())
+}
-#[allow(dead_code)]
-unsafe extern "C" fn read_callback(_cx: *mut JSContext,
- _r: *mut JSStructuredCloneReader,
- _tag: u32,
+unsafe extern "C" fn read_callback(cx: *mut JSContext,
+ r: *mut JSStructuredCloneReader,
+ tag: u32,
_data: u32,
- _closure: *mut raw::c_void) -> *mut JSObject {
- Heap::default().get()
+ _closure: *mut raw::c_void)
+ -> *mut JSObject {
+ assert!(tag < StructuredCloneTags::Max as u32, "tag should be lower than StructuredCloneTags::Max");
+ assert!(tag > StructuredCloneTags::Min as u32, "tag should be higher than StructuredCloneTags::Min");
+ if tag == StructuredCloneTags::DomBlob as u32 {
+ return read_blob(cx, r)
+ }
+ return ptr::null_mut()
}
-#[allow(dead_code)]
unsafe extern "C" fn write_callback(_cx: *mut JSContext,
- _w: *mut JSStructuredCloneWriter,
- _obj: HandleObject,
- _closure: *mut raw::c_void) -> bool {
- false
+ w: *mut JSStructuredCloneWriter,
+ obj: HandleObject,
+ _closure: *mut raw::c_void)
+ -> bool {
+ if let Ok(blob) = root_from_handleobject::<Blob>(obj) {
+ return write_blob(blob, w).is_ok()
+ }
+ return false
}
-#[allow(dead_code)]
unsafe extern "C" fn read_transfer_callback(_cx: *mut JSContext,
_r: *mut JSStructuredCloneReader,
_tag: u32,
_content: *mut raw::c_void,
_extra_data: u64,
_closure: *mut raw::c_void,
- _return_object: MutableHandleObject) -> bool {
+ _return_object: MutableHandleObject)
+ -> bool {
false
}
-#[allow(dead_code)]
unsafe extern "C" fn write_transfer_callback(_cx: *mut JSContext,
_obj: Handle<*mut JSObject>,
_closure: *mut raw::c_void,
_tag: *mut u32,
_ownership: *mut TransferableOwnership,
_content: *mut *mut raw::c_void,
- _extra_data: *mut u64) -> bool {
+ _extra_data: *mut u64)
+ -> bool {
false
}
-#[allow(dead_code)]
unsafe extern "C" fn free_transfer_callback(_tag: u32,
_ownership: TransferableOwnership,
_content: *mut raw::c_void,
@@ -66,11 +151,9 @@ unsafe extern "C" fn free_transfer_callback(_tag: u32,
_closure: *mut raw::c_void) {
}
-#[allow(dead_code)]
unsafe extern "C" fn report_error_callback(_cx: *mut JSContext, _errorid: u32) {
}
-#[allow(dead_code)]
static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredCloneCallbacks {
read: Some(read_callback),
write: Some(write_callback),
@@ -98,7 +181,7 @@ impl StructuredCloneData {
message,
&mut data,
&mut nbytes,
- ptr::null(),
+ &STRUCTURED_CLONE_CALLBACKS,
ptr::null_mut(),
HandleValue::undefined())
};
@@ -126,14 +209,20 @@ impl StructuredCloneData {
/// Reads a structured clone.
///
/// Panics if `JS_ReadStructuredClone` fails.
- fn read_clone(global: &GlobalScope, data: *mut u64, nbytes: size_t, rval: MutableHandleValue) {
+ fn read_clone(global: &GlobalScope,
+ data: *mut u64,
+ nbytes: size_t,
+ rval: MutableHandleValue) {
+ let cx = global.get_cx();
+ let globalhandle = global.reflector().get_jsobject();
+ let _ac = JSAutoCompartment::new(cx, globalhandle.get());
unsafe {
- assert!(JS_ReadStructuredClone(global.get_cx(),
+ assert!(JS_ReadStructuredClone(cx,
data,
nbytes,
JS_STRUCTURED_CLONE_VERSION,
rval,
- ptr::null(),
+ &STRUCTURED_CLONE_CALLBACKS,
ptr::null_mut()));
}
}