mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
servo: Merge #8658 - Implement origin concept and browsing contextless documents (from jdm:origin2); r=Ms2ger+jdm
These pave the way for implementing other parts of specifications more thoroughly. Source-Repo: https://github.com/servo/servo Source-Revision: 9b57d8d686d361c0dfba1056523cbea12abd148b
This commit is contained in:
parent
466c19a211
commit
c57148a88d
@ -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>);
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1868,9 +1881,18 @@ impl DocumentMethods for Document {
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#relaxing-the-same-origin-restriction
|
||||
fn Domain(&self) -> DOMString {
|
||||
// TODO: This should use the effective script origin when it exists
|
||||
let origin = self.window.get_url();
|
||||
DOMString::from(origin.serialize_host().unwrap_or_else(|| "".to_owned()))
|
||||
// Step 1.
|
||||
if self.browsing_context().is_none() {
|
||||
return DOMString::new();
|
||||
}
|
||||
|
||||
if let Some(host) = self.origin.host() {
|
||||
// Step 4.
|
||||
DOMString::from(host.serialize())
|
||||
} else {
|
||||
// Step 3.
|
||||
DOMString::new()
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-document-documenturi
|
||||
@ -2497,10 +2519,11 @@ impl DocumentMethods for Document {
|
||||
return Ok(DOMString::new());
|
||||
}
|
||||
|
||||
let url = self.url();
|
||||
if !is_scheme_host_port_tuple(&url) {
|
||||
if !self.origin.is_scheme_host_port_tuple() {
|
||||
return Err(Error::Security);
|
||||
}
|
||||
|
||||
let url = self.url();
|
||||
let (tx, rx) = ipc::channel().unwrap();
|
||||
let _ = self.window.resource_thread().send(GetCookiesForUrl((*url).clone(), tx, NonHTTP));
|
||||
let cookies = rx.recv().unwrap();
|
||||
@ -2513,10 +2536,11 @@ impl DocumentMethods for Document {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let url = self.url();
|
||||
if !is_scheme_host_port_tuple(url) {
|
||||
if !self.origin.is_scheme_host_port_tuple() {
|
||||
return Err(Error::Security);
|
||||
}
|
||||
|
||||
let url = self.url();
|
||||
let _ = self.window
|
||||
.resource_thread()
|
||||
.send(SetCookiesForUrl((*url).clone(), String::from(cookie), NonHTTP));
|
||||
@ -2720,10 +2744,6 @@ impl DocumentMethods for Document {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_scheme_host_port_tuple(url: &Url) -> bool {
|
||||
url.host().is_some() && url.port_or_default().is_some()
|
||||
}
|
||||
|
||||
fn update_with_current_time_ms(marker: &Cell<u64>) {
|
||||
if marker.get() == Default::default() {
|
||||
let time = time::get_time();
|
||||
|
@ -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;
|
||||
|
73
servo/components/script/origin.rs
Normal file
73
servo/components/script/origin.rs
Normal file
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
2
servo/components/servo/Cargo.lock
generated
2
servo/components/servo/Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
||||
|
@ -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"]}
|
||||
|
@ -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 {
|
||||
|
105
servo/tests/unit/script/origin.rs
Normal file
105
servo/tests/unit/script/origin.rs
Normal file
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user