diff options
-rw-r--r-- | components/net/fetch/methods.rs | 12 | ||||
-rw-r--r-- | components/net_traits/lib.rs | 26 | ||||
-rw-r--r-- | components/net_traits/request.rs | 81 | ||||
-rw-r--r-- | components/net_traits/response.rs | 48 | ||||
-rw-r--r-- | components/script/document_loader.rs | 17 | ||||
-rw-r--r-- | components/script/dom/document.rs | 13 | ||||
-rw-r--r-- | components/script/dom/htmlscriptelement.rs | 106 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLScriptElement.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/xmlhttprequest.rs | 75 | ||||
-rw-r--r-- | tests/wpt/metadata/MANIFEST.json | 12 | ||||
-rw-r--r-- | tests/wpt/metadata/html/dom/interfaces.html.ini | 6 | ||||
-rw-r--r-- | tests/wpt/metadata/html/dom/reflection-misc.html.ini | 219 | ||||
-rw-r--r-- | tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/resources/cross-origin.py | 10 | ||||
-rw-r--r-- | tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-crossorigin-network.html | 49 | ||||
-rw-r--r-- | tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-crossorigin.html | 39 |
15 files changed, 363 insertions, 352 deletions
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs index dd35ce06656..1f3eb0e5a24 100644 --- a/components/net/fetch/methods.rs +++ b/components/net/fetch/methods.rs @@ -22,7 +22,7 @@ use hyper::status::StatusCode; use hyper_serde::Serde; use mime_guess::guess_mime_type; use msg::constellation_msg::ReferrerPolicy; -use net_traits::FetchTaskTarget; +use net_traits::{FetchTaskTarget, FetchMetadata}; use net_traits::request::{CacheMode, CredentialsMode, Destination}; use net_traits::request::{RedirectMode, Referrer, Request, RequestMode, ResponseTainting}; use net_traits::request::{Type, Origin, Window}; @@ -361,13 +361,14 @@ fn main_fetch(request: Rc<Request>, cache: &mut CORSCache, cors_flag: bool, } } } else if let Some(ref mut target) = *target { - if let ResponseBody::Done(ref vec) = *response.body.lock().unwrap() { + let body = response.body.lock().unwrap(); + if let ResponseBody::Done(ref vec) = *body { // in case there was no channel to wait for, the body was // obtained synchronously via basic_fetch for data/file/about/etc // We should still send the body across as a chunk target.process_response_chunk(vec.clone()); } else { - assert!(*response.body.lock().unwrap() == ResponseBody::Empty) + assert!(*body == ResponseBody::Empty) } } @@ -981,7 +982,10 @@ fn http_network_fetch(request: Rc<Request>, // We're about to spawn a thread to be waited on here *done_chan = Some(channel()); - let meta = response.metadata().expect("Response metadata should exist at this stage"); + let meta = match response.metadata().expect("Response metadata should exist at this stage") { + FetchMetadata::Unfiltered(m) => m, + FetchMetadata::Filtered { unsafe_, .. } => unsafe_ + }; let done_sender = done_chan.as_ref().map(|ch| ch.0.clone()); let devtools_sender = devtools_chan.clone(); let meta_status = meta.status.clone(); diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index 036fb54d940..2cbc198e0f7 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -170,7 +170,7 @@ pub enum FetchResponseMsg { ProcessRequestBody, ProcessRequestEOF, // todo: send more info about the response (or perhaps the entire Response) - ProcessResponse(Result<Metadata, NetworkError>), + ProcessResponse(Result<FetchMetadata, NetworkError>), ProcessResponseChunk(Vec<u8>), ProcessResponseEOF(Result<(), NetworkError>), } @@ -200,10 +200,25 @@ pub trait FetchTaskTarget { fn process_response_eof(&mut self, response: &Response); } +#[derive(Serialize, Deserialize)] +pub enum FilteredMetadata { + Opaque, + Transparent(Metadata) +} + +#[derive(Serialize, Deserialize)] +pub enum FetchMetadata { + Unfiltered(Metadata), + Filtered { + filtered: FilteredMetadata, + unsafe_: Metadata + } +} + pub trait FetchResponseListener { fn process_request_body(&mut self); fn process_request_eof(&mut self); - fn process_response(&mut self, metadata: Result<Metadata, NetworkError>); + fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>); fn process_response_chunk(&mut self, chunk: Vec<u8>); fn process_response_eof(&mut self, response: Result<(), NetworkError>); } @@ -520,6 +535,13 @@ impl PendingAsyncLoad { let consumer = LoadConsumer::Listener(listener); self.core_resource_thread.send(CoreResourceMsg::Load(load_data, consumer, None)).unwrap(); } + + /// Initiate the fetch associated with this pending load. + pub fn fetch_async(mut self, request: RequestInit, fetch_target: IpcSender<FetchResponseMsg>) { + self.guard.neuter(); + + self.core_resource_thread.send(CoreResourceMsg::Fetch(request, fetch_target)).unwrap(); + } } /// Message sent in response to `Load`. Contains metadata, and a port diff --git a/components/net_traits/request.rs b/components/net_traits/request.rs index 1ed8950bf2d..c31f821680d 100644 --- a/components/net_traits/request.rs +++ b/components/net_traits/request.rs @@ -6,6 +6,7 @@ use hyper::header::Headers; use hyper::method::Method; use msg::constellation_msg::{PipelineId, ReferrerPolicy}; use std::cell::{Cell, RefCell}; +use std::default::Default; use std::mem::swap; use url::{Origin as UrlOrigin, Url}; @@ -20,7 +21,7 @@ pub enum Initiator { } /// A request [type](https://fetch.spec.whatwg.org/#concept-request-type) -#[derive(Copy, Clone, PartialEq, HeapSizeOf)] +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)] pub enum Type { None, Audio, Font, Image, Script, Style, Track, Video @@ -103,7 +104,7 @@ pub enum Window { } /// [CORS settings attribute](https://html.spec.whatwg.org/multipage/#attr-crossorigin-anonymous) -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum CORSSettings { Anonymous, UseCredentials @@ -122,6 +123,7 @@ pub struct RequestInit { pub same_origin_data: bool, pub body: Option<Vec<u8>>, // TODO: client object + pub type_: Type, pub destination: Destination, pub synchronous: bool, pub mode: RequestMode, @@ -137,6 +139,30 @@ pub struct RequestInit { pub pipeline_id: Option<PipelineId>, } +impl Default for RequestInit { + fn default() -> RequestInit { + RequestInit { + method: Method::Get, + url: Url::parse("about:blank").unwrap(), + headers: Headers::new(), + unsafe_request: false, + same_origin_data: false, + body: None, + type_: Type::None, + destination: Destination::None, + synchronous: false, + mode: RequestMode::NoCORS, + use_cors_preflight: false, + credentials_mode: CredentialsMode::Omit, + use_url_credentials: false, + origin: Url::parse("about:blank").unwrap(), + referrer_url: None, + referrer_policy: None, + pipeline_id: None, + } + } +} + /// A [Request](https://fetch.spec.whatwg.org/#requests) as defined by the Fetch spec #[derive(Clone, HeapSizeOf)] pub struct Request { @@ -232,6 +258,7 @@ impl Request { req.unsafe_request = init.unsafe_request; req.same_origin_data.set(init.same_origin_data); *req.body.borrow_mut() = init.body; + req.type_ = init.type_; req.destination = init.destination; req.synchronous = init.synchronous; req.mode = init.mode; @@ -248,56 +275,6 @@ impl Request { req } - /// https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request - pub fn potential_cors_request(url: Url, - cors_attribute_state: Option<CORSSettings>, - is_service_worker_global_scope: bool, - same_origin_fallback: bool, - pipeline_id: Option<PipelineId>) -> Request { - Request { - method: RefCell::new(Method::Get), - local_urls_only: false, - sandboxed_storage_area_urls: false, - headers: RefCell::new(Headers::new()), - unsafe_request: false, - body: RefCell::new(None), - is_service_worker_global_scope: is_service_worker_global_scope, - window: Cell::new(Window::Client), - keep_alive: Cell::new(false), - skip_service_worker: Cell::new(false), - initiator: Initiator::None, - type_: Type::None, - destination: Destination::None, - origin: RefCell::new(Origin::Client), - omit_origin_header: Cell::new(false), - same_origin_data: Cell::new(false), - referrer: RefCell::new(Referrer::Client), - referrer_policy: Cell::new(None), - synchronous: false, - // Step 1-2 - mode: match cors_attribute_state { - Some(_) => RequestMode::CORSMode, - None if same_origin_fallback => RequestMode::SameOrigin, - None => RequestMode::NoCORS - }, - use_cors_preflight: false, - // Step 3-4 - credentials_mode: match cors_attribute_state { - Some(CORSSettings::Anonymous) => CredentialsMode::CredentialsSameOrigin, - _ => CredentialsMode::Include, - }, - use_url_credentials: true, - cache_mode: Cell::new(CacheMode::Default), - redirect_mode: Cell::new(RedirectMode::Follow), - integrity_metadata: RefCell::new(String::new()), - url_list: RefCell::new(vec![url]), - redirect_count: Cell::new(0), - response_tainting: Cell::new(ResponseTainting::Basic), - pipeline_id: Cell::new(pipeline_id), - done: Cell::new(false) - } - } - pub fn url(&self) -> Url { self.url_list.borrow().first().unwrap().clone() } diff --git a/components/net_traits/response.rs b/components/net_traits/response.rs index 823c56c7002..c4b4a3fe8e3 100644 --- a/components/net_traits/response.rs +++ b/components/net_traits/response.rs @@ -4,7 +4,7 @@ //! The [Response](https://fetch.spec.whatwg.org/#responses) object //! resulting from a [fetch operation](https://fetch.spec.whatwg.org/#concept-fetch) -use {Metadata, NetworkError}; +use {FetchMetadata, FilteredMetadata, Metadata, NetworkError}; use hyper::header::{AccessControlExposeHeaders, ContentType, Headers}; use hyper::status::StatusCode; use hyper_serde::Serde; @@ -225,24 +225,42 @@ impl Response { response } - pub fn metadata(&self) -> Result<Metadata, NetworkError> { - let mut metadata = if let Some(ref url) = self.url { - Metadata::default(url.clone()) - } else { - return Err(NetworkError::Internal("No url found in response".to_string())); + pub fn metadata(&self) -> Result<FetchMetadata, NetworkError> { + fn init_metadata(response: &Response, url: &Url) -> Metadata { + let mut metadata = Metadata::default(url.clone()); + metadata.set_content_type(match response.headers.get() { + Some(&ContentType(ref mime)) => Some(mime), + None => None + }); + metadata.headers = Some(Serde(response.headers.clone())); + metadata.status = response.raw_status.clone(); + metadata.https_state = response.https_state; + metadata }; if self.is_network_error() { - return Err(NetworkError::Internal("Cannot extract metadata from network error".to_string())); + return Err(NetworkError::Internal("Cannot extract metadata from network error".to_owned())); } - metadata.set_content_type(match self.headers.get() { - Some(&ContentType(ref mime)) => Some(mime), - None => None - }); - metadata.headers = Some(Serde(self.headers.clone())); - metadata.status = self.raw_status.clone(); - metadata.https_state = self.https_state; - return Ok(metadata); + let metadata = self.url.as_ref().map(|url| init_metadata(self, url)); + + if let Some(ref response) = self.internal_response { + match response.url { + Some(ref url) => { + let unsafe_metadata = init_metadata(response, url); + + Ok(FetchMetadata::Filtered { + filtered: match metadata { + Some(m) => FilteredMetadata::Transparent(m), + None => FilteredMetadata::Opaque + }, + unsafe_: unsafe_metadata + }) + } + None => Err(NetworkError::Internal("No url found in unsafe response".to_owned())) + } + } else { + Ok(FetchMetadata::Unfiltered(metadata.unwrap())) + } } } diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs index 0fc1e5e06c5..5209b68b9ac 100644 --- a/components/script/document_loader.rs +++ b/components/script/document_loader.rs @@ -7,9 +7,11 @@ use dom::bindings::js::JS; use dom::document::Document; +use ipc_channel::ipc::IpcSender; use msg::constellation_msg::{PipelineId, ReferrerPolicy}; -use net_traits::{PendingAsyncLoad, AsyncResponseTarget, LoadContext}; -use net_traits::{ResourceThreads, IpcSend}; +use net_traits::{AsyncResponseTarget, PendingAsyncLoad, LoadContext}; +use net_traits::{FetchResponseMsg, ResourceThreads, IpcSend}; +use net_traits::request::RequestInit; use std::thread; use url::Url; @@ -148,6 +150,17 @@ impl DocumentLoader { pending.load_async(listener) } + /// Initiate a new fetch. + pub fn fetch_async(&mut self, + load: LoadType, + request: RequestInit, + fetch_target: IpcSender<FetchResponseMsg>, + referrer: &Document, + referrer_policy: Option<ReferrerPolicy>) { + let pending = self.prepare_async_load(load, referrer, referrer_policy); + pending.fetch_async(request, fetch_target); + } + /// Mark an in-progress network request complete. pub fn finish_load(&mut self, load: &LoadType) { let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == *load); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 15cb50aa466..2cca84a625a 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -95,9 +95,10 @@ use js::jsapi::JS_GetRuntime; use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use msg::constellation_msg::{PipelineId, ReferrerPolicy}; -use net_traits::{AsyncResponseTarget, IpcSend, PendingAsyncLoad}; +use net_traits::{AsyncResponseTarget, FetchResponseMsg, IpcSend, PendingAsyncLoad}; use net_traits::CookieSource::NonHTTP; use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl}; +use net_traits::request::RequestInit; use net_traits::response::HttpsState; use num_traits::ToPrimitive; use origin::Origin; @@ -1433,6 +1434,14 @@ impl Document { loader.load_async(load, listener, self, referrer_policy); } + pub fn fetch_async(&self, load: LoadType, + request: RequestInit, + fetch_target: IpcSender<FetchResponseMsg>, + referrer_policy: Option<ReferrerPolicy>) { + let mut loader = self.loader.borrow_mut(); + loader.fetch_async(load, request, fetch_target, self, referrer_policy); + } + pub fn finish_load(&self, load: LoadType) { debug!("Document got finish_load: {:?}", load); // The parser might need the loader, so restrict the lifetime of the borrow. @@ -1520,7 +1529,7 @@ impl Document { } /// https://html.spec.whatwg.org/multipage/#the-end step 5 and the latter parts of - /// https://html.spec.whatwg.org/multipage/#prepare-a-script 15.d and 15.e. + /// https://html.spec.whatwg.org/multipage/#prepare-a-script 20.d and 20.e. pub fn process_asap_scripts(&self) { // Execute the first in-order asap-executed script if it's ready, repeat as required. // Re-borrowing the list for each step because it can also be borrowed under execute. diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 11f4451ad50..566b69967d4 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -5,6 +5,7 @@ use document_loader::LoadType; use dom::attr::Attr; use dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::HTMLScriptElementBinding; use dom::bindings::codegen::Bindings::HTMLScriptElementBinding::HTMLScriptElementMethods; @@ -14,6 +15,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, Root}; use dom::bindings::js::RootedReference; use dom::bindings::refcounted::Trusted; +use dom::bindings::reflector::Reflectable; use dom::bindings::str::DOMString; use dom::document::Document; use dom::element::{AttributeMutation, Element, ElementCreator}; @@ -29,7 +31,8 @@ use html5ever::tree_builder::NextParserState; use ipc_channel::ipc; use ipc_channel::router::ROUTER; use js::jsval::UndefinedValue; -use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkError}; +use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError}; +use net_traits::request::{CORSSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType}; use network_listener::{NetworkListener, PreInvoke}; use std::ascii::AsciiExt; use std::cell::Cell; @@ -151,9 +154,17 @@ struct ScriptContext { status: Result<(), NetworkError> } -impl AsyncResponseListener for ScriptContext { - fn headers_available(&mut self, metadata: Result<Metadata, NetworkError>) { - self.metadata = metadata.ok(); +impl FetchResponseListener for ScriptContext { + fn process_request_body(&mut self) {} // TODO(KiChjang): Perhaps add custom steps to perform fetch here? + + fn process_request_eof(&mut self) {} // TODO(KiChjang): Perhaps add custom steps to perform fetch here? + + fn process_response(&mut self, + metadata: Result<FetchMetadata, NetworkError>) { + self.metadata = metadata.ok().map(|meta| match meta { + FetchMetadata::Unfiltered(m) => m, + FetchMetadata::Filtered { unsafe_, .. } => unsafe_ + }); let status_code = self.metadata.as_ref().and_then(|m| { match m.status { @@ -169,18 +180,17 @@ impl AsyncResponseListener for ScriptContext { }; } - fn data_available(&mut self, payload: Vec<u8>) { + fn process_response_chunk(&mut self, mut chunk: Vec<u8>) { if self.status.is_ok() { - let mut payload = payload; - self.data.append(&mut payload); + self.data.append(&mut chunk); } } /// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script /// step 4-9 - fn response_complete(&mut self, status: Result<(), NetworkError>) { + fn process_response_eof(&mut self, response: Result<(), NetworkError>) { // Step 5. - let load = status.and(self.status.clone()).map(|_| { + let load = response.and(self.status.clone()).map(|_| { let metadata = self.metadata.take().unwrap(); // Step 6. @@ -210,8 +220,38 @@ impl PreInvoke for ScriptContext {} /// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script fn fetch_a_classic_script(script: &HTMLScriptElement, url: Url, + cors_setting: Option<CORSSettings>, character_encoding: EncodingRef) { - // TODO(#9186): use the fetch infrastructure. + let doc = document_from_node(script); + + // Step 1, 2. + let request = RequestInit { + url: url.clone(), + type_: RequestType::Script, + destination: Destination::Script, + // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request + // Step 1 + mode: match cors_setting { + Some(_) => RequestMode::CORSMode, + None => RequestMode::NoCORS, + }, + // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request + // Step 3-4 + credentials_mode: match cors_setting { + Some(CORSSettings::Anonymous) => CredentialsMode::CredentialsSameOrigin, + _ => CredentialsMode::Include, + }, + origin: doc.url().clone(), + pipeline_id: Some(script.global().r().pipeline_id()), + // FIXME: Set to true for now, discussion in https://github.com/whatwg/fetch/issues/381 + same_origin_data: true, + referrer_url: Some(doc.url().clone()), + referrer_policy: doc.get_referrer_policy(), + .. RequestInit::default() + }; + + // TODO: Step 3, Add custom steps to perform fetch + let context = Arc::new(Mutex::new(ScriptContext { elem: Trusted::new(script), character_encoding: character_encoding, @@ -229,14 +269,11 @@ fn fetch_a_classic_script(script: &HTMLScriptElement, script_chan: doc.window().networking_task_source(), wrapper: Some(doc.window().get_runnable_wrapper()), }; - let response_target = AsyncResponseTarget { - sender: action_sender, - }; + ROUTER.add_route(action_receiver.to_opaque(), box move |message| { - listener.notify_action(message.to().unwrap()); + listener.notify_fetch(message.to().unwrap()); }); - - doc.load_async(LoadType::Script(url), response_target, None); + doc.fetch_async(LoadType::Script(url), request, action_sender, None); } impl HTMLScriptElement { @@ -322,7 +359,13 @@ impl HTMLScriptElement { .and_then(|charset| encoding_from_whatwg_label(&charset.value())) .unwrap_or_else(|| doc.encoding()); - // TODO: Step 14: CORS. + // Step 14. + let cors_setting = match self.GetCrossOrigin() { + Some(ref s) if *s == "anonymous" => Some(CORSSettings::Anonymous), + Some(ref s) if *s == "use-credentials" => Some(CORSSettings::UseCredentials), + None => None, + _ => unreachable!() + }; // TODO: Step 15: Nonce. @@ -354,10 +397,11 @@ impl HTMLScriptElement { }; // Step 18.6. - fetch_a_classic_script(self, url, encoding); + fetch_a_classic_script(self, url, cors_setting, encoding); true }, + // TODO: Step 19. None => false, }; @@ -652,6 +696,32 @@ impl HTMLScriptElementMethods for HTMLScriptElement { // https://html.spec.whatwg.org/multipage/#dom-script-htmlfor make_setter!(SetHtmlFor, "for"); + // https://html.spec.whatwg.org/multipage/#dom-script-crossorigin + fn GetCrossOrigin(&self) -> Option<DOMString> { + let element = self.upcast::<Element>(); + let attr = element.get_attribute(&ns!(), &atom!("crossorigin")); + + if let Some(mut val) = attr.map(|v| v.Value()) { + val.make_ascii_lowercase(); + if val == "anonymous" || val == "use-credentials" { + return Some(val); + } + return Some(DOMString::from("anonymous")); + } + None + } + + // https://html.spec.whatwg.org/multipage/#dom-script-crossorigin + fn SetCrossOrigin(&self, value: Option<DOMString>) { + let element = self.upcast::<Element>(); + match value { + Some(val) => element.set_string_attribute(&atom!("crossorigin"), val), + None => { + element.remove_attribute(&ns!(), &atom!("crossorigin")); + } + } + } + // https://html.spec.whatwg.org/multipage/#dom-script-text fn Text(&self) -> DOMString { Node::collect_text_contents(self.upcast::<Node>().children()) diff --git a/components/script/dom/webidls/HTMLScriptElement.webidl b/components/script/dom/webidls/HTMLScriptElement.webidl index 17df2e7e08b..1636df7a12b 100644 --- a/components/script/dom/webidls/HTMLScriptElement.webidl +++ b/components/script/dom/webidls/HTMLScriptElement.webidl @@ -10,7 +10,7 @@ interface HTMLScriptElement : HTMLElement { attribute DOMString charset; // attribute boolean async; attribute boolean defer; - // attribute DOMString crossOrigin; + attribute DOMString? crossOrigin; [Pure] attribute DOMString text; diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index d034b60aebd..24ee2c28d36 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -45,8 +45,8 @@ use js::jsapi::{JSContext, JS_ParseJSON}; use js::jsapi::JS_ClearPendingException; use js::jsval::{JSVal, NullValue, UndefinedValue}; use msg::constellation_msg::{PipelineId, ReferrerPolicy}; -use net_traits::{CoreResourceThread, LoadOrigin}; -use net_traits::{FetchResponseListener, Metadata, NetworkError}; +use net_traits::{CoreResourceThread, FetchMetadata, FilteredMetadata}; +use net_traits::{FetchResponseListener, LoadOrigin, NetworkError}; use net_traits::CoreResourceMsg::Fetch; use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode}; use net_traits::trim_http_whitespace; @@ -219,35 +219,39 @@ impl XMLHttpRequest { core_resource_thread: CoreResourceThread, init: RequestInit) { impl FetchResponseListener for XHRContext { - fn process_request_body(&mut self) { - // todo - } - fn process_request_eof(&mut self) { - // todo - } - fn process_response(&mut self, metadata: Result<Metadata, NetworkError>) { - let xhr = self.xhr.root(); - let rv = xhr.process_headers_available(self.gen_id, - metadata); - if rv.is_err() { - *self.sync_status.borrow_mut() = Some(rv); - } - } - fn process_response_chunk(&mut self, mut chunk: Vec<u8>) { - self.buf.borrow_mut().append(&mut chunk); - self.xhr.root().process_data_available(self.gen_id, self.buf.borrow().clone()); - } - fn process_response_eof(&mut self, response: Result<(), NetworkError>) { - let rv = match response { - Ok(()) => { - self.xhr.root().process_response_complete(self.gen_id, Ok(())) - } - Err(e) => { - self.xhr.root().process_response_complete(self.gen_id, Err(e)) - } - }; + fn process_request_body(&mut self) { + // todo + } + + fn process_request_eof(&mut self) { + // todo + } + + fn process_response(&mut self, + metadata: Result<FetchMetadata, NetworkError>) { + let xhr = self.xhr.root(); + let rv = xhr.process_headers_available(self.gen_id, metadata); + if rv.is_err() { *self.sync_status.borrow_mut() = Some(rv); } + } + + fn process_response_chunk(&mut self, mut chunk: Vec<u8>) { + self.buf.borrow_mut().append(&mut chunk); + self.xhr.root().process_data_available(self.gen_id, self.buf.borrow().clone()); + } + + fn process_response_eof(&mut self, response: Result<(), NetworkError>) { + let rv = match response { + Ok(()) => { + self.xhr.root().process_response_complete(self.gen_id, Ok(())) + } + Err(e) => { + self.xhr.root().process_response_complete(self.gen_id, Err(e)) + } + }; + *self.sync_status.borrow_mut() = Some(rv); + } } impl PreInvoke for XHRContext { @@ -273,9 +277,11 @@ impl LoadOrigin for XMLHttpRequest { fn referrer_url(&self) -> Option<Url> { return self.referrer_url.clone(); } + fn referrer_policy(&self) -> Option<ReferrerPolicy> { return self.referrer_policy; } + fn pipeline_id(&self) -> Option<PipelineId> { let global = self.global(); Some(global.r().pipeline_id()) @@ -596,6 +602,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { referrer_url: self.referrer_url.clone(), referrer_policy: self.referrer_policy.clone(), pipeline_id: self.pipeline_id(), + .. RequestInit::default() }; if bypass_cross_origin_check { @@ -862,10 +869,16 @@ impl XMLHttpRequest { } fn process_headers_available(&self, - gen_id: GenerationId, metadata: Result<Metadata, NetworkError>) + gen_id: GenerationId, metadata: Result<FetchMetadata, NetworkError>) -> Result<(), Error> { let metadata = match metadata { - Ok(meta) => meta, + Ok(meta) => match meta { + FetchMetadata::Unfiltered(m) => m, + FetchMetadata::Filtered { filtered, .. } => match filtered { + FilteredMetadata::Opaque => return Err(Error::Network), + FilteredMetadata::Transparent(m) => m + } + }, Err(_) => { self.process_partial_response(XHRProgress::Errored(gen_id, Error::Network)); return Err(Error::Network); diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index ad6f50c06f5..93cdc730d5e 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -37505,6 +37505,18 @@ "path": "html/semantics/forms/the-input-element/minlength.html", "url": "/html/semantics/forms/the-input-element/minlength.html" } + ], + "html/semantics/scripting-1/the-script-element/script-crossorigin-network.html": [ + { + "path": "html/semantics/scripting-1/the-script-element/script-crossorigin-network.html", + "url": "/html/semantics/scripting-1/the-script-element/script-crossorigin-network.html" + } + ], + "html/semantics/scripting-1/the-script-element/script-crossorigin.html": [ + { + "path": "html/semantics/scripting-1/the-script-element/script-crossorigin.html", + "url": "/html/semantics/scripting-1/the-script-element/script-crossorigin.html" + } ] } }, diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index 240d96a350b..6600612366f 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -4359,15 +4359,9 @@ [HTMLScriptElement interface: attribute async] expected: FAIL - [HTMLScriptElement interface: attribute crossOrigin] - expected: FAIL - [HTMLScriptElement interface: document.createElement("script") must inherit property "async" with the proper type (3)] expected: FAIL - [HTMLScriptElement interface: document.createElement("script") must inherit property "crossOrigin" with the proper type (5)] - expected: FAIL - [HTMLCanvasElement interface: operation probablySupportsContext(DOMString,any)] expected: FAIL diff --git a/tests/wpt/metadata/html/dom/reflection-misc.html.ini b/tests/wpt/metadata/html/dom/reflection-misc.html.ini index 953d81ccd68..bfe086b35fd 100644 --- a/tests/wpt/metadata/html/dom/reflection-misc.html.ini +++ b/tests/wpt/metadata/html/dom/reflection-misc.html.ini @@ -1317,222 +1317,6 @@ [script.tabIndex: IDL set to -2147483648 followed by getAttribute()] expected: FAIL - [script.crossOrigin: typeof IDL attribute] - expected: FAIL - - [script.crossOrigin: IDL get with DOM attribute unset] - expected: FAIL - - [script.crossOrigin: setAttribute() to "" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo " followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to undefined followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to 7 followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to 1.5 followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to true followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to false followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to object "[object Object\]" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to NaN followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to Infinity followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to -Infinity followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "\\0" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to null followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to object "test-toString" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to object "test-valueOf" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "anonymous" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "xanonymous" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "anonymous\\0" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "nonymous" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "ANONYMOUS" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "use-credentials" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "xuse-credentials" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "use-credentials\\0" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "se-credentials" followed by IDL get] - expected: FAIL - - [script.crossOrigin: setAttribute() to "USE-CREDENTIALS" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo " followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo " followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to undefined followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to undefined followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to 7 followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to 7 followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to 1.5 followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to 1.5 followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to true followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to true followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to false followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to false followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to object "[object Object\]" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to object "[object Object\]" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to NaN followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to NaN followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to Infinity followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to Infinity followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to -Infinity followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to -Infinity followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "\\0" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "\\0" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to object "test-toString" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to object "test-toString" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to object "test-valueOf" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to object "test-valueOf" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "anonymous" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "xanonymous" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "xanonymous" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "anonymous\\0" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "anonymous\\0" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "nonymous" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "nonymous" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "ANONYMOUS" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "ANONYMOUS" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "use-credentials" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "xuse-credentials" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "xuse-credentials" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "use-credentials\\0" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "use-credentials\\0" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "se-credentials" followed by getAttribute()] - expected: FAIL - - [script.crossOrigin: IDL set to "se-credentials" followed by IDL get] - expected: FAIL - - [script.crossOrigin: IDL set to "USE-CREDENTIALS" followed by IDL get] - expected: FAIL - [script.itemScope: typeof IDL attribute] expected: FAIL @@ -12447,6 +12231,3 @@ [dialog.itemId: IDL set to object "test-valueOf" followed by IDL get] expected: FAIL - [script.crossOrigin: IDL set to null followed by getAttribute()] - expected: FAIL - diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/resources/cross-origin.py b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/resources/cross-origin.py new file mode 100644 index 00000000000..f8e05d96627 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/resources/cross-origin.py @@ -0,0 +1,10 @@ +def main(request, response): + headers = [("Content-Type", "text/javascript")] + milk = request.cookies.first("milk", None) + + if milk is None: + return headers, "var included = false;" + elif milk.value == "yes": + return headers, "var included = true;" + + return headers, "var included = false;" diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-crossorigin-network.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-crossorigin-network.html new file mode 100644 index 00000000000..488dd4488a4 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-crossorigin-network.html @@ -0,0 +1,49 @@ +<!doctype html> +<meta charset="utf-8"> +<title>HTMLScriptElement: crossorigin attribute network test</title> +<link rel="author" title="KiChjang" href="mailto:kungfukeith11@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#cors-settings-attribute"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + <script type="text/javascript"> + var test1 = async_test(document.title + "1"); + var test2 = async_test(document.title + "2"); + var test3 = async_test(document.title + "3"); + + var script1 = document.createElement("script"); + script1.src = "resources/cross-origin.py"; + script1.crossOrigin = "use-credentials"; + var script2 = document.createElement("script"); + script2.src = "resources/cross-origin.py"; + script2.crossOrigin = "gibberish"; + var script3 = document.createElement("script"); + script3.src = "resources/cross-origin.py"; + + document.cookie = "milk=yes"; + document.body.appendChild(script1); + script1.onload = function() { + test1.step(function() { + assert_true(included, "credentials should be included in script request"); + test1.done(); + }); + }; + + document.body.appendChild(script2); + script2.onload = function() { + test2.step(function() { + assert_true(included, "invalid values should default to include credentials due to response tainting"); + test2.done(); + }); + }; + + document.body.appendChild(script3); + script3.onload = function() { + test3.step(function() { + assert_true(included, "missing value should default to include credentials"); + test3.done(); + }); + }; + </script> +</body> diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-crossorigin.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-crossorigin.html new file mode 100644 index 00000000000..52857a08ea0 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-crossorigin.html @@ -0,0 +1,39 @@ +<!doctype html> +<meta charset="utf-8"> +<title>HTMLScriptElement: crossOrigin IDL attribute</title> +<link rel="author" title="KiChjang" href="mailto:kungfukeith11@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#cors-settings-attribute"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script id="script1"></script> +<script id="script2" crossorigin=""></script> +<script id="script3" crossorigin="foo"></script> +<script id="script4" crossorigin="anonymous"></script> +<script id="script5" crossorigin="use-credentials"></script> +<script> +test(function() { + var script1 = document.getElementById("script1"); + var script2 = document.getElementById("script2"); + var script3 = document.getElementById("script3"); + var script4 = document.getElementById("script4"); + var script5 = document.getElementById("script5"); + + assert_equals(script1.crossOrigin, null, "Missing value default should be null"); + assert_equals(script2.crossOrigin, "anonymous", "Empty string should map to anonymous"); + assert_equals(script3.crossOrigin, "anonymous", "Invalid value default should be anonymous"); + assert_equals(script4.crossOrigin, "anonymous", "anonymous should be parsed correctly"); + assert_equals(script5.crossOrigin, "use-credentials", "use-credentials should be parsed correctly"); + + script1.crossOrigin = "bar"; + assert_equals(script1.crossOrigin, "anonymous", "Setting to invalid value would default to anonymous"); + + script2.crossOrigin = null; + assert_equals(script2.crossOrigin, null, "Resetting to null should work"); + + script4.crossOrigin = "use-credentials"; + assert_equals(script4.crossOrigin, "use-credentials", "Switching from anonymous to use-credentials should work"); + + script5.crossOrigin = "anonymous"; + assert_equals(script5.crossOrigin, "anonymous", "Switching from use-credentials to anonymous should work"); +}, document.title); +</script> |