diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-12-19 16:16:56 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-12-19 16:16:56 -0500 |
commit | bac9903fbeed0a394a86c0091e727aada665433d (patch) | |
tree | 15f61a4fdcc8bbcc09f10a39e25495fb49cb9a75 /components/script/dom/bindings/structuredclone.rs | |
parent | aa36d5f657eb32b59d994d08b177a02372b4b01c (diff) | |
parent | 6e8a85482c2068d4dbccb992954271f725570f91 (diff) | |
download | servo-bac9903fbeed0a394a86c0091e727aada665433d.tar.gz servo-bac9903fbeed0a394a86c0091e727aada665433d.zip |
Auto merge of #24123 - gterzian:redo_blob, r=jdm
Restructure Blob, structured serialization
<!-- Please describe your changes on the following line: -->
FIX #24052 and also address the "cloning" half of FIX #23917
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #___ (GitHub issue number if applicable)
<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because ___
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/24123)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script/dom/bindings/structuredclone.rs')
-rw-r--r-- | components/script/dom/bindings/structuredclone.rs | 201 |
1 files changed, 84 insertions, 117 deletions
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs index 25c440365c8..a61cdb0630c 100644 --- a/components/script/dom/bindings/structuredclone.rs +++ b/components/script/dom/bindings/structuredclone.rs @@ -10,8 +10,9 @@ use crate::dom::bindings::conversions::{root_from_object, ToJSValConvertible}; use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::serializable::{Serializable, StorageKey}; use crate::dom::bindings::transferable::Transferable; -use crate::dom::blob::{Blob, BlobImpl}; +use crate::dom::blob::Blob; use crate::dom::globalscope::GlobalScope; use crate::dom::messageport::MessagePort; use crate::script_runtime::JSContext as SafeJSContext; @@ -29,12 +30,12 @@ use js::jsapi::TransferableOwnership; use js::jsapi::JS_STRUCTURED_CLONE_VERSION; use js::jsapi::{JSObject, JS_ClearPendingException}; use js::jsapi::{JSStructuredCloneCallbacks, JSStructuredCloneReader, JSStructuredCloneWriter}; -use js::jsapi::{JS_ReadBytes, JS_WriteBytes}; use js::jsapi::{JS_ReadUint32Pair, JS_WriteUint32Pair}; use js::jsval::UndefinedValue; use js::rust::wrappers::{JS_ReadStructuredClone, JS_WriteStructuredClone}; use js::rust::{CustomAutoRooterGuard, HandleValue, MutableHandleValue}; -use msg::constellation_msg::MessagePortId; +use msg::constellation_msg::{BlobId, MessagePortId}; +use script_traits::serializable::BlobImpl; use script_traits::transferable::MessagePortImpl; use script_traits::StructuredSerializedData; use std::collections::HashMap; @@ -54,117 +55,62 @@ enum StructuredCloneTags { 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; +unsafe fn read_blob( + owner: &DomRoot<GlobalScope>, + r: *mut JSStructuredCloneReader, + mut sc_holder: &mut StructuredDataHolder, +) -> *mut JSObject { + let mut name_space: u32 = 0; + let mut index: u32 = 0; assert!(JS_ReadUint32Pair( r, - &mut length as *mut u32, - &mut zero as *mut u32 + &mut name_space as *mut u32, + &mut index as *mut u32 )); - return length as usize; + let storage_key = StorageKey { index, name_space }; + if <Blob as Serializable>::deserialize(&owner, &mut sc_holder, storage_key.clone()).is_ok() { + let blobs = match sc_holder { + StructuredDataHolder::Read { blobs, .. } => blobs, + _ => panic!("Unexpected variant of StructuredDataHolder"), + }; + if let Some(blobs) = blobs { + let blob = blobs + .get(&storage_key) + .expect("No blob found at storage key."); + return blob.reflector().get_jsobject().get(); + } + } + warn!( + "Reading structured data for a blob failed in {:?}.", + owner.get_url() + ); + ptr::null_mut() } -struct StructuredCloneWriter { +unsafe fn write_blob( + owner: &DomRoot<GlobalScope>, + blob: DomRoot<Blob>, w: *mut JSStructuredCloneWriter, -} - -impl StructuredCloneWriter { - unsafe fn write_slice(&self, v: &[u8]) { - let type_length = v.len(); - write_length(self.w, type_length); - assert!(JS_WriteBytes( - self.w, - v.as_ptr() as *const raw::c_void, - type_length + sc_holder: &mut StructuredDataHolder, +) -> bool { + if let Ok(storage_key) = blob.serialize(sc_holder) { + assert!(JS_WriteUint32Pair( + w, + StructuredCloneTags::DomBlob as u32, + 0 )); - } - unsafe fn write_str(&self, s: &str) { - self.write_slice(s.as_bytes()); - } -} - -struct StructuredCloneReader { - r: *mut JSStructuredCloneReader, -} - -impl StructuredCloneReader { - unsafe fn read_bytes(&self) -> Vec<u8> { - let mut bytes = vec![0u8; read_length(self.r)]; - let blob_length = bytes.len(); - assert!(JS_ReadBytes( - self.r, - bytes.as_mut_ptr() as *mut raw::c_void, - blob_length + assert!(JS_WriteUint32Pair( + w, + storage_key.name_space, + storage_key.index )); - return bytes; - } - unsafe fn read_str(&self) -> String { - let str_buffer = self.read_bytes(); - return String::from_utf8_unchecked(str_buffer); + return true; } -} - -unsafe fn read_blob( - cx: *mut JSContext, - r: *mut JSStructuredCloneReader, - sc_holder: &mut StructuredDataHolder, -) -> *mut JSObject { - let structured_reader = StructuredCloneReader { r: r }; - let blob_buffer = structured_reader.read_bytes(); - let type_str = structured_reader.read_str(); - let target_global = GlobalScope::from_context(cx); - let read_blob = Blob::new( - &target_global, - BlobImpl::new_from_bytes(blob_buffer), - type_str, + warn!( + "Writing structured data for a blob failed in {:?}.", + owner.get_url() ); - let js_object = read_blob.reflector().get_jsobject().get(); - match sc_holder { - StructuredDataHolder::Read { blob, .. } => { - *blob = Some(read_blob); - }, - _ => panic!("Unexpected variant of StructuredDataHolder"), - } - js_object -} - -unsafe fn write_blob(blob: DomRoot<Blob>, w: *mut JSStructuredCloneWriter) -> Result<(), ()> { - let structured_writer = StructuredCloneWriter { w: w }; - let blob_vec = blob.get_bytes()?; - assert!(JS_WriteUint32Pair( - w, - StructuredCloneTags::DomBlob as u32, - 0 - )); - structured_writer.write_slice(&blob_vec); - structured_writer.write_str(&blob.type_string()); - return Ok(()); + return false; } unsafe extern "C" fn read_callback( @@ -183,7 +129,11 @@ unsafe extern "C" fn read_callback( "tag should be higher than StructuredCloneTags::Min" ); if tag == StructuredCloneTags::DomBlob as u32 { - return read_blob(cx, r, &mut *(closure as *mut StructuredDataHolder)); + return read_blob( + &GlobalScope::from_context(cx), + r, + &mut *(closure as *mut StructuredDataHolder), + ); } return ptr::null_mut(); } @@ -192,10 +142,15 @@ unsafe extern "C" fn write_callback( cx: *mut JSContext, w: *mut JSStructuredCloneWriter, obj: RawHandleObject, - _closure: *mut raw::c_void, + closure: *mut raw::c_void, ) -> bool { if let Ok(blob) = root_from_object::<Blob>(*obj, cx) { - return write_blob(blob, w).is_ok(); + return write_blob( + &GlobalScope::from_context(cx), + blob, + w, + &mut *(closure as *mut StructuredDataHolder), + ); } return false; } @@ -282,8 +237,8 @@ static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredClon /// https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data pub enum StructuredDataHolder { Read { - /// A deserialized blob, stored temporarily here to keep it rooted. - blob: Option<DomRoot<Blob>>, + /// A map of deserialized blobs, stored temporarily here to keep them rooted. + blobs: Option<HashMap<StorageKey, DomRoot<Blob>>>, /// A vec of transfer-received DOM ports, /// to be made available to script through a message event. message_ports: Option<Vec<DomRoot<MessagePort>>>, @@ -291,10 +246,18 @@ pub enum StructuredDataHolder { /// used as part of the "transfer-receiving" steps of ports, /// to produce the DOM ports stored in `message_ports` above. port_impls: Option<HashMap<MessagePortId, MessagePortImpl>>, + /// A map of blob implementations, + /// used as part of the "deserialize" steps of blobs, + /// to produce the DOM blobs stored in `blobs` above. + blob_impls: Option<HashMap<BlobId, BlobImpl>>, + }, + /// A data holder for transferred and serialized objects. + Write { + /// Transferred ports. + ports: Option<HashMap<MessagePortId, MessagePortImpl>>, + /// Serialized blobs. + blobs: Option<HashMap<BlobId, BlobImpl>>, }, - /// A data holder into which transferred ports - /// can be written as part of their transfer steps. - Write(Option<HashMap<MessagePortId, MessagePortImpl>>), } /// Writes a structured clone. Returns a `DataClone` error if that fails. @@ -308,8 +271,10 @@ pub fn write( if let Some(transfer) = transfer { transfer.to_jsval(*cx, val.handle_mut()); } - - let mut sc_holder = StructuredDataHolder::Write(None); + let mut sc_holder = StructuredDataHolder::Write { + ports: None, + blobs: None, + }; let sc_holder_ptr = &mut sc_holder as *mut _; let scbuf = NewJSAutoStructuredCloneBuffer( @@ -343,14 +308,15 @@ pub fn write( DeleteJSAutoStructuredCloneBuffer(scbuf); - let mut port_impls = match sc_holder { - StructuredDataHolder::Write(port_impls) => port_impls, + let (mut blob_impls, mut port_impls) = match sc_holder { + StructuredDataHolder::Write { blobs, ports } => (blobs, ports), _ => panic!("Unexpected variant of StructuredDataHolder"), }; let data = StructuredSerializedData { serialized: data, ports: port_impls.take(), + blobs: blob_impls.take(), }; Ok(data) @@ -367,9 +333,10 @@ pub fn read( let cx = global.get_cx(); let _ac = enter_realm(&*global); let mut sc_holder = StructuredDataHolder::Read { - blob: None, + blobs: None, message_ports: None, port_impls: data.ports.take(), + blob_impls: data.blobs.take(), }; let sc_holder_ptr = &mut sc_holder as *mut _; unsafe { |