diff options
-rw-r--r-- | components/constellation/constellation.rs | 20 | ||||
-rw-r--r-- | components/script/dom/storage.rs | 39 | ||||
-rw-r--r-- | components/script/script_thread.rs | 25 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 5 | ||||
-rw-r--r-- | components/script_traits/script_msg.rs | 4 | ||||
-rw-r--r-- | tests/wpt/metadata/html/browsers/windows/noreferrer.html.ini | 3 | ||||
-rw-r--r-- | tests/wpt/metadata/webstorage/event_local_removeitem.html.ini | 5 | ||||
-rw-r--r-- | tests/wpt/metadata/webstorage/event_session_removeitem.html.ini | 5 |
8 files changed, 67 insertions, 39 deletions
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 42db62eae78..c42bdf42799 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -32,7 +32,7 @@ use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection}; use net_traits::{self, IpcSend, ResourceThreads}; use net_traits::image_cache_thread::ImageCacheThread; -use net_traits::storage_thread::StorageThreadMsg; +use net_traits::storage_thread::{StorageThreadMsg, StorageType}; use offscreen_gl_context::{GLContextAttributes, GLLimits}; use pipeline::{ChildProcess, InitialPipelineState, Pipeline}; use profile_traits::mem; @@ -1026,6 +1026,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> warn!("Unable to forward DOMMessage for postMessage call"); } } + FromScriptMsg::BroadcastStorageEvent(pipeline_id, storage, url, key, old_value, new_value) => { + self.handle_broadcast_storage_event(pipeline_id, storage, url, key, old_value, new_value); + } } } @@ -1052,6 +1055,21 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } + fn handle_broadcast_storage_event(&self, pipeline_id: PipelineId, storage: StorageType, url: Url, + key: Option<String>, old_value: Option<String>, new_value: Option<String>) { + let origin = url.origin(); + for pipeline in self.pipelines.values() { + if (pipeline.id != pipeline_id) && (pipeline.url.origin() == origin) { + let msg = ConstellationControlMsg::DispatchStorageEvent( + pipeline.id, storage, url.clone(), key.clone(), old_value.clone(), new_value.clone() + ); + if let Err(err) = pipeline.script_chan.send(msg) { + warn!("Failed to broadcast storage event to pipeline {} ({:?}).", pipeline.id, err); + } + } + } + } + fn handle_exit(&mut self) { // TODO: add a timer, which forces shutdown if threads aren't responsive. if self.shutting_down { return; } diff --git a/components/script/dom/storage.rs b/components/script/dom/storage.rs index 099c6c04fea..3eb2b1ca844 100644 --- a/components/script/dom/storage.rs +++ b/components/script/dom/storage.rs @@ -17,6 +17,7 @@ use ipc_channel::ipc::{self, IpcSender}; use net_traits::IpcSend; use net_traits::storage_thread::{StorageThreadMsg, StorageType}; use script_thread::{Runnable, ScriptThread}; +use script_traits::ScriptMsg; use task_source::TaskSource; use url::Url; @@ -149,60 +150,60 @@ impl Storage { /// https://html.spec.whatwg.org/multipage/#send-a-storage-notification fn broadcast_change_notification(&self, key: Option<String>, old_value: Option<String>, new_value: Option<String>) { + let pipeline_id = self.global().pipeline_id(); + let storage = self.storage_type; + let url = self.get_url(); + let msg = ScriptMsg::BroadcastStorageEvent(pipeline_id, storage, url, key, old_value, new_value); + self.global().constellation_chan().send(msg).unwrap(); + } + + /// https://html.spec.whatwg.org/multipage/#send-a-storage-notification + pub fn queue_storage_event(&self, url: Url, + key: Option<String>, old_value: Option<String>, new_value: Option<String>) { let global = self.global(); let window = global.as_window(); let task_source = window.dom_manipulation_task_source(); let trusted_storage = Trusted::new(self); task_source .queue( - box StorageEventRunnable::new(trusted_storage, key, old_value, new_value), &global) + box StorageEventRunnable::new(trusted_storage, url, key, old_value, new_value), &global) .unwrap(); } } pub struct StorageEventRunnable { element: Trusted<Storage>, + url: Url, key: Option<String>, old_value: Option<String>, new_value: Option<String> } impl StorageEventRunnable { - fn new(storage: Trusted<Storage>, key: Option<String>, old_value: Option<String>, - new_value: Option<String>) -> StorageEventRunnable { - StorageEventRunnable { element: storage, key: key, old_value: old_value, new_value: new_value } + fn new(storage: Trusted<Storage>, url: Url, + key: Option<String>, old_value: Option<String>, new_value: Option<String>) -> StorageEventRunnable { + StorageEventRunnable { element: storage, url: url, key: key, old_value: old_value, new_value: new_value } } } impl Runnable for StorageEventRunnable { fn name(&self) -> &'static str { "StorageEventRunnable" } - fn main_thread_handler(self: Box<StorageEventRunnable>, script_thread: &ScriptThread) { + fn main_thread_handler(self: Box<StorageEventRunnable>, _: &ScriptThread) { let this = *self; let storage = this.element.root(); let global = storage.global(); - let ev_url = storage.get_url(); + let window = global.as_window(); let storage_event = StorageEvent::new( &global, atom!("storage"), EventBubbles::DoesNotBubble, EventCancelable::NotCancelable, this.key.map(DOMString::from), this.old_value.map(DOMString::from), this.new_value.map(DOMString::from), - DOMString::from(ev_url.to_string()), + DOMString::from(this.url.into_string()), Some(&storage) ); - // TODO: This is only iterating over documents in the current script - // thread, so we are not firing events to other script threads. - // NOTE: once that is fixed, we can remove borrow_documents from ScriptThread. - for (id, document) in script_thread.borrow_documents().iter() { - if ev_url.origin() == document.window().get_url().origin() { - // TODO: Such a Document object is not necessarily fully active, but events fired on such - // objects are ignored by the event loop until the Document becomes fully active again. - if global.pipeline_id() != id { - storage_event.upcast::<Event>().fire(document.window().upcast()); - } - } - } + storage_event.upcast::<Event>().fire(window.upcast()); } } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 7dfe41dac20..632397cc147 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -75,6 +75,7 @@ use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace}; use net_traits::{CoreResourceMsg, IpcSend, Metadata, ReferrerPolicy, ResourceThreads}; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread}; use net_traits::request::{CredentialsMode, Destination, RequestInit}; +use net_traits::storage_thread::StorageType; use network_listener::NetworkListener; use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan}; use profile_traits::time::{self, ProfilerCategory, profile}; @@ -90,7 +91,7 @@ use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent}; use script_traits::webdriver_msg::WebDriverScriptCommand; use std::borrow::ToOwned; -use std::cell::{Cell, Ref}; +use std::cell::Cell; use std::collections::{hash_map, HashMap, HashSet}; use std::option::Option; use std::ptr; @@ -605,12 +606,6 @@ impl ScriptThread { })) } - // TODO: This method is only needed for storage, and can be removed - // once storage event dispatch is moved to the constellation. - pub fn borrow_documents(&self) -> Ref<Documents> { - self.documents.borrow() - } - /// Creates a new script thread. pub fn new(state: InitialScriptState, port: Receiver<MainThreadScriptMsg>, @@ -981,6 +976,8 @@ impl ScriptThread { ConstellationControlMsg::DispatchFrameLoadEvent { target: frame_id, parent: parent_id, child: child_id } => self.handle_frame_load_event(parent_id, frame_id, child_id), + ConstellationControlMsg::DispatchStorageEvent(pipeline_id, storage, url, key, old_value, new_value) => + self.handle_storage_event(pipeline_id, storage, url, key, old_value, new_value), ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, frame_id) => self.handle_framed_content_changed(parent_pipeline_id, frame_id), ConstellationControlMsg::ReportCSSError(pipeline_id, filename, line, column, msg) => @@ -1582,6 +1579,20 @@ impl ScriptThread { } } + /// Notify a window of a storage event + fn handle_storage_event(&self, pipeline_id: PipelineId, storage_type: StorageType, url: Url, + key: Option<String>, old_value: Option<String>, new_value: Option<String>) { + let storage = match self.documents.borrow().find_window(pipeline_id) { + None => return warn!("Storage event sent to closed pipeline {}.", pipeline_id), + Some(window) => match storage_type { + StorageType::Local => window.LocalStorage(), + StorageType::Session => window.SessionStorage(), + }, + }; + + storage.queue_storage_event(url, key, old_value, new_value); + } + /// Notify the containing document of a child frame that has completed loading. fn handle_frame_load_event(&self, parent_id: PipelineId, frame_id: FrameId, child_id: PipelineId) { match self.documents.borrow().find_iframe(parent_id, frame_id) { diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 9db84516fde..b475a214cc1 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -60,6 +60,7 @@ use net_traits::{ReferrerPolicy, ResourceThreads}; use net_traits::image::base::Image; use net_traits::image_cache_thread::ImageCacheThread; use net_traits::response::HttpsState; +use net_traits::storage_thread::StorageType; use profile_traits::mem; use profile_traits::time as profile_time; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -244,6 +245,9 @@ pub enum ConstellationControlMsg { /// The pipeline that has completed loading. child: PipelineId, }, + /// Cause a `storage` event to be dispatched at the appropriate window. + /// The strings are key, old value and new value. + DispatchStorageEvent(PipelineId, StorageType, Url, Option<String>, Option<String>, Option<String>), /// Notifies a parent pipeline that one of its child frames is now active. /// PipelineId is for the parent, FrameId is the child frame. FramedContentChanged(PipelineId, FrameId), @@ -279,6 +283,7 @@ impl fmt::Debug for ConstellationControlMsg { TransitionEnd(..) => "TransitionEnd", WebFontLoaded(..) => "WebFontLoaded", DispatchFrameLoadEvent { .. } => "DispatchFrameLoadEvent", + DispatchStorageEvent(..) => "DispatchStorageEvent", FramedContentChanged(..) => "FramedContentChanged", ReportCSSError(..) => "ReportCSSError", Reload(..) => "Reload" diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 7969218e5d3..434aa0011e6 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -18,6 +18,7 @@ use ipc_channel::ipc::IpcSender; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use msg::constellation_msg::{PipelineId, TraversalDirection}; use net_traits::CoreResourceMsg; +use net_traits::storage_thread::StorageType; use offscreen_gl_context::{GLContextAttributes, GLLimits}; use style_traits::cursor::Cursor; use style_traits::viewport::ViewportConstraints; @@ -59,6 +60,9 @@ pub enum LogEntry { /// Messages from the script to the constellation. #[derive(Deserialize, Serialize)] pub enum ScriptMsg { + /// Broadcast a storage event to every same-origin pipeline. + /// The strings are key, old value and new value. + BroadcastStorageEvent(PipelineId, StorageType, Url, Option<String>, Option<String>, Option<String>), /// Indicates whether this pipeline is currently running animations. ChangeRunningAnimationsState(PipelineId, AnimationState), /// Requests that a new 2D canvas thread be created. (This is done in the constellation because diff --git a/tests/wpt/metadata/html/browsers/windows/noreferrer.html.ini b/tests/wpt/metadata/html/browsers/windows/noreferrer.html.ini index 20debcea4b2..612e98c21b7 100644 --- a/tests/wpt/metadata/html/browsers/windows/noreferrer.html.ini +++ b/tests/wpt/metadata/html/browsers/windows/noreferrer.html.ini @@ -1,6 +1,5 @@ [noreferrer.html] type: testharness - expected: CRASH [rel=noreferrer nullifies window.opener] - expected: CRASH + expected: FAIL diff --git a/tests/wpt/metadata/webstorage/event_local_removeitem.html.ini b/tests/wpt/metadata/webstorage/event_local_removeitem.html.ini deleted file mode 100644 index e199ad9e5f7..00000000000 --- a/tests/wpt/metadata/webstorage/event_local_removeitem.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[event_local_removeitem.html] - type: testharness - [key property test of local event] - expected: FAIL - diff --git a/tests/wpt/metadata/webstorage/event_session_removeitem.html.ini b/tests/wpt/metadata/webstorage/event_session_removeitem.html.ini deleted file mode 100644 index 7b8bfcb51ba..00000000000 --- a/tests/wpt/metadata/webstorage/event_session_removeitem.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[event_session_removeitem.html] - type: testharness - [key property test of session event] - expected: FAIL - |