Use fetch infrastructure to load external scripts

This commit is contained in:
Keith Yeung 2016-07-03 21:24:53 +08:00
parent d4816762fa
commit 4dcf693a75
2 changed files with 57 additions and 20 deletions

View file

@ -9,9 +9,9 @@ use dom::bindings::js::JS;
use dom::document::Document; use dom::document::Document;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{PipelineId, ReferrerPolicy}; use msg::constellation_msg::{PipelineId, ReferrerPolicy};
use net_traits::request::RequestInit;
use net_traits::{AsyncResponseTarget, PendingAsyncLoad, LoadContext}; use net_traits::{AsyncResponseTarget, PendingAsyncLoad, LoadContext};
use net_traits::{FetchResponseMsg, ResourceThreads, IpcSend}; use net_traits::{FetchResponseMsg, ResourceThreads, IpcSend};
use net_traits::request::RequestInit;
use std::thread; use std::thread;
use url::Url; use url::Url;

View file

@ -15,6 +15,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::js::RootedReference; use dom::bindings::js::RootedReference;
use dom::bindings::refcounted::Trusted; use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::Reflectable;
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::document::Document; use dom::document::Document;
use dom::element::{AttributeMutation, Element, ElementCreator}; use dom::element::{AttributeMutation, Element, ElementCreator};
@ -30,8 +31,8 @@ use html5ever::tree_builder::NextParserState;
use ipc_channel::ipc; use ipc_channel::ipc;
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkError}; use net_traits::{FetchResponseListener, Metadata, NetworkError};
use net_traits::request::CORSSettings; use net_traits::request::{CORSSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType};
use network_listener::{NetworkListener, PreInvoke}; use network_listener::{NetworkListener, PreInvoke};
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::cell::Cell; use std::cell::Cell;
@ -153,8 +154,12 @@ struct ScriptContext {
status: Result<(), NetworkError> status: Result<(), NetworkError>
} }
impl AsyncResponseListener for ScriptContext { impl FetchResponseListener for ScriptContext {
fn headers_available(&mut self, metadata: Result<Metadata, NetworkError>) { 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<Metadata, NetworkError>) {
self.metadata = metadata.ok(); self.metadata = metadata.ok();
let status_code = self.metadata.as_ref().and_then(|m| { let status_code = self.metadata.as_ref().and_then(|m| {
@ -171,18 +176,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() { if self.status.is_ok() {
let mut payload = payload; self.data.append(&mut chunk);
self.data.append(&mut payload);
} }
} }
/// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script /// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script
/// step 4-9 /// step 4-9
fn response_complete(&mut self, status: Result<(), NetworkError>) { fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
// Step 5. // Step 5.
let load = status.and(self.status.clone()).map(|_| { let load = response.and(self.status.clone()).map(|_| {
let metadata = self.metadata.take().unwrap(); let metadata = self.metadata.take().unwrap();
// Step 6. // Step 6.
@ -212,8 +216,38 @@ impl PreInvoke for ScriptContext {}
/// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script /// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script
fn fetch_a_classic_script(script: &HTMLScriptElement, fn fetch_a_classic_script(script: &HTMLScriptElement,
url: Url, url: Url,
cors_setting: Option<CORSSettings>,
character_encoding: EncodingRef) { 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 { let context = Arc::new(Mutex::new(ScriptContext {
elem: Trusted::new(script), elem: Trusted::new(script),
character_encoding: character_encoding, character_encoding: character_encoding,
@ -231,14 +265,11 @@ fn fetch_a_classic_script(script: &HTMLScriptElement,
script_chan: doc.window().networking_task_source(), script_chan: doc.window().networking_task_source(),
wrapper: Some(doc.window().get_runnable_wrapper()), 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 { impl HTMLScriptElement {
@ -324,7 +355,13 @@ impl HTMLScriptElement {
.and_then(|charset| encoding_from_whatwg_label(&charset.value())) .and_then(|charset| encoding_from_whatwg_label(&charset.value()))
.unwrap_or_else(|| doc.encoding()); .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. // TODO: Step 15: Nonce.
@ -356,7 +393,7 @@ impl HTMLScriptElement {
}; };
// Step 18.6. // Step 18.6.
fetch_a_classic_script(self, url, encoding); fetch_a_classic_script(self, url, cors_setting, encoding);
true true
}, },