mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Support optional message for dataclone error (#36308)
- [x] our [DataClone error](d733abfca0/components/script/dom/bindings/error.rs (L80)
) needs to support an optional message - [x] we need to add support to our DOMException implementation to allow an optional message to replace the default message - [x] we need to create a new struct used by both StructuredDataReader and StructuredDataWriter for storing the error message in the report_error_callback - [x] report_error_callback needs to cast the closure pointer to the new struct - [x] the code that [throws a DataClone error](5d1c64dba9/components/script/dom/bindings/structuredclone.rs (L542)
) needs to use the stored error message if it's available Testing: *Describe how this pull request is tested or why it doesn't require tests* Fixes: #36191 --------- Signed-off-by: jerensl <54782057+jerensl@users.noreply.github.com>
This commit is contained in:
parent
740a94ef20
commit
d5284dfad9
7 changed files with 61 additions and 10 deletions
|
@ -574,7 +574,7 @@ impl BaseAudioContextMethods<crate::DomTypeHolder> for BaseAudioContext {
|
||||||
.decode_audio_data(audio_data, callbacks);
|
.decode_audio_data(audio_data, callbacks);
|
||||||
} else {
|
} else {
|
||||||
// Step 3.
|
// Step 3.
|
||||||
promise.reject_error(Error::DataClone, can_gc);
|
promise.reject_error(Error::DataClone(None), can_gc);
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,22 @@ pub(crate) fn throw_dom_exception(
|
||||||
Error::Abort => DOMErrorName::AbortError,
|
Error::Abort => DOMErrorName::AbortError,
|
||||||
Error::Timeout => DOMErrorName::TimeoutError,
|
Error::Timeout => DOMErrorName::TimeoutError,
|
||||||
Error::InvalidNodeType => DOMErrorName::InvalidNodeTypeError,
|
Error::InvalidNodeType => DOMErrorName::InvalidNodeTypeError,
|
||||||
Error::DataClone => DOMErrorName::DataCloneError,
|
Error::DataClone(message) => match message {
|
||||||
|
Some(custom_message) => unsafe {
|
||||||
|
assert!(!JS_IsExceptionPending(*cx));
|
||||||
|
let exception = DOMException::new_with_custom_message(
|
||||||
|
global,
|
||||||
|
DOMErrorName::DataCloneError,
|
||||||
|
custom_message,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
rooted!(in(*cx) let mut thrown = UndefinedValue());
|
||||||
|
exception.to_jsval(*cx, thrown.handle_mut());
|
||||||
|
JS_SetPendingException(*cx, thrown.handle(), ExceptionStackBehavior::Capture);
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
None => DOMErrorName::DataCloneError,
|
||||||
|
},
|
||||||
Error::NoModificationAllowed => DOMErrorName::NoModificationAllowedError,
|
Error::NoModificationAllowed => DOMErrorName::NoModificationAllowedError,
|
||||||
Error::QuotaExceeded => DOMErrorName::QuotaExceededError,
|
Error::QuotaExceeded => DOMErrorName::QuotaExceededError,
|
||||||
Error::TypeMismatch => DOMErrorName::TypeMismatchError,
|
Error::TypeMismatch => DOMErrorName::TypeMismatchError,
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
//! This module implements structured cloning, as defined by [HTML](https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data).
|
//! This module implements structured cloning, as defined by [HTML](https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data).
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ffi::CStr;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::os::raw;
|
use std::os::raw;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -312,6 +313,7 @@ unsafe extern "C" fn read_transfer_callback(
|
||||||
let sc_reader = &mut *(closure as *mut StructuredDataReader);
|
let sc_reader = &mut *(closure as *mut StructuredDataReader);
|
||||||
let in_realm_proof = AlreadyInRealm::assert_for_cx(SafeJSContext::from_ptr(cx));
|
let in_realm_proof = AlreadyInRealm::assert_for_cx(SafeJSContext::from_ptr(cx));
|
||||||
let owner = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof));
|
let owner = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof));
|
||||||
|
|
||||||
for transferrable in TransferrableInterface::iter() {
|
for transferrable in TransferrableInterface::iter() {
|
||||||
if tag == StructuredCloneTags::from(transferrable) as u32 {
|
if tag == StructuredCloneTags::from(transferrable) as u32 {
|
||||||
let transfer_receiver = receiver_for_type(transferrable);
|
let transfer_receiver = receiver_for_type(transferrable);
|
||||||
|
@ -439,9 +441,16 @@ unsafe extern "C" fn can_transfer_callback(
|
||||||
unsafe extern "C" fn report_error_callback(
|
unsafe extern "C" fn report_error_callback(
|
||||||
_cx: *mut JSContext,
|
_cx: *mut JSContext,
|
||||||
_errorid: u32,
|
_errorid: u32,
|
||||||
_closure: *mut ::std::os::raw::c_void,
|
closure: *mut raw::c_void,
|
||||||
_error_message: *const ::std::os::raw::c_char,
|
error_message: *const ::std::os::raw::c_char,
|
||||||
) {
|
) {
|
||||||
|
let msg_result = unsafe { CStr::from_ptr(error_message).to_str().map(str::to_string) };
|
||||||
|
|
||||||
|
if let Ok(msg) = msg_result {
|
||||||
|
let dom_error_record = &mut *(closure as *mut DOMErrorRecord);
|
||||||
|
|
||||||
|
dom_error_record.message = Some(msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn sab_cloned_callback(
|
unsafe extern "C" fn sab_cloned_callback(
|
||||||
|
@ -468,9 +477,18 @@ pub(crate) enum StructuredData<'a> {
|
||||||
Writer(&'a mut StructuredDataWriter),
|
Writer(&'a mut StructuredDataWriter),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct DOMErrorRecord {
|
||||||
|
pub(crate) message: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Reader and writer structs for results from, and inputs to, structured-data read/write operations.
|
/// Reader and writer structs for results from, and inputs to, structured-data read/write operations.
|
||||||
/// <https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data>
|
/// <https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data>
|
||||||
|
#[repr(C)]
|
||||||
pub(crate) struct StructuredDataReader {
|
pub(crate) struct StructuredDataReader {
|
||||||
|
/// A struct of error message.
|
||||||
|
pub(crate) errors: DOMErrorRecord,
|
||||||
/// A map of deserialized blobs, stored temporarily here to keep them rooted.
|
/// A map of deserialized blobs, stored temporarily here to keep them rooted.
|
||||||
pub(crate) blobs: Option<HashMap<StorageKey, DomRoot<Blob>>>,
|
pub(crate) blobs: Option<HashMap<StorageKey, DomRoot<Blob>>>,
|
||||||
/// A map of deserialized points, stored temporarily here to keep them rooted.
|
/// A map of deserialized points, stored temporarily here to keep them rooted.
|
||||||
|
@ -493,7 +511,10 @@ pub(crate) struct StructuredDataReader {
|
||||||
|
|
||||||
/// A data holder for transferred and serialized objects.
|
/// A data holder for transferred and serialized objects.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
#[repr(C)]
|
||||||
pub(crate) struct StructuredDataWriter {
|
pub(crate) struct StructuredDataWriter {
|
||||||
|
/// Error message.
|
||||||
|
pub(crate) errors: DOMErrorRecord,
|
||||||
/// Transferred ports.
|
/// Transferred ports.
|
||||||
pub(crate) ports: Option<HashMap<MessagePortId, MessagePortImpl>>,
|
pub(crate) ports: Option<HashMap<MessagePortId, MessagePortImpl>>,
|
||||||
/// Serialized points.
|
/// Serialized points.
|
||||||
|
@ -537,7 +558,7 @@ pub(crate) fn write(
|
||||||
);
|
);
|
||||||
if !result {
|
if !result {
|
||||||
JS_ClearPendingException(*cx);
|
JS_ClearPendingException(*cx);
|
||||||
return Err(Error::DataClone);
|
return Err(Error::DataClone(sc_writer.errors.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
let nbytes = GetLengthOfJSStructuredCloneData(scdata);
|
let nbytes = GetLengthOfJSStructuredCloneData(scdata);
|
||||||
|
@ -575,6 +596,7 @@ pub(crate) fn read(
|
||||||
port_impls: data.ports.take(),
|
port_impls: data.ports.take(),
|
||||||
blob_impls: data.blobs.take(),
|
blob_impls: data.blobs.take(),
|
||||||
points: data.points.take(),
|
points: data.points.take(),
|
||||||
|
errors: DOMErrorRecord { message: None },
|
||||||
};
|
};
|
||||||
let sc_reader_ptr = &mut sc_reader as *mut _;
|
let sc_reader_ptr = &mut sc_reader as *mut _;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -605,14 +627,13 @@ pub(crate) fn read(
|
||||||
);
|
);
|
||||||
if !result {
|
if !result {
|
||||||
JS_ClearPendingException(*cx);
|
JS_ClearPendingException(*cx);
|
||||||
return Err(Error::DataClone);
|
return Err(Error::DataClone(sc_reader.errors.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteJSAutoStructuredCloneBuffer(scbuf);
|
DeleteJSAutoStructuredCloneBuffer(scbuf);
|
||||||
|
|
||||||
// Any transfer-received port-impls should have been taken out.
|
// Any transfer-received port-impls should have been taken out.
|
||||||
assert!(sc_reader.port_impls.is_none());
|
assert!(sc_reader.port_impls.is_none());
|
||||||
|
|
||||||
Ok(sc_reader.message_ports.take().unwrap_or_default())
|
Ok(sc_reader.message_ports.take().unwrap_or_default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,21 @@ impl DOMException {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_with_custom_message(
|
||||||
|
global: &GlobalScope,
|
||||||
|
code: DOMErrorName,
|
||||||
|
message: String,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> DomRoot<DOMException> {
|
||||||
|
let (_, name) = DOMException::get_error_data_by_code(code);
|
||||||
|
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(DOMException::new_inherited(DOMString::from(message), name)),
|
||||||
|
global,
|
||||||
|
can_gc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// not an IDL stringifier, used internally
|
// not an IDL stringifier, used internally
|
||||||
pub(crate) fn stringifier(&self) -> DOMString {
|
pub(crate) fn stringifier(&self) -> DOMString {
|
||||||
DOMString::from(format!("{}: {}", self.name, self.message))
|
DOMString::from(format!("{}: {}", self.name, self.message))
|
||||||
|
|
|
@ -3215,7 +3215,7 @@ impl GlobalScope {
|
||||||
|
|
||||||
let data = structuredclone::write(cx, value, Some(guard))?;
|
let data = structuredclone::write(cx, value, Some(guard))?;
|
||||||
|
|
||||||
structuredclone::read(self, data, retval).map_err(|_| Error::DataClone)?;
|
structuredclone::read(self, data, retval).map_err(|_| Error::DataClone(None))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ impl MessagePort {
|
||||||
for port in ports {
|
for port in ports {
|
||||||
// Step 2
|
// Step 2
|
||||||
if port.message_port_id() == self.message_port_id() {
|
if port.message_port_id() == self.message_port_id() {
|
||||||
return Err(Error::DataClone);
|
return Err(Error::DataClone(None));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
|
|
|
@ -44,7 +44,7 @@ pub enum Error {
|
||||||
/// InvalidNodeTypeError DOMException
|
/// InvalidNodeTypeError DOMException
|
||||||
InvalidNodeType,
|
InvalidNodeType,
|
||||||
/// DataCloneError DOMException
|
/// DataCloneError DOMException
|
||||||
DataClone,
|
DataClone(Option<String>),
|
||||||
/// NoModificationAllowedError DOMException
|
/// NoModificationAllowedError DOMException
|
||||||
NoModificationAllowed,
|
NoModificationAllowed,
|
||||||
/// QuotaExceededError DOMException
|
/// QuotaExceededError DOMException
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue