diff options
32 files changed, 273 insertions, 143 deletions
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index f03643bdbd5..6e1e2b87f30 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -690,6 +690,7 @@ where browsing_context_id: BrowsingContextId, top_level_browsing_context_id: TopLevelBrowsingContextId, parent_info: Option<PipelineId>, + opener: Option<BrowsingContextId>, initial_window_size: Option<TypedSize2D<f32, CSSPixel>>, // TODO: we have to provide ownership of the LoadData // here, because it will be send on an ipc channel, @@ -764,6 +765,7 @@ where browsing_context_id, top_level_browsing_context_id, parent_info, + opener, script_to_constellation_chan: ScriptToConstellationChan { sender: self.script_sender.clone(), pipeline_id: pipeline_id, @@ -1256,6 +1258,13 @@ where warn!("Sending reply to get parent info failed ({:?}).", e); } }, + FromScriptMsg::GetTopForBrowsingContext(browsing_context_id, sender) => { + let result = self.browsing_contexts.get(&browsing_context_id) + .and_then(|bc| Some(bc.top_level_id)); + if let Err(e) = sender.send(result) { + warn!("Sending reply to get top for browsing context info failed ({:?}).", e); + } + }, FromScriptMsg::GetChildBrowsingContextId(browsing_context_id, index, sender) => { let result = self .browsing_contexts @@ -1547,11 +1556,12 @@ where (window_size, pipeline_id) }; - let (pipeline_url, parent_info) = { + let (pipeline_url, parent_info, opener) = { let pipeline = pipeline_id.and_then(|id| self.pipelines.get(&id)); let pipeline_url = pipeline.map(|pipeline| pipeline.url.clone()); let parent_info = pipeline.and_then(|pipeline| pipeline.parent_info); - (pipeline_url, parent_info) + let opener = pipeline.and_then(|pipeline| pipeline.opener); + (pipeline_url, parent_info, opener) }; self.close_browsing_context_children( @@ -1578,6 +1588,7 @@ where browsing_context_id, top_level_browsing_context_id, parent_info, + opener, window_size, load_data.clone(), sandbox, @@ -1672,6 +1683,7 @@ where browsing_context_id, top_level_browsing_context_id, None, + None, Some(window_size), load_data.clone(), sandbox, @@ -1805,6 +1817,7 @@ where load_info.info.browsing_context_id, load_info.info.top_level_browsing_context_id, Some(load_info.info.parent_pipeline_id), + None, window_size, load_data.clone(), load_info.sandbox, @@ -1850,6 +1863,7 @@ where browsing_context_id, top_level_browsing_context_id, Some(parent_pipeline_id), + None, script_sender, layout_sender, self.compositor_proxy.clone(), @@ -1887,8 +1901,8 @@ where let load_data = LoadData::new(url.clone(), None, None, None); let pipeline = { - let opener_pipeline = match self.pipelines.get(&opener_pipeline_id) { - Some(parent_pipeline) => parent_pipeline, + let (opener_pipeline, opener_id) = match self.pipelines.get(&opener_pipeline_id) { + Some(opener_pipeline) => (opener_pipeline, opener_pipeline.browsing_context_id), None => return warn!("Auxiliary loaded url in closed pipeline {}.", opener_pipeline_id), }; let opener_host = match reg_host(&opener_pipeline.url) { @@ -1907,6 +1921,7 @@ where new_browsing_context_id, new_top_level_browsing_context_id, None, + Some(opener_id), script_sender, layout_sender, self.compositor_proxy.clone(), @@ -2010,8 +2025,8 @@ where // requested change so it can update its internal state. // // If replace is true, the current entry is replaced instead of a new entry being added. - let (browsing_context_id, parent_info) = match self.pipelines.get(&source_id) { - Some(pipeline) => (pipeline.browsing_context_id, pipeline.parent_info), + let (browsing_context_id, parent_info, opener) = match self.pipelines.get(&source_id) { + Some(pipeline) => (pipeline.browsing_context_id, pipeline.parent_info, pipeline.opener), None => { warn!("Pipeline {} loaded after closure.", source_id); return None; @@ -2088,6 +2103,7 @@ where browsing_context_id, top_level_id, None, + opener, window_size, load_data.clone(), sandbox, @@ -2372,19 +2388,21 @@ where // TODO: Save the sandbox state so it can be restored here. let sandbox = IFrameSandboxState::IFrameUnsandboxed; let new_pipeline_id = PipelineId::new(); - let (top_level_id, parent_info, window_size, is_private) = + let (top_level_id, parent_info, opener, window_size, is_private) = match self.browsing_contexts.get(&browsing_context_id) { Some(browsing_context) => { match self.pipelines.get(&browsing_context.pipeline_id) { Some(pipeline) => ( browsing_context.top_level_id, pipeline.parent_info, + pipeline.opener, browsing_context.size, pipeline.is_private, ), None => ( browsing_context.top_level_id, None, + None, browsing_context.size, false, ), @@ -2397,6 +2415,7 @@ where browsing_context_id, top_level_id, parent_info, + opener, window_size, load_data.clone(), sandbox, diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 50d2911a535..62899328ca1 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -62,6 +62,8 @@ pub struct Pipeline { /// TODO: move this field to `BrowsingContext`. pub parent_info: Option<PipelineId>, + pub opener: Option<BrowsingContextId>, + /// The event loop handling this pipeline. pub event_loop: Rc<EventLoop>, @@ -119,6 +121,8 @@ pub struct InitialPipelineState { /// If `None`, this is the root. pub parent_info: Option<PipelineId>, + pub opener: Option<BrowsingContextId>, + /// A channel to the associated constellation. pub script_to_constellation_chan: ScriptToConstellationChan, @@ -216,6 +220,7 @@ impl Pipeline { new_pipeline_id: state.id, browsing_context_id: state.browsing_context_id, top_level_browsing_context_id: state.top_level_browsing_context_id, + opener: state.opener, load_data: state.load_data.clone(), window_size: window_size, pipeline_port: pipeline_port, @@ -266,6 +271,7 @@ impl Pipeline { browsing_context_id: state.browsing_context_id, top_level_browsing_context_id: state.top_level_browsing_context_id, parent_info: state.parent_info, + opener: state.opener, script_to_constellation_chan: state.script_to_constellation_chan.clone(), scheduler_chan: state.scheduler_chan, devtools_chan: script_to_devtools_chan, @@ -312,6 +318,7 @@ impl Pipeline { state.browsing_context_id, state.top_level_browsing_context_id, state.parent_info, + state.opener, script_chan, pipeline_chan, state.compositor_proxy, @@ -329,6 +336,7 @@ impl Pipeline { browsing_context_id: BrowsingContextId, top_level_browsing_context_id: TopLevelBrowsingContextId, parent_info: Option<PipelineId>, + opener: Option<BrowsingContextId>, event_loop: Rc<EventLoop>, layout_chan: IpcSender<LayoutControlMsg>, compositor_proxy: CompositorProxy, @@ -342,6 +350,7 @@ impl Pipeline { browsing_context_id: browsing_context_id, top_level_browsing_context_id: top_level_browsing_context_id, parent_info: parent_info, + opener: opener, event_loop: event_loop, layout_chan: layout_chan, compositor_proxy: compositor_proxy, @@ -469,6 +478,7 @@ pub struct UnprivilegedPipelineContent { top_level_browsing_context_id: TopLevelBrowsingContextId, browsing_context_id: BrowsingContextId, parent_info: Option<PipelineId>, + opener: Option<BrowsingContextId>, script_to_constellation_chan: ScriptToConstellationChan, layout_to_constellation_chan: IpcSender<LayoutMsg>, scheduler_chan: IpcSender<TimerSchedulerMsg>, @@ -517,6 +527,7 @@ impl UnprivilegedPipelineContent { browsing_context_id: self.browsing_context_id, top_level_browsing_context_id: self.top_level_browsing_context_id, parent_info: self.parent_info, + opener: self.opener, control_chan: self.script_chan.clone(), control_port: self.script_port, script_to_constellation_chan: self.script_to_constellation_chan.clone(), diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 373aa9c254f..b7540344c6a 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -177,6 +177,7 @@ impl HTMLIFrameElement { new_pipeline_id: new_pipeline_id, browsing_context_id: browsing_context_id, top_level_browsing_context_id: top_level_browsing_context_id, + opener: None, load_data: load_data.unwrap(), pipeline_port: pipeline_receiver, content_process_shutdown_chan: None, diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index c143ec56bbf..396bb936d71 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -35,7 +35,7 @@ // Note that this can return null in the case that the browsing context has been discarded. // https://github.com/whatwg/html/issues/2115 [Unforgeable] readonly attribute WindowProxy? top; - // attribute any opener; + attribute any opener; // Note that this can return null in the case that the browsing context has been discarded. // https://github.com/whatwg/html/issues/2115 [Replaceable] readonly attribute WindowProxy? parent; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 41b7441c3bf..b4c99ddfc94 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -61,10 +61,12 @@ use fetch; use ipc_channel::ipc::IpcSender; use ipc_channel::router::ROUTER; use js::jsapi::{JSAutoCompartment, JSContext}; -use js::jsapi::{JS_GC, JS_GetRuntime}; -use js::jsval::UndefinedValue; +use js::jsapi::{JS_GC, JS_GetRuntime, JSPROP_ENUMERATE}; +use js::jsval::{JSVal, UndefinedValue}; use js::rust::HandleValue; +use js::rust::wrappers::JS_DefineProperty; use layout_image::fetch_image_for_layout; +use libc; use microtask::MicrotaskQueue; use msg::constellation_msg::PipelineId; use net_traits::{ResourceThreads, ReferrerPolicy}; @@ -574,6 +576,30 @@ impl WindowMethods for Window { self.window_proxy().open(url, target, features) } + #[allow(unsafe_code)] + // https://html.spec.whatwg.org/multipage/#dom-opener + unsafe fn Opener(&self, cx: *mut JSContext) -> JSVal { + self.window_proxy().opener(cx) + } + + #[allow(unsafe_code)] + // https://html.spec.whatwg.org/multipage/#dom-opener + unsafe fn SetOpener(&self, cx: *mut JSContext, value: HandleValue) { + // Step 1. + if value.is_null() { + return self.window_proxy().disown(); + } + // Step 2. + let obj = self.reflector().get_jsobject(); + assert!(JS_DefineProperty(cx, + obj, + "opener\0".as_ptr() as *const libc::c_char, + value, + JSPROP_ENUMERATE, + None, + None)); + } + // https://html.spec.whatwg.org/multipage/#dom-window-closed fn Closed(&self) -> bool { self.window_proxy.get() diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index 10c925cb28d..093ea29b3d7 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -36,7 +36,7 @@ use js::jsapi::HandleValue as RawHandleValue; use js::jsapi::MutableHandle as RawMutableHandle; use js::jsapi::MutableHandleObject as RawMutableHandleObject; use js::jsapi::MutableHandleValue as RawMutableHandleValue; -use js::jsval::{UndefinedValue, PrivateValue}; +use js::jsval::{JSVal, NullValue, UndefinedValue, PrivateValue}; use js::rust::{Handle, MutableHandle}; use js::rust::get_object_class; use js::rust::wrappers::{NewWindowProxy, SetWindowProxy, JS_TransplantObject}; @@ -67,6 +67,9 @@ pub struct WindowProxy { /// of the container. browsing_context_id: BrowsingContextId, + // https://html.spec.whatwg.org/multipage/#opener-browsing-context + opener: Option<BrowsingContextId>, + /// The frame id of the top-level ancestor browsing context. /// In the case that this is a top-level window, this is our id. top_level_browsing_context_id: TopLevelBrowsingContextId, @@ -83,6 +86,9 @@ pub struct WindowProxy { /// Has the browsing context been discarded? discarded: Cell<bool>, + /// Has the browsing context been disowned? + disowned: Cell<bool>, + /// The containing iframe element, if this is a same-origin iframe frame_element: Option<Dom<Element>>, @@ -95,7 +101,8 @@ impl WindowProxy { top_level_browsing_context_id: TopLevelBrowsingContextId, currently_active: Option<PipelineId>, frame_element: Option<&Element>, - parent: Option<&WindowProxy>) + parent: Option<&WindowProxy>, + opener: Option<BrowsingContextId>) -> WindowProxy { let name = frame_element.map_or(DOMString::new(), |e| e.get_string_attribute(&local_name!("name"))); @@ -106,8 +113,10 @@ impl WindowProxy { name: DomRefCell::new(name), currently_active: Cell::new(currently_active), discarded: Cell::new(false), + disowned: Cell::new(false), frame_element: frame_element.map(Dom::from_ref), parent: parent.map(Dom::from_ref), + opener, } } @@ -116,7 +125,8 @@ impl WindowProxy { browsing_context_id: BrowsingContextId, top_level_browsing_context_id: TopLevelBrowsingContextId, frame_element: Option<&Element>, - parent: Option<&WindowProxy>) + parent: Option<&WindowProxy>, + opener: Option<BrowsingContextId>) -> DomRoot<WindowProxy> { unsafe { @@ -140,7 +150,8 @@ impl WindowProxy { top_level_browsing_context_id, current, frame_element, - parent + parent, + opener, )); // The window proxy owns the browsing context. @@ -161,7 +172,8 @@ impl WindowProxy { pub fn new_dissimilar_origin(global_to_clone_from: &GlobalScope, browsing_context_id: BrowsingContextId, top_level_browsing_context_id: TopLevelBrowsingContextId, - parent: Option<&WindowProxy>) + parent: Option<&WindowProxy>, + opener: Option<BrowsingContextId>) -> DomRoot<WindowProxy> { unsafe { @@ -176,7 +188,8 @@ impl WindowProxy { top_level_browsing_context_id, None, None, - parent + parent, + opener )); // Create a new dissimilar-origin window. @@ -205,7 +218,7 @@ impl WindowProxy { } // https://html.spec.whatwg.org/multipage/#auxiliary-browsing-context - fn create_auxiliary_browsing_context(&self, name: DOMString, _noopener: bool) -> Option<DomRoot<WindowProxy>> { + fn create_auxiliary_browsing_context(&self, name: DOMString, noopener: bool) -> Option<DomRoot<WindowProxy>> { let (chan, port) = ipc::channel().unwrap(); let window = self.currently_active.get() .and_then(|id| ScriptThread::find_document(id)) @@ -237,6 +250,7 @@ impl WindowProxy { new_pipeline_id: new_pipeline_id, browsing_context_id: new_browsing_context_id, top_level_browsing_context_id: new_top_level_browsing_context_id, + opener: Some(self.browsing_context_id), load_data: load_data, pipeline_port: pipeline_receiver, content_process_shutdown_chan: None, @@ -248,17 +262,64 @@ impl WindowProxy { ScriptThread::process_attach_layout(new_layout_info, document.origin().clone()); let msg = EmbedderMsg::BrowserCreated(new_top_level_browsing_context_id); window.send_to_embedder(msg); + // TODO: if noopener is false, copy the sessionStorage storage area of the creator origin. + // See step 14 of https://html.spec.whatwg.org/multipage/#creating-a-new-browsing-context let auxiliary = ScriptThread::find_document(new_pipeline_id).and_then(|doc| doc.browsing_context()); if let Some(proxy) = auxiliary { if name.to_lowercase() != "_blank" { proxy.set_name(name); } + if noopener { + proxy.disown(); + } return Some(proxy) } } None } + // https://html.spec.whatwg.org/multipage/#disowned-its-opener + pub fn disown(&self) { + self.disowned.set(true); + } + + #[allow(unsafe_code)] + // https://html.spec.whatwg.org/multipage/#dom-opener + pub unsafe fn opener(&self, cx: *mut JSContext) -> JSVal { + if self.disowned.get() { + return NullValue() + } + let opener_id = match self.opener { + Some(opener_browsing_context_id) => opener_browsing_context_id, + None => return NullValue() + }; + let opener_proxy = match ScriptThread::find_window_proxy(opener_id) { + Some(window_proxy) => window_proxy, + None => { + let sender_pipeline_id = self.currently_active().unwrap(); + match ScriptThread::get_top_level_for_browsing_context(sender_pipeline_id, opener_id) { + Some(opener_top_id) => { + let global_to_clone_from = GlobalScope::from_context(cx); + WindowProxy::new_dissimilar_origin( + &*global_to_clone_from, + opener_id, + opener_top_id, + None, + None + ) + }, + None => return NullValue() + } + } + }; + if opener_proxy.is_browsing_context_discarded() { + return NullValue() + } + rooted!(in(cx) let mut val = UndefinedValue()); + opener_proxy.to_jsval(cx, val.handle_mut()); + return val.get() + } + // https://html.spec.whatwg.org/multipage/#window-open-steps pub fn open(&self, url: DOMString, @@ -314,7 +375,11 @@ impl WindowProxy { }, "_parent" => { // Step 4 - (Some(DomRoot::from_ref(self.parent().unwrap())), false) + if let Some(parent) = self.parent() { + return (Some(DomRoot::from_ref(parent)), false) + } + (None, false) + }, "_top" => { // Step 5 @@ -336,6 +401,10 @@ impl WindowProxy { } } + pub fn is_auxiliary(&self) -> bool { + self.opener.is_some() + } + pub fn discard_browsing_context(&self) { self.discarded.set(true); } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 9e20a24e55b..8f4855c777b 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -157,6 +157,8 @@ struct InProgressLoad { top_level_browsing_context_id: TopLevelBrowsingContextId, /// The parent pipeline and frame type associated with this load, if any. parent_info: Option<PipelineId>, + /// The opener, if this is an auxiliary. + opener: Option<BrowsingContextId>, /// The current window size associated with this pipeline. window_size: Option<WindowSizeData>, /// Channel to the layout thread associated with this pipeline. @@ -183,6 +185,7 @@ impl InProgressLoad { browsing_context_id: BrowsingContextId, top_level_browsing_context_id: TopLevelBrowsingContextId, parent_info: Option<PipelineId>, + opener: Option<BrowsingContextId>, layout_chan: Sender<message::Msg>, window_size: Option<WindowSizeData>, url: ServoUrl, @@ -195,6 +198,7 @@ impl InProgressLoad { browsing_context_id: browsing_context_id, top_level_browsing_context_id: top_level_browsing_context_id, parent_info: parent_info, + opener: opener, layout_chan: layout_chan, window_size: window_size, activity: DocumentActivity::FullyActive, @@ -569,6 +573,7 @@ impl ScriptThreadFactory for ScriptThread { let browsing_context_id = state.browsing_context_id; let top_level_browsing_context_id = state.top_level_browsing_context_id; let parent_info = state.parent_info; + let opener = state.opener; let mem_profiler_chan = state.mem_profiler_chan.clone(); let window_size = state.window_size; let script_thread = ScriptThread::new(state, @@ -583,7 +588,7 @@ impl ScriptThreadFactory for ScriptThread { let origin = MutableOrigin::new(load_data.url.origin()); let new_load = InProgressLoad::new(id, browsing_context_id, top_level_browsing_context_id, parent_info, - layout_chan, window_size, load_data.url.clone(), origin); + opener, layout_chan, window_size, load_data.url.clone(), origin); script_thread.pre_page_load(new_load, load_data); let reporter_name = format!("script-reporter-{}", id); @@ -706,6 +711,15 @@ impl ScriptThread { }); } + pub fn get_top_level_for_browsing_context(sender_pipeline: PipelineId, + browsing_context_id: BrowsingContextId) + -> Option<TopLevelBrowsingContextId> { + SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| { + let script_thread = unsafe { &*script_thread }; + script_thread.ask_constellation_for_top_level_info(sender_pipeline, browsing_context_id) + })) + } + pub fn find_document(id: PipelineId) -> Option<DomRoot<Document>> { SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| { let script_thread = unsafe { &*script_thread }; @@ -1553,6 +1567,7 @@ impl ScriptThread { new_pipeline_id, browsing_context_id, top_level_browsing_context_id, + opener, load_data, window_size, pipeline_port, @@ -1597,6 +1612,7 @@ impl ScriptThread { browsing_context_id, top_level_browsing_context_id, parent_info, + opener, layout_chan, window_size, load_data.url.clone(), @@ -2025,6 +2041,16 @@ impl ScriptThread { result_receiver.recv().expect("Failed to get frame id from constellation.") } + fn ask_constellation_for_top_level_info(&self, + sender_pipeline: PipelineId, + browsing_context_id: BrowsingContextId) + -> Option<TopLevelBrowsingContextId> { + let (result_sender, result_receiver) = ipc::channel().unwrap(); + let msg = ScriptMsg::GetTopForBrowsingContext(browsing_context_id, result_sender); + self.script_sender.send((sender_pipeline, msg)).expect("Failed to send to constellation."); + result_receiver.recv().expect("Failed to get top-level id from constellation.") + } + // Get the browsing context for a pipeline that may exist in another // script thread. If the browsing context already exists in the // `window_proxies` map, we return it, otherwise we recursively @@ -2034,7 +2060,8 @@ impl ScriptThread { fn remote_window_proxy(&self, global_to_clone: &GlobalScope, top_level_browsing_context_id: TopLevelBrowsingContextId, - pipeline_id: PipelineId) + pipeline_id: PipelineId, + opener: Option<BrowsingContextId>) -> Option<DomRoot<WindowProxy>> { let browsing_context_id = self.ask_constellation_for_browsing_context_id(pipeline_id)?; @@ -2042,12 +2069,13 @@ impl ScriptThread { return Some(DomRoot::from_ref(window_proxy)); } let parent = self.ask_constellation_for_parent_info(pipeline_id).and_then(|parent_id| { - self.remote_window_proxy(global_to_clone, top_level_browsing_context_id, parent_id) + self.remote_window_proxy(global_to_clone, top_level_browsing_context_id, parent_id, opener) }); let window_proxy = WindowProxy::new_dissimilar_origin(global_to_clone, browsing_context_id, top_level_browsing_context_id, - parent.r()); + parent.r(), + opener); self.window_proxies.borrow_mut().insert(browsing_context_id, Dom::from_ref(&*window_proxy)); Some(window_proxy) } @@ -2062,7 +2090,8 @@ impl ScriptThread { window: &Window, browsing_context_id: BrowsingContextId, top_level_browsing_context_id: TopLevelBrowsingContextId, - parent_info: Option<PipelineId>) + parent_info: Option<PipelineId>, + opener: Option<BrowsingContextId>) -> DomRoot<WindowProxy> { if let Some(window_proxy) = self.window_proxies.borrow().get(&browsing_context_id) { @@ -2075,15 +2104,17 @@ impl ScriptThread { let parent = match (parent_info, iframe.as_ref()) { (_, Some(iframe)) => Some(window_from_node(&**iframe).window_proxy()), (Some(parent_id), _) => self.remote_window_proxy(window.upcast(), - top_level_browsing_context_id, - parent_id), + top_level_browsing_context_id, + parent_id, + opener), _ => None, }; let window_proxy = WindowProxy::new(&window, browsing_context_id, top_level_browsing_context_id, iframe.r().map(Castable::upcast), - parent.r()); + parent.r(), + opener); self.window_proxies.borrow_mut().insert(browsing_context_id, Dom::from_ref(&*window_proxy)); window_proxy } @@ -2162,7 +2193,8 @@ impl ScriptThread { let window_proxy = self.local_window_proxy(&window, incomplete.browsing_context_id, incomplete.top_level_browsing_context_id, - incomplete.parent_info); + incomplete.parent_info, + incomplete.opener); window.init_window_proxy(&window_proxy); let last_modified = metadata.headers.as_ref().and_then(|headers| { diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 476f41ef0f1..be39ab71cb2 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -193,6 +193,8 @@ pub struct NewLayoutInfo { pub browsing_context_id: BrowsingContextId, /// Id of the top-level browsing context associated with this pipeline. pub top_level_browsing_context_id: TopLevelBrowsingContextId, + /// Id of the opener, if any + pub opener: Option<BrowsingContextId>, /// Network request data which will be initiated by the script thread. pub load_data: LoadData, /// Information about the initial window size. @@ -521,6 +523,8 @@ pub struct InitialScriptState { pub browsing_context_id: BrowsingContextId, /// The ID of the top-level browsing context this script is part of. pub top_level_browsing_context_id: TopLevelBrowsingContextId, + /// The ID of the opener, if any. + pub opener: Option<BrowsingContextId>, /// A channel with which messages can be sent to us (the script thread). pub control_chan: IpcSender<ConstellationControlMsg>, /// A port on which messages sent by the constellation to script can be received. diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 3668fd1e2fa..6dba5c00509 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -17,7 +17,8 @@ use embedder_traits::EmbedderMsg; use euclid::{Size2D, TypedSize2D}; use gfx_traits::Epoch; use ipc_channel::ipc::{IpcReceiver, IpcSender}; -use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, TraversalDirection}; +use msg::constellation_msg::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId}; +use msg::constellation_msg::{HistoryStateId, TraversalDirection}; use net_traits::CoreResourceMsg; use net_traits::request::RequestInit; use net_traits::storage_thread::StorageType; @@ -105,6 +106,8 @@ pub enum ScriptMsg { GetBrowsingContextId(PipelineId, IpcSender<Option<BrowsingContextId>>), /// Get the parent info for a given pipeline. GetParentInfo(PipelineId, IpcSender<Option<PipelineId>>), + /// Get the top-level browsing context info for a given browsing context. + GetTopForBrowsingContext(BrowsingContextId, IpcSender<Option<TopLevelBrowsingContextId>>), /// Get the nth child browsing context ID for a given browsing context, sorted in tree order. GetChildBrowsingContextId(BrowsingContextId, usize, IpcSender<Option<BrowsingContextId>>), /// All pending loads are complete, and the `load` event for this pipeline @@ -184,6 +187,7 @@ impl fmt::Debug for ScriptMsg { GetClipboardContents(..) => "GetClipboardContents", GetBrowsingContextId(..) => "GetBrowsingContextId", GetParentInfo(..) => "GetParentInfo", + GetTopForBrowsingContext(..) => "GetParentBrowsingContext", GetChildBrowsingContextId(..) => "GetChildBrowsingContextId", LoadComplete => "LoadComplete", LoadUrl(..) => "LoadUrl", diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index c5b3b544067..9887429ef07 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -279733,6 +279733,11 @@ {} ] ], + "html/browsers/windows/auxiliary-browsing-contexts/resources/opener-setter.html": [ + [ + {} + ] + ], "html/browsers/windows/browsing-context-names/resources/choose-_parent-001-iframe-1.html": [ [ {} @@ -352032,6 +352037,12 @@ {} ] ], + "html/browsers/windows/auxiliary-browsing-contexts/opener-setter.html": [ + [ + "/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.html", + {} + ] + ], "html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js": [ [ "/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.html", @@ -587647,6 +587658,10 @@ "f82aa6f0abe0d16a8b132e531d165988af0af99f", "testharness" ], + "html/browsers/windows/auxiliary-browsing-contexts/opener-setter.html": [ + "85c52e0b42e19bdd78dda120320d66ddbb2103b4", + "testharness" + ], "html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js": [ "6d540ce97c94bff5845023098d0960d51dad62b4", "testharness" @@ -587675,6 +587690,10 @@ "6f43a5188c790577c4a1a03da270317eedba0fb0", "support" ], + "html/browsers/windows/auxiliary-browsing-contexts/resources/opener-setter.html": [ + "4112dae0cee66138a309b202a8d09d6b256c6d4d", + "support" + ], "html/browsers/windows/browsing-context-names/choose-_blank-001.html": [ "a1416f2eb8437a8824a26a0e2e6aa6fdede37ffa", "testharness" diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/005.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/005.html.ini new file mode 100644 index 00000000000..20ee9003920 --- /dev/null +++ b/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/005.html.ini @@ -0,0 +1,3 @@ +[005.html] + type: testharness + expected: ERROR diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/007.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/007.html.ini index 04538ab47a0..aadbdc0beda 100644 --- a/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/007.html.ini +++ b/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/007.html.ini @@ -2,4 +2,3 @@ type: testharness [Link with onclick javascript url and href navigation ] expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html.ini b/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html.ini index d97cd045a92..9516c5bd53e 100644 --- a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html.ini +++ b/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html.ini @@ -1,5 +1,5 @@ [opener-closed.html] type: testharness - expected: TIMEOUT + expected: CRASH [An auxiliary browsing context should report `null` for `window.opener` when that browsing context is discarded] - expected: TIMEOUT + expected: CRASH diff --git a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html.ini b/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html.ini deleted file mode 100644 index 5f19cf016eb..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[opener-multiple.html] - type: testharness - expected: TIMEOUT - [An auxiliary browsing context should be able to open another auxiliary browsing context] - expected: TIMEOUT diff --git a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html.ini b/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html.ini deleted file mode 100644 index dabad35e2ee..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[opener-noreferrer.html] - type: testharness - expected: TIMEOUT - [Auxiliary browsing context created with `rel="noreferrer"` should report `window.opener` `null`] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js.ini b/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js.ini deleted file mode 100644 index 9d293d228ba..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js.ini +++ /dev/null @@ -1,22 +0,0 @@ -[opener-setter.window.html] - [Setting window.opener to undefined] - expected: FAIL - - [Setting window.opener to 42] - expected: FAIL - - [Setting window.opener to function () { return "hi" }] - expected: FAIL - - [Setting window.opener to hi] - expected: FAIL - - [Setting window.opener to [object Object\]] - expected: FAIL - - [Setting window.opener to ] - expected: FAIL - - [Setting window.opener to Symbol()] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener.html.ini b/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener.html.ini deleted file mode 100644 index 59a38204b5e..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/auxiliary-browsing-contexts/opener.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[opener.html] - type: testharness - expected: TIMEOUT - [Newly-created auxiliary browsing context should report `window.opener`] - expected: TIMEOUT - [Browsing context created with `window.open` should report `window.opener`] - expected: FAIL diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_blank-001.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_blank-001.html.ini deleted file mode 100644 index de54ed6babc..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_blank-001.html.ini +++ /dev/null @@ -1,8 +0,0 @@ -[choose-_blank-001.html] - type: testharness - [window.open into `_blank` should create a new browsing context each time] - expected: FAIL - - [`_blank` should be ASCII case-insensitive] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_blank-002.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_blank-002.html.ini deleted file mode 100644 index da270341b6f..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_blank-002.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[choose-_blank-002.html] - type: testharness - expected: TIMEOUT - [Context for opened noreferrer link targeted to "_blank" should not have opener reference] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_blank-003.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_blank-003.html.ini deleted file mode 100644 index 34eeff13c09..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_blank-003.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[choose-_blank-003.html] - type: testharness - expected: TIMEOUT - [Context created by link targeting "_blank" should retain opener reference] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-001.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-001.html.ini deleted file mode 100644 index 13139ca78c7..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-001.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[choose-_parent-001.html] - type: testharness - expected: TIMEOUT - [The parent browsing context must be chosen if the given name is `_parent`] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-002.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-002.html.ini deleted file mode 100644 index beaa956fd61..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-002.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[choose-_parent-002.html] - type: testharness - expected: ERROR - [choosing _parent context: multiple nested contexts] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-003.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-003.html.ini deleted file mode 100644 index a2bcdf6ed59..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-003.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[choose-_parent-003.html] - type: testharness - expected: ERROR - [_parent should reuse window.parent context] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-004.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-004.html.ini deleted file mode 100644 index 853b3be6979..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_parent-004.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[choose-_parent-004.html] - type: testharness - expected: TIMEOUT - [choosing _parent context should be case-insensitive] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_self-002.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_self-002.html.ini deleted file mode 100644 index 8647f6bb351..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_self-002.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[choose-_self-002.html] - type: testharness - expected: TIMEOUT - [choosing _self context should be case-insensitive] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_top-001.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_top-001.html.ini deleted file mode 100644 index 13bbd30d86b..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_top-001.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[choose-_top-001.html] - type: testharness - [Should choose current browsing context for "_top" if current is top] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_top-002.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_top-002.html.ini deleted file mode 100644 index 464f944cdf3..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_top-002.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[choose-_top-002.html] - type: testharness - [Should choose top browsing context for "_top" if current is not top] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_top-003.html.ini b/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_top-003.html.ini deleted file mode 100644 index ee59a5236c8..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/browsing-context-names/choose-_top-003.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[choose-_top-003.html] - type: testharness - [choosing _top context should be case-insensitive] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/windows/noreferrer-null-opener.html.ini b/tests/wpt/metadata/html/browsers/windows/noreferrer-null-opener.html.ini deleted file mode 100644 index 5b7cd2d3c82..00000000000 --- a/tests/wpt/metadata/html/browsers/windows/noreferrer-null-opener.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[noreferrer-null-opener.html] - type: testharness - expected: TIMEOUT - [rel=noreferrer nullifies window.opener] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/windows/targeting-cross-origin-nested-browsing-contexts.html.ini b/tests/wpt/metadata/html/browsers/windows/targeting-cross-origin-nested-browsing-contexts.html.ini index 7e01a712d91..4ee3fbb8304 100644 --- a/tests/wpt/metadata/html/browsers/windows/targeting-cross-origin-nested-browsing-contexts.html.ini +++ b/tests/wpt/metadata/html/browsers/windows/targeting-cross-origin-nested-browsing-contexts.html.ini @@ -1,5 +1,4 @@ [targeting-cross-origin-nested-browsing-contexts.html] type: testharness - expected: TIMEOUT [Targeting nested browsing contexts] expected: FAIL diff --git a/tests/wpt/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.html b/tests/wpt/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.html new file mode 100644 index 00000000000..85c52e0b42e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.html @@ -0,0 +1,32 @@ +<!doctype html> +<html> + <head> + <title>Auxiliary Browing Contexts: window.opener setter</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/common/PrefixedLocalStorage.js"></script> + </head> + <body> + <div id="log"></div> + <script> + var prefixedLocalStorage; + setup(() => prefixedLocalStorage = new PrefixedLocalStorageTest()); + async_test(t => { + t.add_cleanup(() => prefixedLocalStorage.cleanup()); + prefixedLocalStorage.onSet('openerIsNull', t.step_func_done(e => { + assert_equals(e.newValue, 'true'); + })); + window.open(prefixedLocalStorage.url('resources/opener-setter.html'), + 'iShouldSetOpenerToNull'); + }, 'Auxiliary browsing context created via `window.open` and setting `window.opener` to `null` should report `window.opener` `null`'); + async_test(t => { + t.add_cleanup(() => prefixedLocalStorage.cleanup()); + prefixedLocalStorage.onSet('openerIsTest', t.step_func_done(e => { + assert_equals(e.newValue, 'true'); + })); + window.open(prefixedLocalStorage.url('resources/opener-setter.html'), + 'iShouldSetOpenerToTest'); + }, 'Auxiliary browsing context created via `window.open` and setting `window.opener` to `test` should report `test`'); + </script> + </body> +</html> diff --git a/tests/wpt/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/opener-setter.html b/tests/wpt/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/opener-setter.html new file mode 100644 index 00000000000..4112dae0cee --- /dev/null +++ b/tests/wpt/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/opener-setter.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset="utf-8"> +<html> +<p>This window should set the window.opener attribute</p> +<script src="/common/PrefixedLocalStorage.js"></script> +<script> +var prefixedLocalStorage = new PrefixedLocalStorageResource({ + close_on_cleanup: true +}); +function checkOpener () { + if (window.name == 'iShouldSetOpenerToNull') { + window.opener = null; + return prefixedLocalStorage.setItem('openerIsNull', window.opener === null); + } + if (window.name == 'iShouldSetOpenerToTest') { + window.opener = 'test'; + return prefixedLocalStorage.setItem('openerIsTest', window.opener === "test"); + } +} +</script> +<body onload="checkOpener()"> +</body> +</html> |