diff options
-rw-r--r-- | components/script/dom/bindings/trace.rs | 3 | ||||
-rw-r--r-- | components/script/dom/document.rs | 29 | ||||
-rw-r--r-- | components/script/lib.rs | 1 | ||||
-rw-r--r-- | components/script/origin.rs | 73 | ||||
-rw-r--r-- | components/servo/Cargo.lock | 2 | ||||
-rw-r--r-- | tests/unit/script/Cargo.toml | 6 | ||||
-rw-r--r-- | tests/unit/script/lib.rs | 5 | ||||
-rw-r--r-- | tests/unit/script/origin.rs | 105 |
8 files changed, 215 insertions, 9 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 16138b33641..50c3fbf682f 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -89,6 +89,7 @@ use style::properties::PropertyDeclarationBlock; use style::restyle_hints::ElementSnapshot; use style::selector_impl::PseudoElement; use style::values::specified::Length; +use url::Origin as UrlOrigin; use url::Url; use util::str::{DOMString, LengthOrPercentageOrAuto}; use uuid::Uuid; @@ -276,7 +277,7 @@ impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, B, C) { } } -no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool, AtomicUsize, Uuid); +no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool, AtomicUsize, UrlOrigin, Uuid); no_jsmanaged_fields!(usize, u8, u16, u32, u64); no_jsmanaged_fields!(isize, i8, i16, i32, i64); no_jsmanaged_fields!(Sender<T>); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index e38ab86bf29..9bb9a656719 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -94,6 +94,7 @@ use net_traits::CookieSource::NonHTTP; use net_traits::response::HttpsState; use net_traits::{AsyncResponseTarget, PendingAsyncLoad}; use num::ToPrimitive; +use origin::Origin; use script_runtime::ScriptChan; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable}; use script_traits::UntrustedNodeAddress; @@ -223,6 +224,8 @@ pub struct Document { /// https://html.spec.whatwg.org/multipage/#concept-document-https-state https_state: Cell<HttpsState>, touchpad_pressure_phase: Cell<TouchpadPressurePhase>, + /// The document's origin. + origin: Origin, } #[derive(JSTraceable, HeapSizeOf)] @@ -1544,14 +1547,6 @@ impl Document { /// https://html.spec.whatwg.org/multipage/#cookie-averse-document-object fn is_cookie_averse(&self) -> bool { - /// https://url.spec.whatwg.org/#network-scheme - fn url_has_network_scheme(url: &Url) -> bool { - match &*url.scheme { - "ftp" | "http" | "https" => true, - _ => false, - } - } - self.browsing_context.is_none() || !url_has_network_scheme(&self.url) } @@ -1590,6 +1585,14 @@ impl LayoutDocumentHelpers for LayoutJS<Document> { } } +/// https://url.spec.whatwg.org/#network-scheme +fn url_has_network_scheme(url: &Url) -> bool { + match &*url.scheme { + "ftp" | "http" | "https" => true, + _ => false, + } +} + impl Document { pub fn new_inherited(window: &Window, browsing_context: Option<&BrowsingContext>, @@ -1608,6 +1611,15 @@ impl Document { (DocumentReadyState::Complete, true) }; + // Incomplete implementation of Document origin specification at + // https://html.spec.whatwg.org/multipage/#origin:document + let origin = if url_has_network_scheme(&url) { + Origin::new(&url) + } else { + // Default to DOM standard behaviour + Origin::opaque_identifier() + }; + Document { node: Node::new_document_node(), window: JS::from_ref(window), @@ -1673,6 +1685,7 @@ impl Document { css_errors_store: DOMRefCell::new(vec![]), https_state: Cell::new(HttpsState::None), touchpad_pressure_phase: Cell::new(TouchpadPressurePhase::BeforeClick), + origin: origin, } } diff --git a/components/script/lib.rs b/components/script/lib.rs index d3913865070..e525a62b70d 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -90,6 +90,7 @@ pub mod dom; pub mod layout_interface; mod mem; mod network_listener; +pub mod origin; pub mod page; pub mod parse; pub mod reporter; diff --git a/components/script/origin.rs b/components/script/origin.rs new file mode 100644 index 00000000000..096ffbbd6fb --- /dev/null +++ b/components/script/origin.rs @@ -0,0 +1,73 @@ +/* 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 std::cell::RefCell; +use std::rc::Rc; +use url::{OpaqueOrigin, Origin as UrlOrigin}; +use url::{Url, Host}; + +/// A representation of an [origin](https://html.spec.whatwg.org/multipage/#origin-2). +#[derive(HeapSizeOf)] +pub struct Origin { + #[ignore_heap_size_of = "Rc<T> has unclear ownership semantics"] + inner: Rc<RefCell<UrlOrigin>>, +} + +// We can't use RefCell inside JSTraceable, but Origin doesn't contain JS values and +// DOMRefCell makes it much harder to write unit tests (due to setting up required TLS). +no_jsmanaged_fields!(Origin); + +impl Origin { + /// Create a new origin comprising a unique, opaque identifier. + pub fn opaque_identifier() -> Origin { + let opaque = UrlOrigin::UID(OpaqueOrigin::new()); + Origin { + inner: Rc::new(RefCell::new(opaque)), + } + } + + /// Create a new origin for the given URL. + pub fn new(url: &Url) -> Origin { + Origin { + inner: Rc::new(RefCell::new(url.origin())), + } + } + + pub fn set(&self, origin: UrlOrigin) { + *self.inner.borrow_mut() = origin; + } + + /// Does this origin represent a host/scheme/port tuple? + pub fn is_scheme_host_port_tuple(&self) -> bool { + match *self.inner.borrow() { + UrlOrigin::Tuple(..) => true, + UrlOrigin::UID(..) => false, + } + } + + /// Return the host associated with this origin. + pub fn host(&self) -> Option<Host> { + match *self.inner.borrow() { + UrlOrigin::Tuple(_, ref host, _) => Some(host.clone()), + UrlOrigin::UID(..) => None, + } + } + + /// https://html.spec.whatwg.org/multipage/#same-origin + pub fn same_origin(&self, other: &Origin) -> bool { + *self.inner.borrow() == *other.inner.borrow() + } + + pub fn copy(&self) -> Origin { + Origin { + inner: Rc::new(RefCell::new(self.inner.borrow().clone())), + } + } + + pub fn alias(&self) -> Origin { + Origin { + inner: self.inner.clone(), + } + } +} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 07c6aa3a0cb..8cb85eb5550 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1752,7 +1752,9 @@ name = "script_tests" version = "0.0.1" dependencies = [ "msg 0.0.1", + "plugins 0.0.1", "script 0.0.1", + "url 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", ] diff --git a/tests/unit/script/Cargo.toml b/tests/unit/script/Cargo.toml index 8aa177e966b..b34cfb238f6 100644 --- a/tests/unit/script/Cargo.toml +++ b/tests/unit/script/Cargo.toml @@ -11,8 +11,14 @@ doctest = false [dependencies.msg] path = "../../../components/msg" +[dependencies.plugins] +path = "../../../components/plugins" + [dependencies.script] path = "../../../components/script" [dependencies.util] path = "../../../components/util" + +[dependencies] +url = {version = "0.5.8", features = ["heap_size"]} diff --git a/tests/unit/script/lib.rs b/tests/unit/script/lib.rs index 8270d8542d7..2dbbd16ea7a 100644 --- a/tests/unit/script/lib.rs +++ b/tests/unit/script/lib.rs @@ -2,10 +2,15 @@ * 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/. */ +#![feature(plugin)] +#![plugin(plugins)] + extern crate msg; extern crate script; +extern crate url; extern crate util; +#[cfg(test)] mod origin; #[cfg(all(test, target_pointer_width = "64"))] mod size_of; #[cfg(test)] mod textinput; #[cfg(test)] mod dom { diff --git a/tests/unit/script/origin.rs b/tests/unit/script/origin.rs new file mode 100644 index 00000000000..81e5d538686 --- /dev/null +++ b/tests/unit/script/origin.rs @@ -0,0 +1,105 @@ +/* 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 script::origin::Origin; + +#[test] +fn same_origin() { + let a = Origin::new(&url!("http://example.com/a.html")); + let b = Origin::new(&url!("http://example.com/b.html")); + assert!(a.same_origin(&b)); + assert_eq!(a.is_scheme_host_port_tuple(), true); +} + +#[test] +fn identical_origin() { + let a = Origin::new(&url!("http://example.com/a.html")); + assert!(a.same_origin(&a)); +} + +#[test] +fn cross_origin() { + let a = Origin::new(&url!("http://example.com/a.html")); + let b = Origin::new(&url!("http://example.org/b.html")); + assert!(!a.same_origin(&b)); +} + +#[test] +fn alias_same_origin() { + let a = Origin::new(&url!("http://example.com/a.html")); + let b = Origin::new(&url!("http://example.com/b.html")); + let c = b.alias(); + assert!(a.same_origin(&c)); + assert!(b.same_origin(&b)); + assert!(c.same_origin(&b)); + assert_eq!(c.is_scheme_host_port_tuple(), true); +} + +#[test] +fn alias_cross_origin() { + let a = Origin::new(&url!("http://example.com/a.html")); + let b = Origin::new(&url!("http://example.org/b.html")); + let c = b.alias(); + assert!(!a.same_origin(&c)); + assert!(b.same_origin(&c)); + assert!(c.same_origin(&c)); +} + +#[test] +fn alias_update_same_origin() { + let a = Origin::new(&url!("http://example.com/a.html")); + let b = Origin::new(&url!("http://example.org/b.html")); + let c = b.alias(); + b.set(url!("http://example.com/c.html").origin()); + assert!(a.same_origin(&c)); + assert!(b.same_origin(&c)); + assert!(c.same_origin(&c)); +} + +#[test] +fn alias_update_cross_origin() { + let a = Origin::new(&url!("http://example.com/a.html")); + let b = Origin::new(&url!("http://example.com/b.html")); + let c = b.alias(); + b.set(url!("http://example.org/c.html").origin()); + assert!(!a.same_origin(&c)); + assert!(b.same_origin(&c)); + assert!(c.same_origin(&c)); +} + +#[test] +fn alias_chain() { + let a = Origin::new(&url!("http://example.com/a.html")); + let b = Origin::new(&url!("http://example.com/b.html")); + let c = b.copy(); + let d = c.alias(); + let e = d.alias(); + assert!(a.same_origin(&e)); + assert!(b.same_origin(&e)); + assert!(c.same_origin(&e)); + assert!(d.same_origin(&e)); + assert!(e.same_origin(&e)); + c.set(url!("http://example.org/c.html").origin()); + assert!(a.same_origin(&b)); + assert!(!b.same_origin(&c)); + assert!(c.same_origin(&d)); + assert!(d.same_origin(&e)); + assert!(!e.same_origin(&a)); +} + +#[test] +fn opaque() { + let a = Origin::opaque_identifier(); + let b = Origin::opaque_identifier(); + assert!(!a.same_origin(&b)); + assert_eq!(a.is_scheme_host_port_tuple(), false); +} + +#[test] +fn opaque_clone() { + let a = Origin::opaque_identifier(); + let b = a.alias(); + assert!(a.same_origin(&b)); + assert_eq!(a.is_scheme_host_port_tuple(), false); +} |