diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index d638ad582b4..2a512d84060 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -5,7 +5,6 @@
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;
@@ -35,7 +34,6 @@ use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkEr
use network_listener::{NetworkListener, PreInvoke};
use std::ascii::AsciiExt;
use std::cell::Cell;
-use std::mem;
use std::sync::{Arc, Mutex};
use string_cache::Atom;
use style::str::{HTML_SPACE_CHARACTERS, StaticStringVec};
@@ -64,10 +62,6 @@ pub struct HTMLScriptElement {
/// The source this script was loaded from
load: DOMRefCell>,
-
- #[ignore_heap_size_of = "Defined in rust-encoding"]
- /// https://html.spec.whatwg.org/multipage/#concept-script-encoding
- block_character_encoding: Cell >,
}
impl HTMLScriptElement {
@@ -82,7 +76,6 @@ impl HTMLScriptElement {
ready_to_be_parser_executed: Cell::new(false),
parser_document: JS::from_ref(document),
load: DOMRefCell::new(None),
- block_character_encoding: Cell::new(None),
}
}
@@ -120,13 +113,16 @@ static SCRIPT_JS_MIMES: StaticStringVec = &[
#[derive(HeapSizeOf, JSTraceable)]
pub enum ScriptOrigin {
Internal(DOMString, Url),
- External(Result<(Metadata, Vec), NetworkError>),
+ External(Result<(String, Url), NetworkError>),
}
/// The context required for asynchronously loading an external script source.
struct ScriptContext {
/// The element that initiated the request.
elem: Trusted,
+ /// The (fallback) character encoding argument to the "fetch a classic
+ /// script" algorithm.
+ character_encoding: EncodingRef,
/// The response body received to date.
data: Vec,
/// The response metadata received to date.
@@ -162,14 +158,27 @@ impl AsyncResponseListener for ScriptContext {
}
}
+ /// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script
+ /// step 4-9
fn response_complete(&mut self, status: Result<(), NetworkError>) {
+ // Step 5.
let load = status.and(self.status.clone()).map(|_| {
- let data = mem::replace(&mut self.data, vec!());
let metadata = self.metadata.take().unwrap();
- (metadata, data)
+
+ // Step 6.
+ let encoding = metadata.charset
+ .and_then(|encoding| encoding_from_whatwg_label(&encoding))
+ .unwrap_or(self.character_encoding);
+
+ // Step 7.
+ let source_text = encoding.decode(&self.data, DecoderTrap::Replace).unwrap();
+ (source_text, metadata.final_url)
});
+
+ // Step 9.
+ // https://html.spec.whatwg.org/multipage/#prepare-a-script
+ // Step 18.6 (When the chosen algorithm asynchronously completes).
let elem = self.elem.root();
- // TODO: maybe set this to None again after script execution to save memory.
*elem.load.borrow_mut() = Some(ScriptOrigin::External(load));
elem.ready_to_be_parser_executed.set(true);
@@ -180,6 +189,38 @@ impl AsyncResponseListener for ScriptContext {
impl PreInvoke for ScriptContext {}
+/// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script
+fn fetch_a_classic_script(script: &HTMLScriptElement,
+ url: Url,
+ character_encoding: EncodingRef) {
+ // TODO(#9186): use the fetch infrastructure.
+ let context = Arc::new(Mutex::new(ScriptContext {
+ elem: Trusted::new(script),
+ character_encoding: character_encoding,
+ data: vec!(),
+ metadata: None,
+ url: url.clone(),
+ status: Ok(())
+ }));
+
+ let doc = document_from_node(script);
+
+ let (action_sender, action_receiver) = ipc::channel().unwrap();
+ let listener = NetworkListener {
+ context: context,
+ 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);
+}
+
impl HTMLScriptElement {
/// https://html.spec.whatwg.org/multipage/#prepare-a-script
pub fn prepare(&self) -> NextParserState {
@@ -227,13 +268,12 @@ impl HTMLScriptElement {
// Step 9.
let doc = document_from_node(self);
- let document_from_node_ref = doc.r();
- if self.parser_inserted.get() && &*self.parser_document != document_from_node_ref {
+ if self.parser_inserted.get() && &*self.parser_document != &*doc {
return NextParserState::Continue;
}
// Step 10.
- if !document_from_node_ref.is_scripting_enabled() {
+ if !doc.is_scripting_enabled() {
return NextParserState::Continue;
}
@@ -260,30 +300,32 @@ impl HTMLScriptElement {
}
// Step 13.
- if let Some(ref charset) = element.get_attribute(&ns!(), &atom!("charset")) {
- if let Some(encodingRef) = encoding_from_whatwg_label(&charset.Value()) {
- self.block_character_encoding.set(Some(encodingRef));
- }
- }
+ let encoding = element.get_attribute(&ns!(), &atom!("charset"))
+ .and_then(|charset| encoding_from_whatwg_label(&charset.value()))
+ .unwrap_or_else(|| doc.encoding());
// TODO: Step 14: CORS.
- // TODO: Step 15: environment settings object.
+ // TODO: Step 15: Nonce.
+
+ // TODO: Step 16: Parser state.
+
+ // TODO: Step 17: environment settings object.
let base_url = doc.base_url();
let is_external = match element.get_attribute(&ns!(), &atom!("src")) {
- // Step 16.
+ // Step 18.
Some(ref src) => {
- // Step 16.1.
+ // Step 18.1.
let src = src.value();
- // Step 16.2.
+ // Step 18.2.
if src.is_empty() {
self.queue_error_event();
return NextParserState::Continue;
}
- // Step 16.4-16.5.
+ // Step 18.4-18.5.
let url = match base_url.join(&src) {
Err(_) => {
error!("error parsing URL for script {}", &**src);
@@ -293,40 +335,16 @@ impl HTMLScriptElement {
Ok(url) => url,
};
- // Step 16.6.
- // TODO(#9186): use the fetch infrastructure.
- let elem = Trusted::new(self);
-
- let context = Arc::new(Mutex::new(ScriptContext {
- elem: elem,
- data: vec!(),
- metadata: None,
- url: url.clone(),
- status: Ok(())
- }));
-
- let (action_sender, action_receiver) = ipc::channel().unwrap();
- let listener = NetworkListener {
- context: context,
- 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);
+ // Step 18.6.
+ fetch_a_classic_script(self, url, encoding);
true
},
None => false,
};
- // Step 18.
+ // Step 20.
let deferred = element.has_attribute(&atom!("defer"));
- // Step 18.a: has src, has defer, was parser-inserted, is not async.
+ // Step 20.a: classic, has src, has defer, was parser-inserted, is not async.
if is_external &&
deferred &&
was_parser_inserted &&
@@ -334,23 +352,23 @@ impl HTMLScriptElement {
doc.add_deferred_script(self);
// Second part implemented in Document::process_deferred_scripts.
return NextParserState::Continue;
- // Step 18.b: has src, was parser-inserted, is not async.
+ // Step 20.b: classic, has src, was parser-inserted, is not async.
} else if is_external &&
was_parser_inserted &&
!async {
doc.set_pending_parsing_blocking_script(Some(self));
// Second part implemented in the load result handler.
- // Step 18.c: has src, isn't async, isn't non-blocking.
+ // Step 20.c: classic, has src, isn't async, isn't non-blocking.
} else if is_external &&
!async &&
!self.non_blocking.get() {
doc.push_asap_in_order_script(self);
// Second part implemented in Document::process_asap_scripts.
- // Step 18.d: has src.
+ // Step 20.d: classic, has src.
} else if is_external {
doc.add_asap_script(self);
// Second part implemented in Document::process_asap_scripts.
- // Step 18.e: doesn't have src, was parser-inserted, is blocked on stylesheet.
+ // Step 20.e: doesn't have src, was parser-inserted, is blocked on stylesheet.
} else if !is_external &&
was_parser_inserted &&
// TODO: check for script nesting levels.
@@ -358,7 +376,7 @@ impl HTMLScriptElement {
doc.set_pending_parsing_blocking_script(Some(self));
*self.load.borrow_mut() = Some(ScriptOrigin::Internal(text, base_url));
self.ready_to_be_parser_executed.set(true);
- // Step 18.f: otherwise.
+ // Step 20.f: otherwise.
} else {
assert!(!text.is_empty());
self.ready_to_be_parser_executed.set(true);
@@ -402,17 +420,9 @@ impl HTMLScriptElement {
}
// Step 2.b.1.a.
- ScriptOrigin::External(Ok((metadata, bytes))) => {
- debug!("loading external script, url = {}", metadata.final_url);
-
- let encoding = metadata.charset
- .and_then(|encoding| encoding_from_whatwg_label(&encoding))
- .or_else(|| self.block_character_encoding.get())
- .unwrap_or_else(|| self.parser_document.encoding());
-
- (DOMString::from(encoding.decode(&*bytes, DecoderTrap::Replace).unwrap()),
- true,
- metadata.final_url)
+ ScriptOrigin::External(Ok((text, url))) => {
+ debug!("loading external script, url = {}", url);
+ (DOMString::from(text), true, url)
},
// Step 2.b.1.c.
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json
index 399c880f2ea..cb936f17478 100644
--- a/tests/wpt/metadata/MANIFEST.json
+++ b/tests/wpt/metadata/MANIFEST.json
@@ -37203,7 +37203,16 @@
"local_changes": {
"deleted": [],
"deleted_reftests": {},
- "items": {},
+ "items": {
+ "testharness": {
+ "html/semantics/scripting-1/the-script-element/script-charset-03.html": [
+ {
+ "path": "html/semantics/scripting-1/the-script-element/script-charset-03.html",
+ "url": "/html/semantics/scripting-1/the-script-element/script-charset-03.html"
+ }
+ ]
+ }
+ },
"reftest_nodes": {}
},
"reftest_nodes": {
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-charset-03.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-charset-03.html
new file mode 100644
index 00000000000..4ff4cc6b0ba
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/script-charset-03.html
@@ -0,0 +1,20 @@
+
+
+
+Script changing @charset
+
+
+
+
+