aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Jeffrey <ajeffrey@mozilla.com>2016-11-01 20:49:46 -0500
committerAlan Jeffrey <ajeffrey@mozilla.com>2016-11-15 09:57:12 -0600
commitc91ef86a20813d433fb7fb595c37d611d27967d0 (patch)
treefdfab8c411c77d05604ff166a9b623f4a957978e
parentef74d8da3bdb1cc3b1edf767a593e0e59228f23b (diff)
downloadservo-c91ef86a20813d433fb7fb595c37d611d27967d0.tar.gz
servo-c91ef86a20813d433fb7fb595c37d611d27967d0.zip
Storage notifications routed via the constellation.
-rw-r--r--components/constellation/constellation.rs20
-rw-r--r--components/script/dom/storage.rs39
-rw-r--r--components/script/script_thread.rs25
-rw-r--r--components/script_traits/lib.rs5
-rw-r--r--components/script_traits/script_msg.rs4
-rw-r--r--tests/wpt/metadata/html/browsers/windows/noreferrer.html.ini3
-rw-r--r--tests/wpt/metadata/webstorage/event_local_removeitem.html.ini5
-rw-r--r--tests/wpt/metadata/webstorage/event_session_removeitem.html.ini5
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
-