aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2019-09-06 07:36:26 -0400
committerGitHub <noreply@github.com>2019-09-06 07:36:26 -0400
commit7a67261dce714413e602754895f6715f8a628a8c (patch)
tree483498425971800ab6b638fa457abfa414c2466b /components/script
parente852d02f1c02b42b5eb5b0ee592d5128f1232458 (diff)
parent95ddfb3930debb81653dffcade6c2ea15dd30d9b (diff)
downloadservo-7a67261dce714413e602754895f6715f8a628a8c.tar.gz
servo-7a67261dce714413e602754895f6715f8a628a8c.zip
Auto merge of #24142 - CYBAI:warn-module-script, r=jdm
Show warning when module scripts are ignored The first five commits are `cherry-pick`-ed from the module script PR. I think it might be also good to have this PR first so that reviewers can focus on module script things on that PR! --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #24089 - [x] These changes do not require tests because it just ignored module scripts (or should we turn on module script tests in this PR and update those test expectation to TIMEOUT?) <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- 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/24142) <!-- Reviewable:end -->
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/htmlscriptelement.rs279
1 files changed, 168 insertions, 111 deletions
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index dbfda59db02..7c9e3ebd42d 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -125,35 +125,44 @@ static SCRIPT_JS_MIMES: StaticStringVec = &[
"text/x-javascript",
];
+#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
+pub enum ScriptType {
+ Classic,
+ Module,
+}
+
#[derive(JSTraceable, MallocSizeOf)]
-pub struct ClassicScript {
+pub struct ScriptOrigin {
text: DOMString,
url: ServoUrl,
external: bool,
+ type_: ScriptType,
}
-impl ClassicScript {
- fn internal(text: DOMString, url: ServoUrl) -> ClassicScript {
- ClassicScript {
+impl ScriptOrigin {
+ fn internal(text: DOMString, url: ServoUrl, type_: ScriptType) -> ScriptOrigin {
+ ScriptOrigin {
text: text,
url: url,
external: false,
+ type_,
}
}
- fn external(text: DOMString, url: ServoUrl) -> ClassicScript {
- ClassicScript {
+ fn external(text: DOMString, url: ServoUrl, type_: ScriptType) -> ScriptOrigin {
+ ScriptOrigin {
text: text,
url: url,
external: true,
+ type_,
}
}
}
-pub type ScriptResult = Result<ClassicScript, NetworkError>;
+pub type ScriptResult = Result<ScriptOrigin, NetworkError>;
/// The context required for asynchronously loading an external script source.
-struct ScriptContext {
+struct ClassicContext {
/// The element that initiated the request.
elem: Trusted<HTMLScriptElement>,
/// The kind of external script.
@@ -173,7 +182,7 @@ struct ScriptContext {
resource_timing: ResourceFetchTiming,
}
-impl FetchResponseListener for ScriptContext {
+impl FetchResponseListener for ClassicContext {
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?
@@ -226,7 +235,11 @@ impl FetchResponseListener for ScriptContext {
// Step 7.
let (source_text, _, _) = encoding.decode(&self.data);
- ClassicScript::external(DOMString::from(source_text), metadata.final_url)
+ ScriptOrigin::external(
+ DOMString::from(source_text),
+ metadata.final_url,
+ ScriptType::Classic,
+ )
});
// Step 9.
@@ -260,7 +273,7 @@ impl FetchResponseListener for ScriptContext {
}
}
-impl ResourceTimingListener for ScriptContext {
+impl ResourceTimingListener for ClassicContext {
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
let initiator_type = InitiatorType::LocalName(
self.elem
@@ -277,7 +290,7 @@ impl ResourceTimingListener for ScriptContext {
}
}
-impl PreInvoke for ScriptContext {}
+impl PreInvoke for ClassicContext {}
/// <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script>
fn fetch_a_classic_script(
@@ -313,7 +326,7 @@ fn fetch_a_classic_script(
// TODO: Step 3, Add custom steps to perform fetch
- let context = Arc::new(Mutex::new(ScriptContext {
+ let context = Arc::new(Mutex::new(ClassicContext {
elem: Trusted::new(script),
kind: kind,
character_encoding: character_encoding,
@@ -364,47 +377,49 @@ impl HTMLScriptElement {
self.non_blocking.set(true);
}
- // Step 4.
+ // Step 4-5.
let text = self.Text();
if text.is_empty() && !element.has_attribute(&local_name!("src")) {
return;
}
- // Step 5.
+ // Step 6.
if !self.upcast::<Node>().is_connected() {
return;
}
- // Step 6.
- if !self.is_javascript() {
+ let script_type = if let Some(ty) = self.get_script_type() {
+ ty
+ } else {
+ // Step 7.
return;
- }
+ };
- // Step 7.
+ // Step 8.
if was_parser_inserted {
self.parser_inserted.set(true);
self.non_blocking.set(false);
}
- // Step 8.
+ // Step 9.
self.already_started.set(true);
- // Step 9.
+ // Step 10.
let doc = document_from_node(self);
if self.parser_inserted.get() && &*self.parser_document != &*doc {
return;
}
- // Step 10.
+ // Step 11.
if !doc.is_scripting_enabled() {
return;
}
- // TODO: Step 11: nomodule content attribute
+ // TODO: Step 12: nomodule content attribute
- // TODO(#4577): Step 12: CSP.
+ // TODO(#4577): Step 13: CSP.
- // Step 13.
+ // Step 14.
let for_attribute = element.get_attribute(&ns!(), &local_name!("for"));
let event_attribute = element.get_attribute(&ns!(), &local_name!("event"));
match (for_attribute, event_attribute) {
@@ -424,20 +439,20 @@ impl HTMLScriptElement {
(_, _) => (),
}
- // Step 14.
+ // Step 15.
let encoding = element
.get_attribute(&ns!(), &local_name!("charset"))
.and_then(|charset| Encoding::for_label(charset.value().as_bytes()))
.unwrap_or_else(|| doc.encoding());
- // Step 15.
+ // Step 16.
let cors_setting = cors_setting_for_element(element);
- // TODO: Step 16: Module script credentials mode.
+ // TODO: Step 17: Module script credentials mode.
- // TODO: Step 17: Nonce.
+ // TODO: Step 18: Nonce.
- // Step 18: Integrity metadata.
+ // Step 19: Integrity metadata.
let im_attribute = element.get_attribute(&ns!(), &local_name!("integrity"));
let integrity_val = im_attribute.as_ref().map(|a| a.value());
let integrity_metadata = match integrity_val {
@@ -445,26 +460,30 @@ impl HTMLScriptElement {
None => "",
};
- // TODO: Step 19: parser state.
+ // TODO: Step 20: referrer policy
+
+ // TODO: Step 21: parser state.
+
+ // TODO: Step 22: Fetch options
- // TODO: Step 20: environment settings object.
+ // TODO: Step 23: environment settings object.
let base_url = doc.base_url();
if let Some(src) = element.get_attribute(&ns!(), &local_name!("src")) {
- // Step 21.
+ // Step 24.
- // Step 21.1.
+ // Step 24.1.
let src = src.value();
- // Step 21.2.
+ // Step 24.2.
if src.is_empty() {
self.queue_error_event();
return;
}
- // Step 21.3: The "from an external file"" flag is stored in ClassicScript.
+ // Step 24.3: The "from an external file"" flag is stored in ScriptOrigin.
- // Step 21.4-21.5.
+ // Step 24.4-24.5.
let url = match base_url.join(&src) {
Ok(url) => url,
Err(_) => {
@@ -474,64 +493,89 @@ impl HTMLScriptElement {
},
};
- // Preparation for step 23.
- let kind = if element.has_attribute(&local_name!("defer")) &&
- was_parser_inserted &&
- !r#async
- {
- // Step 23.a: classic, has src, has defer, was parser-inserted, is not async.
- ExternalScriptKind::Deferred
- } else if was_parser_inserted && !r#async {
- // Step 23.c: classic, has src, was parser-inserted, is not async.
- ExternalScriptKind::ParsingBlocking
- } else if !r#async && !self.non_blocking.get() {
- // Step 23.d: classic, has src, is not async, is not non-blocking.
- ExternalScriptKind::AsapInOrder
- } else {
- // Step 23.f: classic, has src.
- ExternalScriptKind::Asap
- };
-
- // Step 21.6.
- fetch_a_classic_script(
- self,
- kind,
- url,
- cors_setting,
- integrity_metadata.to_owned(),
- encoding,
- );
-
- // Step 23.
- match kind {
- ExternalScriptKind::Deferred => doc.add_deferred_script(self),
- ExternalScriptKind::ParsingBlocking => {
- doc.set_pending_parsing_blocking_script(self, None)
+ match script_type {
+ ScriptType::Classic => {
+ // Preparation for step 26.
+ let kind = if element.has_attribute(&local_name!("defer")) &&
+ was_parser_inserted &&
+ !r#async
+ {
+ // Step 26.a: classic, has src, has defer, was parser-inserted, is not async.
+ ExternalScriptKind::Deferred
+ } else if was_parser_inserted && !r#async {
+ // Step 26.c: classic, has src, was parser-inserted, is not async.
+ ExternalScriptKind::ParsingBlocking
+ } else if !r#async && !self.non_blocking.get() {
+ // Step 26.d: classic, has src, is not async, is not non-blocking.
+ ExternalScriptKind::AsapInOrder
+ } else {
+ // Step 26.f: classic, has src.
+ ExternalScriptKind::Asap
+ };
+
+ // Step 24.6.
+ fetch_a_classic_script(
+ self,
+ kind,
+ url,
+ cors_setting,
+ integrity_metadata.to_owned(),
+ encoding,
+ );
+
+ // Step 23.
+ match kind {
+ ExternalScriptKind::Deferred => doc.add_deferred_script(self),
+ ExternalScriptKind::ParsingBlocking => {
+ doc.set_pending_parsing_blocking_script(self, None)
+ },
+ ExternalScriptKind::AsapInOrder => doc.push_asap_in_order_script(self),
+ ExternalScriptKind::Asap => doc.add_asap_script(self),
+ }
+ },
+ ScriptType::Module => {
+ warn!(
+ "{} is a module script. It should be fixed after #23545 landed.",
+ url.clone()
+ );
},
- ExternalScriptKind::AsapInOrder => doc.push_asap_in_order_script(self),
- ExternalScriptKind::Asap => doc.add_asap_script(self),
}
} else {
- // Step 22.
+ // Step 25.
assert!(!text.is_empty());
- let result = Ok(ClassicScript::internal(text, base_url));
- // Step 23.
+ // Step 25-1.
+ let result = Ok(ScriptOrigin::internal(
+ text.clone(),
+ base_url.clone(),
+ script_type.clone(),
+ ));
+
+ // TODO: Step 25-2.
+ if let ScriptType::Module = script_type {
+ warn!(
+ "{} is a module script. It should be fixed after #23545 landed.",
+ base_url.clone()
+ );
+ return;
+ }
+
+ // Step 26.
if was_parser_inserted &&
doc.get_current_parser()
.map_or(false, |parser| parser.script_nesting_level() <= 1) &&
doc.get_script_blocking_stylesheets_count() > 0
{
- // Step 23.h: classic, has no src, was parser-inserted, is blocked on stylesheet.
+ // Step 26.h: classic, has no src, was parser-inserted, is blocked on stylesheet.
doc.set_pending_parsing_blocking_script(self, Some(result));
} else {
- // Step 23.i: otherwise.
+ // Step 26.i: otherwise.
self.execute(result);
}
}
}
- fn unminify_js(&self, script: &mut ClassicScript) {
+ fn unminify_js(&self, script: &mut ScriptOrigin) {
if !self.parser_document.window().unminify_js() {
return;
}
@@ -584,7 +628,7 @@ impl HTMLScriptElement {
}
/// <https://html.spec.whatwg.org/multipage/#execute-the-script-block>
- pub fn execute(&self, result: Result<ClassicScript, NetworkError>) {
+ pub fn execute(&self, result: Result<ScriptOrigin, NetworkError>) {
// Step 1.
let doc = document_from_node(self);
if self.parser_inserted.get() && &*doc != &*self.parser_document {
@@ -639,7 +683,7 @@ impl HTMLScriptElement {
}
// https://html.spec.whatwg.org/multipage/#run-a-classic-script
- pub fn run_a_classic_script(&self, script: &ClassicScript) {
+ pub fn run_a_classic_script(&self, script: &ScriptOrigin) {
// TODO use a settings object rather than this element's document/window
// Step 2
let document = document_from_node(self);
@@ -688,45 +732,58 @@ impl HTMLScriptElement {
);
}
- pub fn is_javascript(&self) -> bool {
+ // https://html.spec.whatwg.org/multipage/#prepare-a-script Step 7.
+ pub fn get_script_type(&self) -> Option<ScriptType> {
let element = self.upcast::<Element>();
+
let type_attr = element.get_attribute(&ns!(), &local_name!("type"));
- let is_js = match type_attr.as_ref().map(|s| s.value()) {
- Some(ref s) if s.is_empty() => {
- // type attr exists, but empty means js
+ let language_attr = element.get_attribute(&ns!(), &local_name!("language"));
+
+ let script_type = match (
+ type_attr.as_ref().map(|t| t.value()),
+ language_attr.as_ref().map(|l| l.value()),
+ ) {
+ (Some(ref ty), _) if ty.is_empty() => {
debug!("script type empty, inferring js");
- true
+ Some(ScriptType::Classic)
},
- Some(s) => {
- debug!("script type={}", &**s);
- SCRIPT_JS_MIMES
- .contains(&s.to_ascii_lowercase().trim_matches(HTML_SPACE_CHARACTERS))
+ (None, Some(ref lang)) if lang.is_empty() => {
+ debug!("script type empty, inferring js");
+ Some(ScriptType::Classic)
},
- None => {
- debug!("no script type");
- let language_attr = element.get_attribute(&ns!(), &local_name!("language"));
- let is_js = match language_attr.as_ref().map(|s| s.value()) {
- Some(ref s) if s.is_empty() => {
- debug!("script language empty, inferring js");
- true
- },
- Some(s) => {
- debug!("script language={}", &**s);
- let mut language = format!("text/{}", &**s);
- language.make_ascii_lowercase();
- SCRIPT_JS_MIMES.contains(&&*language)
- },
- None => {
- debug!("no script type or language, inferring js");
- true
- },
- };
- // https://github.com/rust-lang/rust/issues/21114
- is_js
+ (None, None) => {
+ debug!("script type empty, inferring js");
+ Some(ScriptType::Classic)
+ },
+ (None, Some(ref lang)) => {
+ debug!("script language={}", &***lang);
+ let language = format!("text/{}", &***lang);
+
+ if SCRIPT_JS_MIMES.contains(&language.to_ascii_lowercase().as_str()) {
+ Some(ScriptType::Classic)
+ } else {
+ None
+ }
+ },
+ (Some(ref ty), _) => {
+ debug!("script type={}", &***ty);
+
+ if &***ty == String::from("module") {
+ return Some(ScriptType::Module);
+ }
+
+ if SCRIPT_JS_MIMES
+ .contains(&ty.to_ascii_lowercase().trim_matches(HTML_SPACE_CHARACTERS))
+ {
+ Some(ScriptType::Classic)
+ } else {
+ None
+ }
},
};
+
// https://github.com/rust-lang/rust/issues/21114
- is_js
+ script_type
}
pub fn set_parser_inserted(&self, parser_inserted: bool) {