Auto merge of #26499 - utsavoza:ugo/issue-26287/10-05-2020, r=jdm

Add creator URL, creator base URL and creator origin to browsing context

- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #24944 and fix (partially) #26287
- [x] There are tests for these changes
This commit is contained in:
bors-servo 2020-05-19 12:45:11 -04:00 committed by GitHub
commit cab9104d92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 216 additions and 107 deletions

View file

@ -60,7 +60,6 @@ impl Blob {
blobParts: Option<Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>>,
blobPropertyBag: &BlobBinding::BlobPropertyBag,
) -> Fallible<DomRoot<Blob>> {
// TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView
let bytes: Vec<u8> = match blobParts {
None => Vec::new(),
Some(blobparts) => match blob_parts_to_bytes(blobparts) {

View file

@ -683,10 +683,25 @@ impl Document {
// https://html.spec.whatwg.org/multipage/#fallback-base-url
pub fn fallback_base_url(&self) -> ServoUrl {
// Step 1: iframe srcdoc (#4767).
// Step 2: about:blank with a creator browsing context.
// Step 3.
self.url()
let document_url = self.url();
if let Some(browsing_context) = self.browsing_context() {
// Step 1: If document is an iframe srcdoc document, then return the
// document base URL of document's browsing context's container document.
let container_base_url = browsing_context
.parent()
.and_then(|parent| parent.document())
.map(|document| document.base_url());
if document_url.as_str() == "about:srcdoc" && container_base_url.is_some() {
return container_base_url.unwrap();
}
// Step 2: If document's URL is about:blank, and document's browsing
// context's creator base URL is non-null, then return that creator base URL.
if document_url.as_str() == "about:blank" && browsing_context.has_creator_base_url() {
return browsing_context.creator_base_url().unwrap();
}
}
// Step 3: Return document's URL.
document_url
}
// https://html.spec.whatwg.org/multipage/#document-base-url

View file

@ -637,7 +637,7 @@ pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
if let Some(suffix) = hyperlink_suffix {
href.push_str(&suffix);
}
let url = match document.url().join(&href) {
let url = match document.base_url().join(&href) {
Ok(url) => url,
Err(_) => return,
};

View file

@ -9,7 +9,6 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString;
use crate::dom::document::Document;
use crate::dom::globalscope::GlobalScope;
use crate::dom::urlhelper::UrlHelper;
use crate::dom::window::Window;
@ -66,7 +65,7 @@ impl Location {
fn check_same_origin_domain(&self) -> ErrorResult {
let this_document = self.window.Document();
if self
.entry_document()
.entry_settings_object()
.origin()
.same_origin_domain(this_document.origin())
{
@ -76,8 +75,8 @@ impl Location {
}
}
fn entry_document(&self) -> DomRoot<Document> {
GlobalScope::entry().as_window().Document()
fn entry_settings_object(&self) -> DomRoot<GlobalScope> {
GlobalScope::entry()
}
// https://html.spec.whatwg.org/multipage/#dom-location-reload
@ -104,7 +103,7 @@ impl LocationMethods for Location {
self.check_same_origin_domain()?;
// Step 3: Parse url relative to the entry settings object. If that failed,
// throw a "SyntaxError" DOMException.
let base_url = self.entry_document().url();
let base_url = self.entry_settings_object().api_base_url();
let url = match base_url.join(&url.0) {
Ok(url) => url,
Err(_) => return Err(Error::Syntax),
@ -131,7 +130,7 @@ impl LocationMethods for Location {
if self.window.has_document() {
// Step 2: Parse url relative to the entry settings object. If that failed,
// throw a "SyntaxError" DOMException.
let base_url = self.entry_document().url();
let base_url = self.entry_settings_object().api_base_url();
let url = match base_url.join(&url.0) {
Ok(url) => url,
Err(_) => return Err(Error::Syntax),
@ -253,7 +252,7 @@ impl LocationMethods for Location {
// Note: no call to self.check_same_origin_domain()
// Step 2: Parse the given value relative to the entry settings object.
// If that failed, throw a TypeError exception.
let base_url = self.entry_document().url();
let base_url = self.entry_settings_object().api_base_url();
let url = match base_url.join(&value.0) {
Ok(url) => url,
Err(e) => return Err(Error::Type(format!("Couldn't parse URL: {}", e))),

View file

@ -155,7 +155,7 @@ impl URL {
result.push('/');
// Step 5
result.push_str(&id.to_simple().to_string());
result.push_str(&id.to_string());
result
}

View file

@ -52,7 +52,7 @@ use script_traits::{
AuxiliaryBrowsingContextLoadInfo, HistoryEntryReplacement, LoadData, LoadOrigin,
};
use script_traits::{NewLayoutInfo, ScriptMsg};
use servo_url::ServoUrl;
use servo_url::{ImmutableOrigin, ServoUrl};
use std::cell::Cell;
use std::ptr;
use style::attr::parse_integer;
@ -108,6 +108,15 @@ pub struct WindowProxy {
/// https://html.spec.whatwg.org/multipage/#delaying-load-events-mode
delaying_load_events_mode: Cell<bool>,
/// The creator browsing context's base url.
creator_base_url: Option<ServoUrl>,
/// The creator browsing context's url.
creator_url: Option<ServoUrl>,
/// The creator browsing context's origin.
creator_origin: Option<ImmutableOrigin>,
}
impl WindowProxy {
@ -118,6 +127,7 @@ impl WindowProxy {
frame_element: Option<&Element>,
parent: Option<&WindowProxy>,
opener: Option<BrowsingContextId>,
creator: CreatorBrowsingContextInfo,
) -> WindowProxy {
let name = frame_element.map_or(DOMString::new(), |e| {
e.get_string_attribute(&local_name!("name"))
@ -135,6 +145,9 @@ impl WindowProxy {
parent: parent.map(Dom::from_ref),
delaying_load_events_mode: Cell::new(false),
opener,
creator_base_url: creator.base_url,
creator_url: creator.url,
creator_origin: creator.origin,
}
}
@ -146,6 +159,7 @@ impl WindowProxy {
frame_element: Option<&Element>,
parent: Option<&WindowProxy>,
opener: Option<BrowsingContextId>,
creator: CreatorBrowsingContextInfo,
) -> DomRoot<WindowProxy> {
unsafe {
let WindowProxyHandler(handler) = window.windowproxy_handler();
@ -173,6 +187,7 @@ impl WindowProxy {
frame_element,
parent,
opener,
creator,
));
// The window proxy owns the browsing context.
@ -204,6 +219,7 @@ impl WindowProxy {
top_level_browsing_context_id: TopLevelBrowsingContextId,
parent: Option<&WindowProxy>,
opener: Option<BrowsingContextId>,
creator: CreatorBrowsingContextInfo,
) -> DomRoot<WindowProxy> {
unsafe {
let handler = CreateWrapperProxyHandler(&XORIGIN_PROXY_HANDLER);
@ -219,6 +235,7 @@ impl WindowProxy {
None,
parent,
opener,
creator,
));
// Create a new dissimilar-origin window.
@ -368,6 +385,33 @@ impl WindowProxy {
self.is_closing.get()
}
/// https://html.spec.whatwg.org/multipage/#creator-base-url
pub fn creator_base_url(&self) -> Option<ServoUrl> {
self.creator_base_url.clone()
}
pub fn has_creator_base_url(&self) -> bool {
self.creator_base_url.is_some()
}
/// https://html.spec.whatwg.org/multipage/#creator-url
pub fn creator_url(&self) -> Option<ServoUrl> {
self.creator_url.clone()
}
pub fn has_creator_url(&self) -> bool {
self.creator_base_url.is_some()
}
/// https://html.spec.whatwg.org/multipage/#creator-origin
pub fn creator_origin(&self) -> Option<ImmutableOrigin> {
self.creator_origin.clone()
}
pub fn has_creator_origin(&self) -> bool {
self.creator_origin.is_some()
}
#[allow(unsafe_code)]
// https://html.spec.whatwg.org/multipage/#dom-opener
pub fn opener(&self, cx: *mut JSContext, in_realm_proof: InRealm) -> JSVal {
@ -378,6 +422,7 @@ impl WindowProxy {
Some(opener_browsing_context_id) => opener_browsing_context_id,
None => return NullValue(),
};
let parent_browsing_context = self.parent.as_deref();
let opener_proxy = match ScriptThread::find_window_proxy(opener_id) {
Some(window_proxy) => window_proxy,
None => {
@ -389,12 +434,15 @@ impl WindowProxy {
Some(opener_top_id) => {
let global_to_clone_from =
unsafe { GlobalScope::from_context(cx, in_realm_proof) };
let creator =
CreatorBrowsingContextInfo::from(parent_browsing_context, None);
WindowProxy::new_dissimilar_origin(
&*global_to_clone_from,
opener_id,
opener_top_id,
None,
None,
creator,
)
},
None => return NullValue(),
@ -655,6 +703,54 @@ impl WindowProxy {
}
}
/// A browsing context can have a creator browsing context, the browsing context that
/// was responsible for its creation. If a browsing context has a parent browsing context,
/// then that is its creator browsing context. Otherwise, if the browsing context has an
/// opener browsing context, then that is its creator browsing context. Otherwise, the
/// browsing context has no creator browsing context.
///
/// If a browsing context A has a creator browsing context, then the Document that was the
/// active document of that creator browsing context at the time A was created is the creator
/// Document.
///
/// See: https://html.spec.whatwg.org/multipage/#creating-browsing-contexts
#[derive(Debug, Deserialize, Serialize)]
pub struct CreatorBrowsingContextInfo {
/// Creator document URL.
url: Option<ServoUrl>,
/// Creator document base URL.
base_url: Option<ServoUrl>,
/// Creator document origin.
origin: Option<ImmutableOrigin>,
}
impl CreatorBrowsingContextInfo {
pub fn from(
parent: Option<&WindowProxy>,
opener: Option<&WindowProxy>,
) -> CreatorBrowsingContextInfo {
let creator = match (parent, opener) {
(Some(parent), _) => parent.document(),
(None, Some(opener)) => opener.document(),
(None, None) => None,
};
let base_url = creator.as_deref().map(|document| document.base_url());
let url = creator.as_deref().map(|document| document.url());
let origin = creator
.as_deref()
.map(|document| document.origin().immutable().clone());
CreatorBrowsingContextInfo {
base_url,
url,
origin,
}
}
}
// https://html.spec.whatwg.org/multipage/#concept-window-open-features-tokenize
fn tokenize_open_features(features: DOMString) -> IndexMap<String, String> {
let is_feature_sep = |c: char| c.is_ascii_whitespace() || ['=', ','].contains(&c);

View file

@ -68,7 +68,7 @@ use crate::dom::servoparser::{ParserContext, ServoParser};
use crate::dom::transitionevent::TransitionEvent;
use crate::dom::uievent::UIEvent;
use crate::dom::window::{ReflowReason, Window};
use crate::dom::windowproxy::WindowProxy;
use crate::dom::windowproxy::{CreatorBrowsingContextInfo, WindowProxy};
use crate::dom::worker::TrustedWorkerAddress;
use crate::dom::worklet::WorkletThreadPool;
use crate::dom::workletglobalscope::WorkletGlobalScopeInit;
@ -3162,7 +3162,7 @@ impl ScriptThread {
return Some(DomRoot::from_ref(window_proxy));
}
let parent = parent_pipeline_id.and_then(|parent_id| {
let parent_browsing_context = parent_pipeline_id.and_then(|parent_id| {
self.remote_window_proxy(
global_to_clone,
top_level_browsing_context_id,
@ -3170,12 +3170,21 @@ impl ScriptThread {
opener,
)
});
let opener_browsing_context = opener.and_then(|id| ScriptThread::find_window_proxy(id));
let creator = CreatorBrowsingContextInfo::from(
parent_browsing_context.as_deref(),
opener_browsing_context.as_deref(),
);
let window_proxy = WindowProxy::new_dissimilar_origin(
global_to_clone,
browsing_context_id,
top_level_browsing_context_id,
parent.as_deref(),
parent_browsing_context.as_deref(),
opener,
creator,
);
self.window_proxies
.borrow_mut()
@ -3207,7 +3216,7 @@ impl ScriptThread {
.borrow()
.find_iframe(parent_id, browsing_context_id)
});
let parent = match (parent_info, iframe.as_ref()) {
let parent_browsing_context = match (parent_info, iframe.as_ref()) {
(_, Some(iframe)) => Some(window_from_node(&**iframe).window_proxy()),
(Some(parent_id), _) => self.remote_window_proxy(
window.upcast(),
@ -3217,13 +3226,22 @@ impl ScriptThread {
),
_ => None,
};
let opener_browsing_context = opener.and_then(|id| ScriptThread::find_window_proxy(id));
let creator = CreatorBrowsingContextInfo::from(
parent_browsing_context.as_deref(),
opener_browsing_context.as_deref(),
);
let window_proxy = WindowProxy::new(
&window,
browsing_context_id,
top_level_browsing_context_id,
iframe.as_deref().map(Castable::upcast),
parent.as_deref(),
parent_browsing_context.as_deref(),
opener,
creator,
);
self.window_proxies
.borrow_mut()

View file

@ -1,4 +1,43 @@
[sandboxed-iframe.html]
expected: TIMEOUT
[Blob URLs can be used in <script> tags]
expected: TIMEOUT
[Blob URLs can be used in iframes, and are treated same origin]
expected: FAIL
[Blob URL fragment is implemented.]
expected: TIMEOUT
[Blob URLs can be used in XHR]
expected: FAIL
[XHR with a fragment should succeed]
expected: FAIL
[Only exact matches should revoke URLs, using XHR]
expected: FAIL
[Revoke blob URL after open(), will fetch]
expected: FAIL
[Blob URLs can be used in fetch]
expected: FAIL
[fetch with a fragment should succeed]
expected: FAIL
[Only exact matches should revoke URLs, using fetch]
expected: FAIL
[fetch should return Content-Type from Blob]
expected: FAIL
[Revoke blob URL after creating Request, will fetch]
expected: FAIL
[Revoke blob URL after calling fetch, fetch should succeed]
expected: FAIL
[XHR should return Content-Type from Blob]
expected: FAIL

View file

@ -2,14 +2,7 @@
[Generated Blob URLs are unique]
expected: FAIL
[Blob URL parses correctly]
expected: FAIL
[url-format.any.html]
[Generated Blob URLs are unique]
expected: FAIL
[Blob URL parses correctly]
expected: FAIL

View file

@ -1,5 +0,0 @@
[viewport-units-after-font-load.html]
expected: TIMEOUT
[Viewport units are correctly updated after resize even if a font load has happened before]
expected: TIMEOUT

View file

@ -18,39 +18,11 @@
[Fetch: /images/green-1x1.png?<\\t=block]
expected: FAIL
[<img id="dangling" src="/images/green-1x1.png?img=&lt;b">]
[<img id="dangling" src="/images/green-1x1.png?img=&#10;&lt;b">]
expected: FAIL
[<img id="dangling" src="/images/green-1x1.png?img=&#10;b">]
[<img id="dangling" src="/images/green-1x1.png?img=&lt;&#10;b">]
expected: FAIL
[<img id="dangling" src="/images/green-1x1.png?img=&amp;#10;b">]
[\\n <img id="dangling" src="/images/green-1x1.png?img=\\n &lt;\\n &#10;b\\n ">\\n ]
expected: FAIL
[<img id="dangling" src="/images/green-1x1.png?img=&amp;lt;b">]
expected: FAIL
[<img id="dangling" src="/images/green-1x1.png?img=&amp;#10;b&amp;lt;c">]
expected: FAIL
[\\n <img id="dangling" src="\\n /images/green-1x1.png?img=\\n ">\\n ]
expected: FAIL
[\\n <img id="dangling" src="\\n /images/green-1x1.png?img=&amp;lt;\\n ">\\n ]
expected: FAIL
[\\n <img id="dangling" src="\\n /images/green-1x1.png?img=&amp;#10;\\n ">\\n ]
expected: FAIL
[<img id="dangling" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">]
expected: FAIL
[<img id="dangling" src="data:image/png;base64,&#10;iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">]
expected: FAIL
[<img id="dangling" src="data:image/png;base64,i&#10;VBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">]
expected: FAIL
[<img id="dangling" src="data:image/svg+xml;utf8,\\n <svg width='1' height='1' xmlns='http://www.w3.org/2000/svg'>\\n <rect width='100%' height='100%' fill='rebeccapurple'/>\\n <rect x='10%' y='10%' width='80%' height='80%' fill='lightgreen'/>\\n </svg>">]
expected: FAIL

View file

@ -0,0 +1,4 @@
[010.html]
type: testharness
[Link with onclick form submit to javascript url with delayed document.write and href navigation ]
expected: FAIL

View file

@ -1,14 +0,0 @@
[document-base-url.html]
type: testharness
[The fallback base URL of a document whose address is about:blank is the document base URL of the creator document.]
expected: FAIL
[The fallback base URL of an iframe srcdoc document is the document base URL of the document's browsing context's browsing context container's document.]
expected: FAIL
[about:blank with a base element.]
expected: FAIL
[The base URL of an iframe srcdoc document with a <base> tag should be set by that tag.]
expected: FAIL

View file

@ -1,5 +0,0 @@
[base_about_blank.html]
type: testharness
[base element in about:blank document should resolve against its fallback base URI]
expected: FAIL

View file

@ -1,5 +0,0 @@
[base_srcdoc.html]
type: testharness
[base element in srcdoc document should resolve against its fallback base URI]
expected: FAIL

View file

@ -1,5 +1,6 @@
[iframe_sandbox_anchor_download_allow_downloads.sub.tentative.html]
expected: TIMEOUT
[<a download> triggered download in sandbox is allowed by allow-downloads.]
expected: TIMEOUT
expected: FAIL
[<a download> triggered download in sandbox is blocked]
expected: FAIL

View file

@ -0,0 +1,3 @@
[iframe_sandbox_anchor_download_block_downloads.sub.tentative.html]
[<a download> triggered download in sandbox is blocked.]
expected: FAIL

View file

@ -1,5 +1,6 @@
[iframe_sandbox_navigation_download_allow_downloads.sub.tentative.html]
expected: TIMEOUT
[Navigation resulted download in sandbox is allowed by allow-downloads.]
expected: TIMEOUT
expected: FAIL
[Navigation resulted download in sandbox is blocked.]
expected: FAIL

View file

@ -0,0 +1,3 @@
[iframe_sandbox_navigation_download_block_downloads.sub.tentative.html]
[Navigation resulted download in sandbox is blocked.]
expected: FAIL

View file

@ -1,2 +1,4 @@
[move-element-and-scroll.html]
expected: ERROR
[Test that <img> below viewport is not loaded when moved to another document and then scrolled to]
expected: FAIL

View file

@ -0,0 +1,2 @@
[sizes-dynamic-001-ref.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[sizes-dynamic-001.html]
expected: FAIL

View file

@ -1,7 +1,10 @@
[abort-while-navigating.window.html]
expected: TIMEOUT
[document.open() aborts documents that are navigating through iframe loading (XMLHttpRequest)]
expected: FAIL
expected: TIMEOUT
[document.open() aborts documents that are navigating through iframe loading (fetch())]
expected: TIMEOUT
[document.open() aborts documents that are navigating through Location (fetch())]
expected: TIMEOUT

View file

@ -1,9 +1,5 @@
[sandboxed-iframe-with-opaque-origin.html]
type: testharness
expected: TIMEOUT
[Sandboxed iframe with opaque origin doesn't send referrers.]
expected: TIMEOUT
[Sandboxed iframe with tuple origin sends referrers.]
expected: TIMEOUT
expected: FAIL

View file

@ -1,5 +0,0 @@
[open-url-about-blank-window.htm]
type: testharness
[XMLHttpRequest: open() resolving URLs (about:blank iframe)]
expected: FAIL

View file

@ -1,5 +0,0 @@
[open-url-javascript-window-2.htm]
type: testharness
[XMLHttpRequest: open() - resolving URLs (javascript: <iframe>; 2)]
expected: FAIL