begin messageport, transferable objects, impl

Accept transfer argument for StructuredCloneData::write

Allow structured clone reads to return a boolean

Add Transferable trait

Add basic skeletons to MessagePort

Implement transfer and transfer-receiving steps on MessagePort

Use transfer and transfer_receive in StructuredClone callbacks

Implement MessageChannel

Freeze the array object for the MessageEvent ports attribute

Implement transfer argument on window.postMessage

Use ReentrantMutex instead for MessagePortInternal

Accept origin as a parameter in dispatch_jsval

Fix BorrowMut crash with pending_port_message

Detach port on closure and check for detached during transfer

Enable webmessaging tests

fix webidl

fix
This commit is contained in:
Keith Yeung 2016-12-11 03:52:08 -08:00 committed by Gregory Terzian
parent 605ddbecd4
commit c3b17c1201
37 changed files with 801 additions and 81 deletions

2
Cargo.lock generated
View file

@ -3154,6 +3154,7 @@ dependencies = [
"malloc_size_of_derive",
"parking_lot",
"serde",
"servo_url",
"size_of_test",
"webrender_api",
]
@ -4134,6 +4135,7 @@ dependencies = [
"app_units",
"backtrace",
"base64",
"bincode",
"bitflags",
"bluetooth_traits",
"canvas_traits",

View file

@ -419,6 +419,7 @@ pub enum ScriptHangAnnotation {
ExitFullscreen,
WebVREvent,
PerformanceTimelineTask,
PortMessage,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]

View file

@ -136,6 +136,7 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::ScriptParseHTML => "Script Parse HTML",
ProfilerCategory::ScriptParseXML => "Script Parse XML",
ProfilerCategory::ScriptPlannedNavigation => "Script Planned Navigation",
ProfilerCategory::ScriptPortMessage => "Script Port Message",
ProfilerCategory::ScriptResize => "Script Resize",
ProfilerCategory::ScriptEvent => "Script Event",
ProfilerCategory::ScriptUpdateReplacedElement => "Script Update Replaced Element",

View file

@ -108,6 +108,7 @@ pub enum ProfilerCategory {
ScriptWorkletEvent = 0x7a,
ScriptPerformanceEvent = 0x7b,
ScriptHistoryEvent = 0x7c,
ScriptPortMessage = 0x7d,
TimeToFirstPaint = 0x80,
TimeToFirstContentfulPaint = 0x81,
TimeToInteractive = 0x82,

View file

@ -97,6 +97,7 @@ servo_config = {path = "../config"}
servo_geometry = {path = "../geometry" }
servo-media = {git = "https://github.com/servo/media"}
servo_rand = {path = "../rand"}
servo_remutex = {path = "../remutex"}
servo_url = {path = "../url"}
sparkle = "0.1"
smallvec = { version = "0.6", features = ["std", "union"] }

View file

@ -12,7 +12,10 @@ pub enum WorkerScriptMsg {
/// Common variants associated with the script messages
Common(CommonScriptMsg),
/// Message sent through Worker.postMessage
DOMMessage(StructuredCloneData),
DOMMessage {
origin: String,
data: StructuredCloneData,
}
}
pub struct SimpleWorkerErrorHandler<T: DomObject> {

View file

@ -75,7 +75,7 @@ impl ScriptPort for Receiver<DedicatedWorkerScriptMsg> {
};
match common_msg {
WorkerScriptMsg::Common(script_msg) => Ok(script_msg),
WorkerScriptMsg::DOMMessage(_) => panic!("unexpected worker event message!"),
WorkerScriptMsg::DOMMessage { .. } => panic!("unexpected worker event message!"),
}
}
}

View file

@ -154,6 +154,7 @@ pub mod settings_stack;
pub mod str;
pub mod structuredclone;
pub mod trace;
pub mod transferable;
pub mod utils;
pub mod weakref;
pub mod xmlname;

View file

@ -10,8 +10,10 @@ use crate::dom::bindings::conversions::root_from_handleobject;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::transferable::Transferable;
use crate::dom::blob::{Blob, BlobImpl};
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageport::MessagePort;
use js::glue::CopyJSStructuredCloneData;
use js::glue::DeleteJSAutoStructuredCloneBuffer;
use js::glue::GetLengthOfJSStructuredCloneData;
@ -44,6 +46,7 @@ enum StructuredCloneTags {
/// To support additional types, add new tags with values incremented from the last one before Max.
Min = 0xFFFF8000,
DomBlob = 0xFFFF8001,
MessagePort = 0xFFFF8002,
Max = 0xFFFFFFFF,
}
@ -189,26 +192,43 @@ unsafe extern "C" fn write_callback(
}
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: RawMutableHandleObject,
cx: *mut JSContext,
r: *mut JSStructuredCloneReader,
tag: u32,
content: *mut raw::c_void,
extra_data: u64,
closure: *mut raw::c_void,
return_object: RawMutableHandleObject,
) -> bool {
false
if tag == StructuredCloneTags::MessagePort as u32 {
<MessagePort as Transferable>::transfer_receive(cx, r, closure, content, extra_data, return_object)
} else {
false
}
}
/// <https://html.spec.whatwg.org/multipage/#structuredserializewithtransfer>
unsafe extern "C" fn write_transfer_callback(
_cx: *mut JSContext,
_obj: RawHandleObject,
_closure: *mut raw::c_void,
_tag: *mut u32,
_ownership: *mut TransferableOwnership,
_content: *mut *mut raw::c_void,
_extra_data: *mut u64,
obj: RawHandleObject,
closure: *mut raw::c_void,
tag: *mut u32,
ownership: *mut TransferableOwnership,
content: *mut *mut raw::c_void,
extra_data: *mut u64,
) -> bool {
if let Ok(port) = root_from_handleobject::<MessagePort>(Handle::from_raw(obj)) {
if let Some(true) = port.detached() {
return false;
}
*tag = StructuredCloneTags::MessagePort as u32;
*ownership = TransferableOwnership::SCTAG_TMO_CUSTOM;
if port.transfer(closure, content, extra_data) {
port.set_detached(true);
return true;
}
}
false
}
@ -256,7 +276,11 @@ pub enum StructuredCloneData {
impl StructuredCloneData {
// TODO: should this be unsafe?
/// Writes a structured clone. Returns a `DataClone` error if that fails.
pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData> {
pub fn write(
cx: *mut JSContext,
message: HandleValue,
transfer: HandleValue,
) -> Fallible<StructuredCloneData> {
unsafe {
let scbuf = NewJSAutoStructuredCloneBuffer(
StructuredCloneScope::DifferentProcess,
@ -275,7 +299,7 @@ impl StructuredCloneData {
policy,
&STRUCTURED_CLONE_CALLBACKS,
ptr::null_mut(),
HandleValue::undefined(),
transfer,
);
if !result {
JS_ClearPendingException(cx);
@ -306,7 +330,12 @@ 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,
) -> bool {
let cx = global.get_cx();
let _ac = enter_realm(&*global);
let mut sc_holder = StructuredCloneHolder { blob: None };
@ -320,31 +349,33 @@ impl StructuredCloneData {
WriteBytesToJSStructuredCloneData(data as *const u8, nbytes, scdata);
assert!(JS_ReadStructuredClone(
*cx,
scdata,
JS_STRUCTURED_CLONE_VERSION,
StructuredCloneScope::DifferentProcess,
rval,
&STRUCTURED_CLONE_CALLBACKS,
sc_holder_ptr as *mut raw::c_void
));
let result = JS_ReadStructuredClone(
*cx,
scdata,
JS_STRUCTURED_CLONE_VERSION,
StructuredCloneScope::DifferentProcess,
rval,
&STRUCTURED_CLONE_CALLBACKS,
sc_holder_ptr as *mut raw::c_void
);
DeleteJSAutoStructuredCloneBuffer(scbuf);
result
}
}
/// Thunk for the actual `read_clone` method. Resolves proper variant for read_clone.
pub fn read(self, global: &GlobalScope, rval: MutableHandleValue) {
pub fn read(self, global: &GlobalScope, rval: MutableHandleValue) -> bool {
match self {
StructuredCloneData::Vector(mut vec_msg) => {
let nbytes = vec_msg.len();
let data = vec_msg.as_mut_ptr() as *mut u64;
StructuredCloneData::read_clone(global, data, nbytes, rval);
},
StructuredCloneData::read_clone(global, data, nbytes, rval)
}
StructuredCloneData::Struct(data, nbytes) => {
StructuredCloneData::read_clone(global, data, nbytes, rval)
},
}
}
}
}

View file

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Trait representing the concept of [transferable objects]
//! (https://html.spec.whatwg.org/multipage/#transferable-objects).
use crate::dom::bindings::reflector::DomObject;
use js::jsapi::{JSContext, JSStructuredCloneReader, MutableHandleObject};
use std::os::raw;
pub trait Transferable : DomObject {
fn transfer(
&self,
closure: *mut raw::c_void,
content: *mut *mut raw::c_void,
extra_data: *mut u64,
) -> bool;
fn transfer_receive(
cx: *mut JSContext,
r: *mut JSStructuredCloneReader,
closure: *mut raw::c_void,
content: *mut raw::c_void,
extra_data: u64,
return_object: MutableHandleObject,
) -> bool;
fn detached(&self) -> Option<bool> { None }
fn set_detached(&self, _value: bool) { }
fn transferable(&self) -> bool { false }
}

View file

@ -462,13 +462,20 @@ impl DedicatedWorkerGlobalScope {
fn handle_script_event(&self, msg: WorkerScriptMsg) {
match msg {
WorkerScriptMsg::DOMMessage(data) => {
WorkerScriptMsg::DOMMessage { origin, data } => {
let scope = self.upcast::<WorkerGlobalScope>();
let target = self.upcast();
let _ac = enter_realm(self);
rooted!(in(*scope.get_cx()) let mut message = UndefinedValue());
data.read(scope.upcast(), message.handle_mut());
MessageEvent::dispatch_jsval(target, scope.upcast(), message.handle(), None, None);
assert!(data.read(scope.upcast(), message.handle_mut()));
MessageEvent::dispatch_jsval(
target,
scope.upcast(),
message.handle(),
Some(&origin),
None,
vec![],
);
},
WorkerScriptMsg::Common(msg) => {
self.upcast::<WorkerGlobalScope>().process_event(msg);
@ -562,11 +569,13 @@ unsafe extern "C" fn interrupt_callback(cx: *mut JSContext) -> bool {
impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope {
// https://html.spec.whatwg.org/multipage/#dom-dedicatedworkerglobalscope-postmessage
fn PostMessage(&self, cx: SafeJSContext, message: HandleValue) -> ErrorResult {
let data = StructuredCloneData::write(*cx, message)?;
rooted!(in(*cx) let transfer = UndefinedValue());
let data = StructuredCloneData::write(*cx, message, transfer.handle())?;
let worker = self.worker.borrow().as_ref().unwrap().clone();
let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
let pipeline_id = self.global().pipeline_id();
let origin = self.global().origin().immutable().ascii_serialization();
let task = Box::new(task!(post_worker_message: move || {
Worker::handle_message(worker, data);
Worker::handle_message(worker, origin, data);
}));
// TODO: Change this task source to a new `unshipped-port-message-queue` task source
self.parent_sender

View file

@ -150,7 +150,8 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
// Step 1-2, 6-8.
// TODO(#12717): Should implement the `transfer` argument.
let data = StructuredCloneData::write(*cx, message)?;
rooted!(in(*cx) let transfer = UndefinedValue());
let data = StructuredCloneData::write(*cx, message, transfer.handle())?;
// Step 9.
self.post_message(origin, data);

View file

@ -236,6 +236,7 @@ impl EventSourceContext {
DOMString::from(self.origin.clone()),
None,
event_source.last_event_id.borrow().clone(),
vec![],
)
};
// Step 7

View file

@ -33,6 +33,7 @@ use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::file_reading::FileReadingTaskSource;
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_source::TaskSourceName;
@ -504,7 +505,7 @@ impl GlobalScope {
unreachable!();
}
/// `ScriptChan` to send messages to the networking task source of
/// `TaskSource` to send messages to the networking task source of
/// this global scope.
pub fn networking_task_source(&self) -> NetworkingTaskSource {
if let Some(window) = self.downcast::<Window>() {
@ -516,7 +517,19 @@ impl GlobalScope {
unreachable!();
}
/// `ScriptChan` to send messages to the remote-event task source of
/// `TaskSource` to send messages to the port message queue of
/// this global scope.
pub fn port_message_queue(&self) -> PortMessageQueue {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().port_message_queue();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.port_message_queue();
}
unreachable!();
}
/// `TaskSource` to send messages to the remote-event task source of
/// this global scope.
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
if let Some(window) = self.downcast::<Window>() {
@ -528,7 +541,7 @@ impl GlobalScope {
unreachable!();
}
/// `ScriptChan` to send messages to the websocket task source of
/// `TaskSource` to send messages to the websocket task source of
/// this global scope.
pub fn websocket_task_source(&self) -> WebsocketTaskSource {
if let Some(window) = self.downcast::<Window>() {
@ -537,7 +550,7 @@ impl GlobalScope {
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.websocket_task_source();
}
unreachable!();
unreachable!()
}
/// Evaluate JS code on this global scope.

View file

@ -185,7 +185,8 @@ impl History {
// TODO: Step 4
// Step 5
let serialized_data = StructuredCloneData::write(*cx, data)?.move_to_arraybuffer();
rooted!(in(cx) let transfer = UndefinedValue());
let serialized_data = StructuredCloneData::write(*cx, data, transfer.handle())?.move_to_arraybuffer();
let new_url: ServoUrl = match url {
// Step 6

View file

@ -0,0 +1,60 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::codegen::Bindings::MessageChannelBinding::{MessageChannelMethods, Wrap};
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageport::MessagePort;
use dom_struct::dom_struct;
#[dom_struct]
pub struct MessageChannel {
reflector_: Reflector,
port1: Dom<MessagePort>,
port2: Dom<MessagePort>,
}
impl MessageChannel {
/// <https://html.spec.whatwg.org/multipage/#dom-messagechannel>
pub fn Constructor(global: &GlobalScope) -> Fallible<DomRoot<MessageChannel>> {
let incumbent = GlobalScope::incumbent().ok_or(Error::InvalidState)?;
// Step 1
let port1 = MessagePort::new(&incumbent);
// Step 2
let port2 = MessagePort::new(&incumbent);
// Step 3
port1.entangle(&port2);
// Steps 4-6
let channel = reflect_dom_object(Box::new(
MessageChannel {
reflector_: Reflector::new(),
port1: Dom::from_ref(&port1),
port2: Dom::from_ref(&port2),
}),
global,
Wrap
);
// Step 7
Ok(channel)
}
}
impl MessageChannelMethods for MessageChannel {
/// <https://html.spec.whatwg.org/multipage/#dom-messagechannel-port1>
fn Port1(&self) -> DomRoot<MessagePort> {
DomRoot::from_ref(&*self.port1)
}
/// <https://html.spec.whatwg.org/multipage/#dom-messagechannel-port2>
fn Port2(&self) -> DomRoot<MessagePort> {
DomRoot::from_ref(&*self.port2)
}
}

View file

@ -14,11 +14,14 @@ use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageport::MessagePort;
use crate::dom::windowproxy::WindowProxy;
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use js::jsval::JSVal;
use js::conversions::ToJSValConvertible;
use js::jsapi::{Heap, JS_FreezeObject, JSContext, JSObject};
use js::jsapi::HandleObject as RawHandleObject;
use js::jsval::{JSVal, UndefinedValue};
use js::rust::HandleValue;
use servo_atoms::Atom;
use std::ptr::NonNull;
@ -31,6 +34,7 @@ pub struct MessageEvent {
origin: DOMString,
source: Option<Dom<WindowProxy>>,
lastEventId: DOMString,
ports: Vec<DomRoot<MessagePort>>,
}
impl MessageEvent {
@ -41,6 +45,7 @@ impl MessageEvent {
DOMString::new(),
None,
DOMString::new(),
vec![],
)
}
@ -50,13 +55,15 @@ impl MessageEvent {
origin: DOMString,
source: Option<&WindowProxy>,
lastEventId: DOMString,
ports: Vec<DomRoot<MessagePort>>,
) -> DomRoot<MessageEvent> {
let ev = Box::new(MessageEvent {
event: Event::new_inherited(),
data: Heap::default(),
origin: origin,
source: source.map(Dom::from_ref),
lastEventId: lastEventId,
origin,
lastEventId,
ports,
});
let ev = reflect_dom_object(ev, global, MessageEventBinding::Wrap);
ev.data.set(data.get());
@ -73,8 +80,9 @@ impl MessageEvent {
origin: DOMString,
source: Option<&WindowProxy>,
lastEventId: DOMString,
ports: Vec<DomRoot<MessagePort>>,
) -> DomRoot<MessageEvent> {
let ev = MessageEvent::new_initialized(global, data, origin, source, lastEventId);
let ev = MessageEvent::new_initialized(global, data, origin, source, lastEventId, ports);
{
let event = ev.upcast::<Event>();
event.init_event(type_, bubbles, cancelable);
@ -100,6 +108,7 @@ impl MessageEvent {
init.origin.clone(),
source.as_ref().map(|source| &**source),
init.lastEventId.clone(),
init.ports.clone().unwrap_or(vec![])
);
Ok(ev)
}
@ -112,6 +121,7 @@ impl MessageEvent {
message: HandleValue,
origin: Option<&str>,
source: Option<&WindowProxy>,
ports: Vec<DomRoot<MessagePort>>,
) {
let messageevent = MessageEvent::new(
scope,
@ -122,18 +132,19 @@ impl MessageEvent {
DOMString::from(origin.unwrap_or("")),
source,
DOMString::new(),
ports,
);
messageevent.upcast::<Event>().fire(target);
}
}
impl MessageEventMethods for MessageEvent {
// https://html.spec.whatwg.org/multipage/#dom-messageevent-data
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-data>
fn Data(&self, _cx: JSContext) -> JSVal {
self.data.get()
}
// https://html.spec.whatwg.org/multipage/#dom-messageevent-origin
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-origin>
fn Origin(&self) -> DOMString {
self.origin.clone()
}
@ -145,13 +156,24 @@ impl MessageEventMethods for MessageEvent {
.and_then(|source| NonNull::new(source.reflector().get_jsobject().get()))
}
// https://html.spec.whatwg.org/multipage/#dom-messageevent-lasteventid
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-lasteventid>
fn LastEventId(&self) -> DOMString {
self.lastEventId.clone()
}
// https://dom.spec.whatwg.org/#dom-event-istrusted
/// <https://dom.spec.whatwg.org/#dom-event-istrusted>
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
#[allow(unsafe_code)]
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-ports>
unsafe fn Ports(&self, cx: *mut JSContext) -> JSVal {
rooted!(in(cx) let mut ports = UndefinedValue());
self.ports.to_jsval(cx, ports.handle_mut());
rooted!(in(cx) let obj = ports.to_object());
JS_FreezeObject(cx, RawHandleObject::from(obj.handle()));
*ports
}
}

View file

@ -0,0 +1,395 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use crate::dom::bindings::codegen::Bindings::MessagePortBinding::{MessagePortMethods, Wrap};
use crate::dom::bindings::conversions::{ToJSValConvertible, root_from_object};
use crate::dom::bindings::error::{Error, ErrorResult};
use crate::dom::bindings::inheritance::{Castable, HasParent};
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{DomObject, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::structuredclone::StructuredCloneData;
use crate::dom::bindings::trace::JSTraceable;
use crate::dom::bindings::transferable::Transferable;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent;
use crate::task_source::TaskSource;
use crate::task_source::port_message::PortMessageQueue;
use js::jsapi::{JSContext, JSStructuredCloneReader, JSObject, JSTracer, MutableHandleObject};
use js::jsval::UndefinedValue;
use js::rust::{CustomAutoRooterGuard, HandleValue};
use servo_remutex::ReentrantMutex;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::mem;
use std::os::raw;
use std::rc::Rc;
use std::sync::Arc;
// FIXME: This is wrong, we need to figure out a better way of collecting message port objects per transfer
thread_local! {
pub static TRANSFERRED_MESSAGE_PORTS: RefCell<Vec<DomRoot<MessagePort>>> = RefCell::new(Vec::new())
}
struct PortMessageTask {
origin: String,
data: Vec<u8>,
}
pub struct MessagePortInternal {
dom_port: RefCell<Option<Trusted<MessagePort>>>,
port_message_queue: RefCell<PortMessageQueue>,
enabled: Cell<bool>,
has_been_shipped: Cell<bool>,
entangled_port: RefCell<Option<Arc<ReentrantMutex<MessagePortInternal>>>>,
pending_port_messages: RefCell<VecDeque<PortMessageTask>>,
}
impl MessagePortInternal {
fn new(port_message_queue: PortMessageQueue) -> MessagePortInternal {
MessagePortInternal {
dom_port: RefCell::new(None),
port_message_queue: RefCell::new(port_message_queue),
enabled: Cell::new(false),
has_been_shipped: Cell::new(false),
entangled_port: RefCell::new(None),
pending_port_messages: RefCell::new(VecDeque::new()),
}
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
// Step 7 substeps
#[allow(unrooted_must_root)]
fn process_pending_port_messages(&self) {
let PortMessageTask { origin, data } = match self.pending_port_messages.borrow_mut().pop_front() {
Some(task) => task,
None => return,
};
// Substep 1
let final_target_port = self.dom_port.borrow().as_ref().unwrap().root();
// Substep 2
let target_global = final_target_port.global();
// Substep 3-4
rooted!(in(target_global.get_cx()) let mut message_clone = UndefinedValue());
let deserialize_result = StructuredCloneData::Vector(data).read(
&target_global,
message_clone.handle_mut()
);
if !deserialize_result {
return;
}
// Substep 5
let new_ports = TRANSFERRED_MESSAGE_PORTS.with(|list| {
mem::replace(&mut *list.borrow_mut(), vec![])
});
// Substep 6
MessageEvent::dispatch_jsval(
final_target_port.upcast(),
&target_global,
message_clone.handle(),
Some(&origin),
None,
new_ports,
);
}
}
#[derive(DenyPublicFields, DomObject, MallocSizeOf)]
#[must_root]
#[repr(C)]
pub struct MessagePort {
eventtarget: EventTarget,
detached: Cell<bool>,
#[ignore_malloc_size_of = "Defined in std"]
message_port_internal: Arc<ReentrantMutex<MessagePortInternal>>,
}
#[allow(unsafe_code)]
unsafe impl JSTraceable for MessagePort {
unsafe fn trace(&self, trc: *mut JSTracer) {
if !self.detached.get() {
self.eventtarget.trace(trc);
}
// Otherwise, do nothing.
}
}
impl HasParent for MessagePort {
type Parent = EventTarget;
fn as_parent(&self) -> &EventTarget {
&self.eventtarget
}
}
impl MessagePort {
fn new_inherited(global: &GlobalScope) -> MessagePort {
MessagePort {
eventtarget: EventTarget::new_inherited(),
detached: Cell::new(false),
message_port_internal: Arc::new(
ReentrantMutex::new(
MessagePortInternal::new(global.port_message_queue().clone())
)
),
}
}
fn new_transferred(message_port_internal: Arc<ReentrantMutex<MessagePortInternal>>) -> MessagePort {
MessagePort {
eventtarget: EventTarget::new_inherited(),
detached: Cell::new(false),
message_port_internal,
}
}
/// <https://html.spec.whatwg.org/multipage/#create-a-new-messageport-object>
pub fn new(owner: &GlobalScope) -> DomRoot<MessagePort> {
let message_port = reflect_dom_object(Box::new(MessagePort::new_inherited(owner)), owner, Wrap);
{
let internal = message_port.message_port_internal.lock().unwrap();
*internal.dom_port.borrow_mut() = Some(Trusted::new(&*message_port));
}
message_port
}
/// <https://html.spec.whatwg.org/multipage/#entangle>
pub fn entangle(&self, other: &MessagePort) {
{
let internal = self.message_port_internal.lock().unwrap();
*internal.entangled_port.borrow_mut() = Some(other.message_port_internal.clone());
}
let internal = other.message_port_internal.lock().unwrap();
*internal.entangled_port.borrow_mut() = Some(self.message_port_internal.clone());
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
// Step 7 substeps
fn process_pending_port_messages(&self) {
if self.detached.get() { return; }
let internal = self.message_port_internal.lock().unwrap();
internal.process_pending_port_messages();
}
}
impl Transferable for MessagePort {
/// <https://html.spec.whatwg.org/multipage/#message-ports:transfer-steps>
#[allow(unsafe_code)]
fn transfer(
&self,
_closure: *mut raw::c_void,
content: *mut *mut raw::c_void,
extra_data: *mut u64
) -> bool {
{
let internal = self.message_port_internal.lock().unwrap();
// Step 1
internal.has_been_shipped.set(true);
// Step 3
if let Some(ref other_port) = *internal.entangled_port.borrow() {
let entangled_internal = other_port.lock().unwrap();
// Substep 1
entangled_internal.has_been_shipped.set(true);
}; // This line MUST contain a semicolon, due to the strict drop check rule
}
unsafe {
// Steps 2, 3.2 and 4
*content = Arc::into_raw(self.message_port_internal.clone()) as *mut raw::c_void;
*extra_data = 0;
}
true
}
/// https://html.spec.whatwg.org/multipage/#message-ports:transfer-receiving-steps
#[allow(unrooted_must_root, unsafe_code)]
fn transfer_receive(
cx: *mut JSContext,
_r: *mut JSStructuredCloneReader,
_closure: *mut raw::c_void,
content: *mut raw::c_void,
_extra_data: u64,
return_object: MutableHandleObject
) -> bool {
let internal = unsafe { Arc::from_raw(content as *const ReentrantMutex<MessagePortInternal>) };
let value = MessagePort::new_transferred(internal);
// Step 2
let owner = unsafe { GlobalScope::from_context(cx) };
let message_port = reflect_dom_object(Box::new(value), &*owner, Wrap);
{
let internal = message_port.message_port_internal.lock().unwrap();
// Step 1
internal.has_been_shipped.set(true);
let dom_port = Trusted::new(&*message_port);
internal.enabled.set(false);
*internal.dom_port.borrow_mut() = Some(dom_port);
*internal.port_message_queue.borrow_mut() = owner.port_message_queue().clone();
}
return_object.set(message_port.reflector().rootable().get());
TRANSFERRED_MESSAGE_PORTS.with(|list| {
list.borrow_mut().push(message_port);
});
true
}
fn detached(&self) -> Option<bool> {
Some(self.detached.get())
}
fn set_detached(&self, value: bool) {
self.detached.set(value);
}
fn transferable(&self) -> bool {
!self.detached.get()
}
}
impl MessagePortMethods for MessagePort {
#[allow(unsafe_code)]
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
unsafe fn PostMessage(
&self,
cx: *mut JSContext,
message: HandleValue,
transfer: CustomAutoRooterGuard<Option<Vec<*mut JSObject>>>,
) -> ErrorResult {
if self.detached.get() { return Ok(()); }
let internal = self.message_port_internal.lock().unwrap();
// Step 1
let target_port = internal.entangled_port.borrow();
// Step 3
let mut doomed = false;
rooted!(in(cx) let mut val = UndefinedValue());
let transfer = match *transfer {
Some(ref vec) => {
let ports = vec.iter().filter_map(|&obj| root_from_object::<MessagePort>(obj).ok());
for port in ports {
// Step 2
if Arc::ptr_eq(&port.message_port_internal, &self.message_port_internal) {
return Err(Error::DataClone);
}
// Step 4
if let Some(target) = target_port.as_ref() {
if Arc::ptr_eq(&port.message_port_internal, target) {
doomed = true;
}
}
}
vec.to_jsval(cx, val.handle_mut());
val
}
None => {
Vec::<*mut JSObject>::new().to_jsval(cx, val.handle_mut());
val
}
};
// Step 5
let data = StructuredCloneData::write(cx, message, transfer.handle())?.move_to_arraybuffer();
// Step 6
if target_port.is_none() || doomed { return Ok(()); }
// Step 7
let task = PortMessageTask {
origin: self.global().origin().immutable().ascii_serialization(),
data,
};
{
let target_port = target_port.as_ref().unwrap();
let target_internal = target_port.lock().unwrap();
target_internal.pending_port_messages.borrow_mut().push_back(task);
if target_internal.enabled.get() {
let target_port = target_port.clone();
let _ = target_internal.port_message_queue.borrow().queue(
task!(process_pending_port_messages: move || {
let internal = target_port.lock().unwrap();
internal.process_pending_port_messages();
}),
&self.global()
);
}
}
Ok(())
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
fn Start(&self) {
let len = {
let internal = self.message_port_internal.lock().unwrap();
if internal.enabled.get() {
return;
}
internal.enabled.set(true);
let messages = internal.pending_port_messages.borrow();
messages.len()
};
let global = self.global();
for _ in 0..len {
let port = Trusted::new(self);
let _ = global.port_message_queue().queue(
task!(process_pending_port_messages: move || {
let this = port.root();
this.process_pending_port_messages();
}),
&global
);
}
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
fn Close(&self) {
// Step 1
self.detached.set(true);
// Step 2
let maybe_port = {
let internal = self.message_port_internal.lock().unwrap();
let mut maybe_port = internal.entangled_port.borrow_mut();
maybe_port.take()
};
if let Some(other) = maybe_port {
let other_internal = other.lock().unwrap();
*other_internal.entangled_port.borrow_mut() = None;
}
}
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessage>
fn GetOnmessage(&self) -> Option<Rc<EventHandlerNonNull>> {
let eventtarget = self.upcast::<EventTarget>();
eventtarget.get_event_handler_common("message")
}
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessage>
fn SetOnmessage(&self, listener: Option<Rc<EventHandlerNonNull>>) {
self.Start();
let eventtarget = self.upcast::<EventTarget>();
eventtarget.set_event_handler_common("message", listener)
}
}

View file

@ -401,7 +401,9 @@ pub mod mediaquerylist;
pub mod mediaquerylistevent;
pub mod mediastream;
pub mod mediastreamtrack;
pub mod messagechannel;
pub mod messageevent;
pub mod messageport;
pub mod mimetype;
pub mod mimetypearray;
pub mod mouseevent;

View file

@ -19,6 +19,8 @@ use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::JSContext;
use crate::task::TaskOnce;
use dom_struct::dom_struct;
use js::jsapi::JSContext;
use js::jsval::UndefinedValue;
use js::rust::HandleValue;
use script_traits::{DOMMessage, ScriptMsg};
use servo_url::ServoUrl;
@ -97,14 +99,18 @@ impl ServiceWorkerMethods for ServiceWorker {
return Err(Error::InvalidState);
}
// Step 7
let data = StructuredCloneData::write(*cx, message)?;
let msg_vec = DOMMessage(data.move_to_arraybuffer());
rooted!(in(*cx) let transfer = UndefinedValue());
let data = StructuredCloneData::write(*cx, message, transfer.handle())?;
let msg_vec = DOMMessage {
origin: self.global().origin().immutable().ascii_serialization(),
data: data.move_to_arraybuffer(),
};
let _ = self
.global()
.script_to_constellation_chan()
.send(ScriptMsg::ForwardDOMMessage(
msg_vec,
self.scope_url.clone(),
self.scope_url.clone()
));
Ok(())
}

View file

@ -409,12 +409,12 @@ impl ServiceWorkerGlobalScope {
use self::ServiceWorkerScriptMsg::*;
match msg {
CommonWorker(WorkerScriptMsg::DOMMessage(data)) => {
CommonWorker(WorkerScriptMsg::DOMMessage { data, .. }) => {
let scope = self.upcast::<WorkerGlobalScope>();
let target = self.upcast();
let _ac = enter_realm(&*scope);
rooted!(in(*scope.get_cx()) let mut message = UndefinedValue());
data.read(scope.upcast(), message.handle_mut());
assert!(data.read(scope.upcast(), message.handle_mut()));
ExtendableMessageEvent::dispatch_jsval(target, scope.upcast(), message.handle());
},
CommonWorker(WorkerScriptMsg::Common(msg)) => {

View file

@ -0,0 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* The origin of this IDL file is:
* https://html.spec.whatwg.org/multipage/#messagechannel
*/
[Exposed=(Window,Worker)]
interface MessageChannel {
[Throws] constructor();
readonly attribute MessagePort port1;
readonly attribute MessagePort port2;
};

View file

@ -12,7 +12,7 @@ interface MessageEvent : Event {
// FIXME(#22617): WindowProxy is not exposed in Worker globals
readonly attribute object? source;
//readonly attribute (WindowProxy or MessagePort)? source;
//readonly attribute MessagePort[]? ports;
readonly attribute /*FrozenArray<MessagePort>*/any ports;
};
dictionary MessageEventInit : EventInit {
@ -22,5 +22,7 @@ dictionary MessageEventInit : EventInit {
//DOMString channel;
Window? source;
//(WindowProxy or MessagePort)? source;
//sequence<MessagePort> ports;
sequence<MessagePort> ports;
};
typedef (/*WindowProxy or */MessagePort or ServiceWorker) MessageEventSource;

View file

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* The origin of this IDL file is:
* https://html.spec.whatwg.org/multipage/#messageport
*/
[Exposed=(Window,Worker)]
interface MessagePort : EventTarget {
[Throws] void postMessage(any message, optional sequence<object> transfer /*= []*/);
void start();
void close();
// event handlers
attribute EventHandler onmessage;
};

View file

@ -63,9 +63,8 @@
unsigned long requestAnimationFrame(FrameRequestCallback callback);
void cancelAnimationFrame(unsigned long handle);
//void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer);
[Throws]
void postMessage(any message, DOMString targetOrigin);
void postMessage(any message, USVString targetOrigin, optional sequence<object> transfer /*= []*/);
// also has obsolete members
};

View file

@ -598,6 +598,7 @@ impl TaskOnce for MessageReceivedTask {
message.handle(),
Some(&ws.origin().ascii_serialization()),
None,
vec![],
);
}
}

View file

@ -17,6 +17,7 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::{
};
use crate::dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions};
use crate::dom::bindings::codegen::UnionTypes::RequestOrUSVString;
use crate::dom::bindings::conversions::ToJSValConvertible;
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
@ -43,6 +44,7 @@ use crate::dom::location::Location;
use crate::dom::mediaquerylist::{MediaQueryList, MediaQueryListMatchState};
use crate::dom::mediaquerylistevent::MediaQueryListEvent;
use crate::dom::messageevent::MessageEvent;
use crate::dom::messageport::TRANSFERRED_MESSAGE_PORTS;
use crate::dom::navigator::Navigator;
use crate::dom::node::{document_from_node, from_untrusted_node_address, Node, NodeDamage};
use crate::dom::performance::Performance;
@ -80,12 +82,13 @@ use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
use ipc_channel::ipc::{channel, IpcSender};
use ipc_channel::router::ROUTER;
use js::jsapi::JSAutoRealm;
use js::jsapi::JSObject;
use js::jsapi::JSPROP_ENUMERATE;
use js::jsapi::{GCReason, JS_GC};
use js::jsval::UndefinedValue;
use js::jsval::{JSVal, NullValue};
use js::rust::wrappers::JS_DefineProperty;
use js::rust::HandleValue;
use js::rust::{CustomAutoRooterGuard, HandleValue};
use media::WindowGLContext;
use msg::constellation_msg::PipelineId;
use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse};
@ -969,12 +972,18 @@ impl WindowMethods for Window {
}
// https://html.spec.whatwg.org/multipage/#dom-window-postmessage
fn PostMessage(&self, cx: JSContext, message: HandleValue, origin: DOMString) -> ErrorResult {
fn PostMessage(
&self,
cx: JSContext,
message: HandleValue,
origin: USVString,
transfer: CustomAutoRooterGuard<Option<Vec<*mut JSObject>>>,
) -> ErrorResult {
let source_global = GlobalScope::incumbent().expect("no incumbent global??");
let source = source_global.as_window();
// Step 3-5.
let origin = match &origin[..] {
let origin = match &origin.0[..] {
"*" => None,
"/" => Some(source.Document().origin().immutable().clone()),
url => match ServoUrl::parse(&url) {
@ -984,8 +993,10 @@ impl WindowMethods for Window {
};
// Step 1-2, 6-8.
// TODO(#12717): Should implement the `transfer` argument.
let data = StructuredCloneData::write(*cx, message)?;
rooted!(in(*cx) let mut val = UndefinedValue());
(*transfer).as_ref().unwrap_or(&Vec::new()).to_jsval(*cx, val.handle_mut());
let data = StructuredCloneData::write(*cx, message, val.handle())?;
// Step 9.
self.post_message(origin, &*source.window_proxy(), data);
@ -2342,10 +2353,11 @@ impl Window {
let task = task!(post_serialised_message: move || {
let this = this.root();
let source = source.root();
let document = this.Document();
// Step 7.1.
if let Some(target_origin) = target_origin {
if !target_origin.same_origin(this.Document().origin()) {
if let Some(ref target_origin) = target_origin {
if !target_origin.same_origin(document.origin()) {
return;
}
}
@ -2355,13 +2367,15 @@ impl Window {
let obj = this.reflector().get_jsobject();
let _ac = JSAutoRealm::new(*cx, obj.get());
rooted!(in(*cx) let mut message_clone = UndefinedValue());
serialize_with_transfer_result.read(
assert!(serialize_with_transfer_result.read(
this.upcast(),
message_clone.handle_mut(),
);
));
// Step 7.6.
// TODO: MessagePort array.
let new_ports = TRANSFERRED_MESSAGE_PORTS.with(|list| {
mem::replace(&mut *list.borrow_mut(), vec![])
});
// Step 7.7.
// TODO(#12719): Set the other attributes.
@ -2369,8 +2383,9 @@ impl Window {
this.upcast(),
this.upcast(),
message_clone.handle(),
None,
Some(&document.origin().immutable().ascii_serialization()),
Some(&*source),
new_ports,
);
});
// FIXME(nox): Why are errors silenced here?

View file

@ -137,7 +137,11 @@ impl Worker {
self.terminated.get()
}
pub fn handle_message(address: TrustedWorkerAddress, data: StructuredCloneData) {
pub fn handle_message(
address: TrustedWorkerAddress,
origin: String,
data: StructuredCloneData,
) {
let worker = address.root();
if worker.is_terminated() {
@ -148,8 +152,8 @@ impl Worker {
let target = worker.upcast();
let _ac = enter_realm(target);
rooted!(in(*global.get_cx()) let mut message = UndefinedValue());
data.read(&global, message.handle_mut());
MessageEvent::dispatch_jsval(target, &global, message.handle(), None, None);
assert!(data.read(&global, message.handle_mut()));
MessageEvent::dispatch_jsval(target, &global, message.handle(), Some(&origin), None, vec![]);
}
pub fn dispatch_simple_error(address: TrustedWorkerAddress) {
@ -161,14 +165,18 @@ impl Worker {
impl WorkerMethods for Worker {
// https://html.spec.whatwg.org/multipage/#dom-worker-postmessage
fn PostMessage(&self, cx: JSContext, message: HandleValue) -> ErrorResult {
let data = StructuredCloneData::write(*cx, message)?;
rooted!(in(*cx) let transfer = UndefinedValue());
let data = StructuredCloneData::write(*cx, message, transfer.handle())?;
let address = Trusted::new(self);
// NOTE: step 9 of https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage
// indicates that a nonexistent communication channel should result in a silent error.
let _ = self.sender.send(DedicatedWorkerScriptMsg::CommonWorker(
address,
WorkerScriptMsg::DOMMessage(data),
WorkerScriptMsg::DOMMessage {
origin: self.global().origin().immutable().ascii_serialization(),
data,
},
));
Ok(())
}

View file

@ -33,6 +33,7 @@ use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::file_reading::FileReadingTaskSource;
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::timers::{IsInterval, TimerCallback};
@ -457,6 +458,10 @@ impl WorkerGlobalScope {
PerformanceTimelineTaskSource(self.script_chan(), self.pipeline_id())
}
pub fn port_message_queue(&self) -> PortMessageQueue {
PortMessageQueue(self.script_chan(), self.pipeline_id())
}
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
RemoteEventTaskSource(self.script_chan(), self.pipeline_id())
}

View file

@ -115,6 +115,7 @@ pub enum ScriptThreadEventCategory {
ImageCacheMsg,
InputEvent,
NetworkEvent,
PortMessage,
Resize,
ScriptEvent,
SetScrollState,

View file

@ -81,6 +81,7 @@ use crate::task_source::history_traversal::HistoryTraversalTaskSource;
use crate::task_source::media_element::MediaElementTaskSource;
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
use crate::task_source::user_interaction::UserInteractionTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
@ -566,6 +567,8 @@ pub struct ScriptThread {
performance_timeline_task_sender: Box<dyn ScriptChan>,
port_message_sender: Box<dyn ScriptChan>,
remote_event_task_sender: Box<dyn ScriptChan>,
/// A channel to hand out to threads that need to respond to a message from the script thread.
@ -1296,6 +1299,7 @@ impl ScriptThread {
media_element_task_sender: chan.clone(),
user_interaction_task_sender: chan.clone(),
networking_task_sender: boxed_script_sender.clone(),
port_message_sender: boxed_script_sender.clone(),
file_reading_task_sender: boxed_script_sender.clone(),
performance_timeline_task_sender: boxed_script_sender.clone(),
remote_event_task_sender: boxed_script_sender.clone(),
@ -1656,6 +1660,7 @@ impl ScriptThread {
ScriptThreadEventCategory::PerformanceTimelineTask => {
ScriptHangAnnotation::PerformanceTimelineTask
},
ScriptThreadEventCategory::PortMessage => ScriptHangAnnotation::PortMessage,
};
self.background_hang_monitor
.notify_activity(HangAnnotation::Script(hang_annotation));
@ -1756,6 +1761,7 @@ impl ScriptThread {
ScriptThreadEventCategory::ImageCacheMsg => ProfilerCategory::ScriptImageCacheMsg,
ScriptThreadEventCategory::InputEvent => ProfilerCategory::ScriptInputEvent,
ScriptThreadEventCategory::NetworkEvent => ProfilerCategory::ScriptNetworkEvent,
ScriptThreadEventCategory::PortMessage => ProfilerCategory::ScriptPortMessage,
ScriptThreadEventCategory::Resize => ProfilerCategory::ScriptResize,
ScriptThreadEventCategory::ScriptEvent => ProfilerCategory::ScriptEvent,
ScriptThreadEventCategory::SetScrollState => ProfilerCategory::ScriptSetScrollState,
@ -2780,6 +2786,10 @@ impl ScriptThread {
NetworkingTaskSource(self.networking_task_sender.clone(), pipeline_id)
}
pub fn port_message_queue(&self, pipeline_id: PipelineId) -> PortMessageQueue {
PortMessageQueue(self.port_message_sender.clone(), pipeline_id)
}
pub fn file_reading_task_source(&self, pipeline_id: PipelineId) -> FileReadingTaskSource {
FileReadingTaskSource(self.file_reading_task_sender.clone(), pipeline_id)
}
@ -3177,6 +3187,7 @@ impl ScriptThread {
self.networking_task_source(incomplete.pipeline_id),
self.performance_timeline_task_source(incomplete.pipeline_id)
.clone(),
self.port_message_queue(incomplete.pipeline_id),
self.user_interaction_task_source(incomplete.pipeline_id),
self.remote_event_task_source(incomplete.pipeline_id),
self.websocket_task_source(incomplete.pipeline_id),

View file

@ -135,10 +135,10 @@ impl ServiceWorkerManager {
}
fn forward_message(&self, msg: DOMMessage, sender: &Sender<ServiceWorkerScriptMsg>) {
let DOMMessage(data) = msg;
let DOMMessage { origin, data } = msg;
let data = StructuredCloneData::Vector(data);
let _ = sender.send(ServiceWorkerScriptMsg::CommonWorker(
WorkerScriptMsg::DOMMessage(data),
WorkerScriptMsg::DOMMessage { origin, data },
));
}

View file

@ -10,6 +10,7 @@ use crate::task_source::history_traversal::HistoryTraversalTaskSource;
use crate::task_source::media_element::MediaElementTaskSource;
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
use crate::task_source::user_interaction::UserInteractionTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
@ -47,6 +48,8 @@ pub struct TaskManager {
#[ignore_malloc_size_of = "task sources are hard"]
performance_timeline_task_source: PerformanceTimelineTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
port_message_queue: PortMessageQueue,
#[ignore_malloc_size_of = "task sources are hard"]
user_interaction_task_source: UserInteractionTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
remote_event_task_source: RemoteEventTaskSource,
@ -62,6 +65,7 @@ impl TaskManager {
media_element_task_source: MediaElementTaskSource,
networking_task_source: NetworkingTaskSource,
performance_timeline_task_source: PerformanceTimelineTaskSource,
port_message_queue: PortMessageQueue,
user_interaction_task_source: UserInteractionTaskSource,
remote_event_task_source: RemoteEventTaskSource,
websocket_task_source: WebsocketTaskSource,
@ -73,6 +77,7 @@ impl TaskManager {
media_element_task_source,
networking_task_source,
performance_timeline_task_source,
port_message_queue,
user_interaction_task_source,
remote_event_task_source,
websocket_task_source,
@ -136,6 +141,14 @@ impl TaskManager {
PerformanceTimeline
);
task_source_functions!(
self,
port_message_queue_with_canceller,
port_message_queue,
PortMessageQueue,
PortMessage
);
task_source_functions!(
self,
remote_event_task_source_with_canceller,

View file

@ -8,6 +8,7 @@ pub mod history_traversal;
pub mod media_element;
pub mod networking;
pub mod performance_timeline;
pub mod port_message;
pub mod remote_event;
pub mod user_interaction;
pub mod websocket;
@ -28,6 +29,7 @@ pub enum TaskSourceName {
HistoryTraversal,
Networking,
PerformanceTimeline,
PortMessage,
UserInteraction,
RemoteEvent,
MediaElement,

View file

@ -0,0 +1,45 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
use crate::task::{TaskCanceller, TaskOnce};
use crate::task_source::{TaskSource, TaskSourceName};
use msg::constellation_msg::PipelineId;
use std::fmt;
#[derive(JSTraceable)]
pub struct PortMessageQueue(pub Box<ScriptChan + Send + 'static>, pub PipelineId);
impl Clone for PortMessageQueue {
fn clone(&self) -> PortMessageQueue {
PortMessageQueue(self.0.clone(), self.1.clone())
}
}
impl fmt::Debug for PortMessageQueue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "PortMessageQueue(...)")
}
}
impl TaskSource for PortMessageQueue {
const NAME: TaskSourceName = TaskSourceName::PortMessage;
fn queue_with_canceller<T>(
&self,
task: T,
canceller: &TaskCanceller,
) -> Result<(), ()>
where
T: TaskOnce + 'static,
{
let msg = CommonScriptMsg::Task(
ScriptThreadEventCategory::PortMessage,
Box::new(canceller.wrap_task(task)),
Some(self.1),
Self::NAME,
);
self.0.send(msg).map_err(|_| ())
}
}

View file

@ -284,7 +284,12 @@ pub struct ScopeThings {
/// Message that gets passed to service worker scope on postMessage
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DOMMessage(pub Vec<u8>);
pub struct DOMMessage {
/// The origin of the message
pub origin: String,
/// The payload of the message
pub data: Vec<u8>,
}
/// Channels to allow service worker manager to communicate with constellation and resource thread
pub struct SWManagerSenders {

View file

@ -167,6 +167,8 @@ skip: true
skip: false
[WebIDL]
skip: false
[webmessaging]
skip: false
[websockets]
skip: false
[webstorage]