Auto merge of #12472 - KiChjang:use-fetch-in-script, r=jdm

Use fetch infrastructure to load external scripts

Fixes  #9186.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12472)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-09-21 18:49:33 -05:00 committed by GitHub
commit f357afc94a
15 changed files with 364 additions and 353 deletions

View file

@ -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();

View file

@ -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

View file

@ -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()
}

View file

@ -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()));
};
if self.is_network_error() {
return Err(NetworkError::Internal("Cannot extract metadata from network error".to_string()));
}
metadata.set_content_type(match self.headers.get() {
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(self.headers.clone()));
metadata.status = self.raw_status.clone();
metadata.https_state = self.https_state;
return Ok(metadata);
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_owned()));
}
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()))
}
}
}

View file

@ -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);

View file

@ -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.

View file

@ -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());
});
doc.load_async(LoadType::Script(url), response_target, None);
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
listener.notify_fetch(message.to().unwrap());
});
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())

View file

@ -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;

View file

@ -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;
@ -222,21 +222,25 @@ impl XMLHttpRequest {
fn process_request_body(&mut self) {
// todo
}
fn process_request_eof(&mut self) {
// todo
}
fn process_response(&mut self, metadata: Result<Metadata, NetworkError>) {
fn process_response(&mut self,
metadata: Result<FetchMetadata, NetworkError>) {
let xhr = self.xhr.root();
let rv = xhr.process_headers_available(self.gen_id,
metadata);
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(()) => {
@ -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);

View file

@ -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"
}
]
}
},

View file

@ -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

View file

@ -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

View file

@ -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;"

View file

@ -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>

View file

@ -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>