Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Unified Diff: third_party/WebKit/Source/core/dom/ScriptLoader.cpp

Issue 2555653002: [WIP Prototype] ES6 https://html.spec.whatwg.org/#fetch-a-single-module-script implementation (Closed)
Patch Set: ModuleTreeLinkerTest.fetchTreeInstantiationFailure Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/dom/ScriptLoader.cpp
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index b7ffc14fe49f45a40f6278f6b44bea0e0dc5ddd4..f15b209b11fa9b963db109875c45d22560b2d39a 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -29,10 +29,13 @@
#include "bindings/core/v8/V8Binding.h"
#include "core/HTMLNames.h"
#include "core/SVGNames.h"
+#include "core/dom/ClassicPendingScript.h"
#include "core/dom/ClassicScript.h"
#include "core/dom/Document.h"
#include "core/dom/DocumentParserTiming.h"
#include "core/dom/IgnoreDestructiveWriteCountIncrementer.h"
+#include "core/dom/Modulator.h"
+#include "core/dom/ModulePendingScript.h"
#include "core/dom/Script.h"
#include "core/dom/ScriptElementBase.h"
#include "core/dom/ScriptRunner.h"
@@ -42,13 +45,13 @@
#include "core/frame/LocalFrame.h"
#include "core/frame/SubresourceIntegrity.h"
#include "core/frame/csp/ContentSecurityPolicy.h"
-#include "core/html/CrossOriginAttribute.h"
#include "core/html/imports/HTMLImport.h"
#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/modulescript/ModuleScriptFetchRequest.h"
+#include "core/loader/resource/ScriptResource.h"
#include "platform/WebFrameScheduler.h"
#include "platform/loader/fetch/AccessControlStatus.h"
#include "platform/loader/fetch/FetchParameters.h"
-#include "platform/loader/fetch/MemoryCache.h"
#include "platform/loader/fetch/ResourceFetcher.h"
#include "platform/network/mime/MIMETypeRegistry.h"
#include "platform/weborigin/SecurityOrigin.h"
@@ -107,6 +110,7 @@ DEFINE_TRACE(ScriptLoader) {
visitor->Trace(element_);
visitor->Trace(resource_);
visitor->Trace(pending_script_);
+ visitor->Trace(module_tree_client_);
PendingScriptClient::Trace(visitor);
}
@@ -157,10 +161,12 @@ void ScriptLoader::DispatchLoadEvent() {
SetHaveFiredLoadEvent(true);
}
-bool ScriptLoader::IsValidScriptTypeAndLanguage(
+namespace {
+
+bool IsValidClassicScriptTypeAndLanguage(
const String& type,
const String& language,
- LegacyTypeSupport support_legacy_types) {
+ ScriptLoader::LegacyTypeSupport support_legacy_types) {
// FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used
// here to maintain backwards compatibility with existing layout tests. The
// specific violations are:
@@ -173,12 +179,10 @@ bool ScriptLoader::IsValidScriptTypeAndLanguage(
MIMETypeRegistry::IsSupportedJavaScriptMIMEType("text/" +
language) ||
MIMETypeRegistry::IsLegacySupportedJavaScriptLanguage(language);
- } else if (RuntimeEnabledFeatures::moduleScriptsEnabled() &&
- type == "module") {
- return true;
} else if (MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
type.StripWhiteSpace()) ||
- (support_legacy_types == kAllowLegacyTypeInTypeAttribute &&
+ (support_legacy_types ==
+ ScriptLoader::kAllowLegacyTypeInTypeAttribute &&
MIMETypeRegistry::IsLegacySupportedJavaScriptLanguage(type))) {
return true;
}
@@ -186,11 +190,40 @@ bool ScriptLoader::IsValidScriptTypeAndLanguage(
return false;
}
-bool ScriptLoader::IsScriptTypeSupported(
- LegacyTypeSupport support_legacy_types) const {
+} // namespace
+
+// Step 6 of https://html.spec.whatwg.org/#prepare-a-script
+bool ScriptLoader::IsValidScriptTypeAndLanguage(
+ const String& type,
+ const String& language,
+ LegacyTypeSupport support_legacy_types,
+ ScriptType& out_script_type) {
+ if (IsValidClassicScriptTypeAndLanguage(type, language,
+ support_legacy_types)) {
+ // - "If the script block's type string is an ASCII case-insensitive match
+ // for any JavaScript MIME type, the script's type is "classic"."
+ // TODO(hiroshige): Annotate and/or cleanup this step.
+ out_script_type = ScriptType::kClassic;
+ return true;
+ }
+
+ if (RuntimeEnabledFeatures::moduleScriptsEnabled() && type == "module") {
+ // - "If the script block's type string is an ASCII case-insensitive match
+ // for the string "module", the script's type is "module"."
+ out_script_type = ScriptType::kModule;
+ return true;
+ }
+
+ // - "If neither of the above conditions are true, then abort these steps
+ // at this point. No script is executed."
+ return false;
+}
+
+bool ScriptLoader::IsScriptTypeSupported(LegacyTypeSupport support_legacy_types,
+ ScriptType& out_script_type) const {
return IsValidScriptTypeAndLanguage(element_->TypeAttributeValue(),
element_->LanguageAttributeValue(),
- support_legacy_types);
+ support_legacy_types, out_script_type);
}
// https://html.spec.whatwg.org/#prepare-a-script
@@ -231,9 +264,9 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
if (!element_->IsConnected())
return false;
- // 6.
- // TODO(hiroshige): Annotate and/or cleanup this step.
- if (!IsScriptTypeSupported(support_legacy_types))
+ // 6. "Determine the script's type as follows:"
+ // |script_type_| is set here.
+ if (!IsScriptTypeSupported(support_legacy_types, script_type_))
return false;
// 7. "If was-parser-inserted is true,
@@ -264,66 +297,201 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
if (!context_document->CanExecuteScripts(kAboutToExecuteScript))
return false;
+ // 11. "If the script element has a nomodule content attribute
+ // and the script's type is "classic", then abort these steps.
+ // The script is not executed."
+ // TODO(japhet): Implement this step.
+
// 13.
if (!IsScriptForEventSupported())
return false;
- // 14. "If the script element has a charset attribute,
- // then let encoding be the result of
- // getting an encoding from the value of the charset attribute."
- // "If the script element does not have a charset attribute,
- // or if getting an encoding failed, let encoding
- // be the same as the encoding of the script element's node document."
- // TODO(hiroshige): Should we handle failure in getting an encoding?
- String encoding;
- if (!element_->CharsetAttributeValue().IsEmpty())
- encoding = element_->CharsetAttributeValue();
- else
- encoding = element_document.characterSet();
-
- // Steps 15--20 are handled in fetchScript().
+ // 14. is handled below.
+
+ // 15. "Let CORS setting be the current state of the element's
+ // crossorigin content attribute."
+ CrossOriginAttributeValue cross_origin =
+ GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue());
+
+ // 16. is handled below.
+
+ // 17. "If the script element has a nonce attribute,
+ // then let cryptographic nonce be that attribute's value.
+ // Otherwise, let cryptographic nonce be the empty string."
+ String nonce;
+ if (element_->IsNonceableElement())
+ nonce = element_->nonce();
+
+ // 18. is handled below.
+
+ // 19. "Let parser state be "parser-inserted"
+ // if the script element has been flagged as "parser-inserted",
+ // and "not parser-inserted" otherwise."
+ ParserDisposition parser_state =
+ IsParserInserted() ? kParserInserted : kNotParserInserted;
// 21. "If the element has a src content attribute, run these substeps:"
if (element_->HasSourceAttribute()) {
- FetchParameters::DeferOption defer = FetchParameters::kNoDefer;
- if (!parser_inserted_ || element_->AsyncAttributeValue() ||
- element_->DeferAttributeValue())
- defer = FetchParameters::kLazyLoad;
- if (document_write_intervention_ ==
- DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle)
- defer = FetchParameters::kIdleLoad;
- if (!FetchScript(element_->SourceAttributeValue(), encoding, defer))
+ // 21.1. Let src be the value of the element's src attribute.
+ String src =
+ StripLeadingAndTrailingHTMLSpaces(element_->SourceAttributeValue());
+
+ // 21.2. "If src is the empty string, queue a task to
+ // fire an event named error at the element, and abort these steps."
+ if (src.IsEmpty()) {
+ // TODO(hiroshige): Make this asynchronous. Currently we fire the error
+ // event synchronously to keep the existing behavior.
+ DispatchErrorEvent();
return false;
+ }
+
+ // 21.3. "Set the element's from an external file flag."
+ is_external_script_ = true;
+
+ // 21.4. "Parse src relative to the element's node document."
+ KURL url = element_document.CompleteURL(src);
+
+ // 21.5. "If the previous step failed, queue a task to
+ // fire an event named error at the element, and abort these steps."
+ if (!url.IsValid()) {
+ // TODO(hiroshige): Make this asynchronous. Currently we fire the error
+ // event synchronously to keep the existing behavior.
+ DispatchErrorEvent();
+ return false;
+ }
+
+ DCHECK(!resource_);
+ DCHECK(!module_tree_client_);
+
+ // 21.6. "Switch on the script's type:"
+ if (GetScriptType() == ScriptType::kClassic) {
+ // - "classic":
+
+ // 14. "If the script element has a charset attribute,
+ // then let encoding be the result of
+ // getting an encoding from the value of the charset attribute."
+ // "If the script element does not have a charset attribute,
+ // or if getting an encoding failed, let encoding
+ // be the same as the encoding of the script element's node
+ // document."
+ // TODO(hiroshige): Should we handle failure in getting an encoding?
+ String encoding;
+ if (!element_->CharsetAttributeValue().IsEmpty())
+ encoding = element_->CharsetAttributeValue();
+ else
+ encoding = element_document.characterSet();
+
+ // Step 16 is skipped because "module script credentials" is not used
+ // for classic scripts.
+
+ // 18. "If the script element has an integrity attribute,
+ // then let integrity metadata be that attribute's value.
+ // Otherwise, let integrity metadata be the empty string."
+ String integrity_attr = element_->IntegrityAttributeValue();
+ IntegrityMetadataSet integrity_metadata;
+ if (!integrity_attr.IsEmpty()) {
+ SubresourceIntegrity::ParseIntegrityAttribute(
+ integrity_attr, integrity_metadata, &element_document);
+ }
+
+ if (!FetchClassicScript(url, element_document.Fetcher(), nonce,
+ integrity_metadata, parser_state, cross_origin,
+ element_document.GetSecurityOrigin(), encoding)) {
+ // TODO(hiroshige): Make this asynchronous. Currently we fire the error
+ // event synchronously to keep the existing behavior.
+ DispatchErrorEvent();
+ return false;
+ }
+
+ DCHECK(resource_);
+ DCHECK(!module_tree_client_);
+ } else {
+ // - "module":
+
+ // Steps 14 and 18 are skipped because they are not used in module
+ // scripts.
+
+ // 16. "Let module script credentials mode be determined by switching
+ // on CORS setting:"
+ WebURLRequest::FetchCredentialsMode credentials_mode =
+ WebURLRequest::kFetchCredentialsModeOmit;
+ switch (cross_origin) {
+ case kCrossOriginAttributeNotSet:
+ credentials_mode = WebURLRequest::kFetchCredentialsModeOmit;
+ break;
+ case kCrossOriginAttributeAnonymous:
+ credentials_mode = WebURLRequest::kFetchCredentialsModeSameOrigin;
+ break;
+ case kCrossOriginAttributeUseCredentials:
+ credentials_mode = WebURLRequest::kFetchCredentialsModeInclude;
+ break;
+ }
+
+ DCHECK(RuntimeEnabledFeatures::moduleScriptsEnabled());
+ Modulator* modulator = Modulator::From(
+ ToScriptStateForMainWorld(element_document.GetFrame()));
+ FetchModuleScriptTree(url, modulator, nonce, parser_state,
+ credentials_mode);
+
+ DCHECK(!resource_);
+ DCHECK(module_tree_client_);
+ }
+
+ // "When the chosen algorithm asynchronously completes, set
+ // the script's script to the result. At that time, the script is ready."
+ // When the script is ready, PendingScriptClient::pendingScriptFinished()
+ // is used as the notification, and the action to take when
+ // the script is ready is specified later, in
+ // - ScriptLoader::PrepareScript(), or
+ // - HTMLParserScriptRunner,
+ // depending on the conditions in Step 23 of "prepare a script".
}
// 22. "If the element does not have a src content attribute,
// run these substeps:"
-
- // 22.1. "Let source text be the value of the text IDL attribute."
- // This step is done later:
- // - in ScriptLoader::pendingScript() (Step 23, 6th Clause),
- // as Element::textFromChildren() in ScriptLoader::scriptContent(),
- // - in HTMLParserScriptRunner::processScriptElementInternal()
- // (Duplicated code of Step 23, 6th Clause),
- // as Element::textContent(),
- // - in XMLDocumentParser::endElementNs() (Step 23, 5th Clause),
- // as Element::textFromChildren() in ScriptLoader::scriptContent(),
- // - PendingScript::getSource() (Indirectly used via
- // HTMLParserScriptRunner::processScriptElementInternal(),
- // Step 23, 5th Clause),
- // as Element::textContent().
- // TODO(hiroshige): Make them merged or consistent.
-
- // 22.2. "Switch on the script's type:"
- // TODO(hiroshige): Clarify how Step 22.2 is implemented for "classic".
- // TODO(hiroshige): Implement Step 22.2 for "module".
+ if (!element_->HasSourceAttribute()) {
+ // 22.1. "Let source text be the value of the text IDL attribute."
+ // This step is done later:
+ // - in ScriptLoader::pendingScript() (Step 23, 6th Clause),
+ // as Element::textFromChildren() in ScriptLoader::scriptContent(),
+ // - in HTMLParserScriptRunner::processScriptElementInternal()
+ // (Duplicated code of Step 23, 6th Clause),
+ // as Element::textContent(),
+ // - in XMLDocumentParser::endElementNs() (Step 23, 5th Clause),
+ // as Element::textFromChildren() in ScriptLoader::scriptContent(),
+ // - PendingScript::getSource() (Indirectly used via
+ // HTMLParserScriptRunner::processScriptElementInternal(),
+ // Step 23, 5th Clause),
+ // as Element::textContent().
+ // TODO(hiroshige): Make them merged or consistent.
+
+ // 22.2. "Switch on the script's type:"
+ switch (GetScriptType()) {
+ // - "classic":
+ case ScriptType::kClassic:
+ // TODO(hiroshige): Clarify how Step 22.2 is implemented for "classic".
+ break;
+
+ // - "module":
+ case ScriptType::kModule:
+ // Inline module scripts are not yet supported.
+ // FOXME: (how) should we handle this? Should we fail more gracefully?
+ fprintf(
+ stderr,
+ "Inline module script is not yet supported (Document URL: %s)\n",
+ element_document.Url().GetString().Utf8().Data());
+ CHECK(false);
+ break;
+ }
+ }
// [Intervention]
// Since the asynchronous, low priority fetch for doc.written blocked
// script is not for execution, return early from here. Watch for its
// completion to be able to remove it from the memory cache.
- if (document_write_intervention_ ==
- DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
+ if (GetScriptType() == ScriptType::kClassic &&
+ document_write_intervention_ ==
+ DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
pending_script_ = CreatePendingScript();
pending_script_->WatchForLoad(this);
return true;
@@ -344,9 +512,14 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// the element has a src attribute, and the element has a defer attribute,
// and the element has been flagged as "parser-inserted",
// and the element does not have an async attribute"
- // TODO(hiroshige): Check the script's type and implement "module" case.
- if (element_->HasSourceAttribute() && element_->DeferAttributeValue() &&
- parser_inserted_ && !element_->AsyncAttributeValue()) {
+ // - "If the script's type is "module",
+ // and the element has been flagged as "parser-inserted",
+ // and the element does not have an async attribute"
+ if ((GetScriptType() == ScriptType::kClassic &&
+ element_->HasSourceAttribute() && element_->DeferAttributeValue() &&
+ parser_inserted_ && !element_->AsyncAttributeValue()) ||
+ (GetScriptType() == ScriptType::kModule && parser_inserted_ &&
+ !element_->AsyncAttributeValue())) {
// This clause is implemented by the caller-side of prepareScript():
// - HTMLParserScriptRunner::requestDeferredScript(), and
// - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs()
@@ -362,7 +535,8 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// and the element has been flagged as "parser-inserted",
// and the element does not have an async attribute"
// TODO(hiroshige): Check the script's type.
- if (element_->HasSourceAttribute() && parser_inserted_ &&
+ if (GetScriptType() == ScriptType::kClassic &&
+ element_->HasSourceAttribute() && parser_inserted_ &&
!element_->AsyncAttributeValue()) {
// This clause is implemented by the caller-side of prepareScript():
// - HTMLParserScriptRunner::requestParsingBlockingScript()
@@ -386,7 +560,11 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// Part of the condition check is done in
// HTMLParserScriptRunner::processScriptElementInternal().
// TODO(hiroshige): Clean up the split condition check.
- if (!element_->HasSourceAttribute() && parser_inserted_ &&
+ // We check that the type is "classic" here, because according to the spec
+ // a "module" script doesn't reach the 5th Clause because the 4th Clause
+ // catches all "module" scripts.
+ if (GetScriptType() == ScriptType::kClassic &&
+ !element_->HasSourceAttribute() && parser_inserted_ &&
!element_document.IsScriptExecutionReady()) {
// The former part of this clause is
// implemented by the caller-side of prepareScript():
@@ -404,9 +582,15 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// and the element has a src attribute,
// and the element does not have an async attribute,
// and the element does not have the "non-blocking" flag set"
+ // - "If the script's type is "module",
+ // and the element does not have an async attribute,
+ // and the element does not have the "non-blocking" flag set"
// TODO(hiroshige): Check the script's type and implement "module" case.
- if (element_->HasSourceAttribute() && !element_->AsyncAttributeValue() &&
- !non_blocking_) {
+ if ((GetScriptType() == ScriptType::kClassic &&
+ element_->HasSourceAttribute() && !element_->AsyncAttributeValue() &&
+ !non_blocking_) ||
+ (GetScriptType() == ScriptType::kModule &&
+ !element_->AsyncAttributeValue() && !non_blocking_)) {
// "Add the element to the end of the list of scripts that will execute
// in order as soon as possible associated with the node document of the
// script element at the time the prepare a script algorithm started."
@@ -427,8 +611,10 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// 4th Clause:
// - "If the script's type is "classic", and the element has a src attribute"
- // TODO(hiroshige): Check the script's type and implement "module" case.
- if (element_->HasSourceAttribute()) {
+ // - "If the script's type is "module""
+ if ((GetScriptType() == ScriptType::kClassic &&
+ element_->HasSourceAttribute()) ||
+ GetScriptType() == ScriptType::kModule) {
// "The element must be added to the set of scripts that will execute
// as soon as possible of the node document of the script element at the
// time the prepare a script algorithm started."
@@ -459,6 +645,8 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// This clause is executed only if the script's type is "classic"
// and the element doesn't have a src attribute.
+ DCHECK_EQ(GetScriptType(), ScriptType::kClassic);
+ DCHECK(!is_external_script_);
// Reset line numbering for nested writes.
TextPosition position = element_document.IsInDocumentWrite()
@@ -477,108 +665,62 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
return true;
}
-// Steps 15--21 of https://html.spec.whatwg.org/#prepare-a-script
-bool ScriptLoader::FetchScript(const String& source_url,
- const String& encoding,
- FetchParameters::DeferOption defer) {
- Document* element_document = &(element_->GetDocument());
- if (!element_->IsConnected() || element_->GetDocument() != element_document)
- return false;
-
- DCHECK(!resource_);
- // 21. "If the element has a src content attribute, run these substeps:"
- if (!StripLeadingAndTrailingHTMLSpaces(source_url).IsEmpty()) {
- // 21.4. "Parse src relative to the element's node document."
- ResourceRequest resource_request(element_document->CompleteURL(source_url));
-
- // [Intervention]
- if (document_write_intervention_ ==
- DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
- resource_request.SetHTTPHeaderField(
- "Intervention",
- "<https://www.chromestatus.com/feature/5718547946799104>");
- }
+bool ScriptLoader::FetchClassicScript(
+ const KURL& url,
+ ResourceFetcher* fetcher,
+ const String& nonce,
+ const IntegrityMetadataSet& integrity_metadata,
+ ParserDisposition parser_state,
+ CrossOriginAttributeValue cross_origin,
+ SecurityOrigin* security_origin,
+ const String& encoding) {
+ // https://html.spec.whatwg.org/#prepare-a-script
+ // 21.6, "classic":
+ // "Fetch a classic script given url, settings, ..."
+ ResourceRequest resource_request(url);
- FetchParameters params(resource_request, element_->InitiatorName());
-
- // 15. "Let CORS setting be the current state of the element's
- // crossorigin content attribute."
- CrossOriginAttributeValue cross_origin =
- GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue());
+ // [Intervention]
+ if (document_write_intervention_ ==
+ DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
+ resource_request.SetHTTPHeaderField(
+ "Intervention",
+ "<https://www.chromestatus.com/feature/5718547946799104>");
+ }
- // 16. "Let module script credentials mode be determined by switching
- // on CORS setting:"
- // TODO(hiroshige): Implement this step for "module".
+ FetchParameters params(resource_request, element_->InitiatorName());
- // 21.6, "classic": "Fetch a classic script given ... CORS setting
- // ... and encoding."
- if (cross_origin != kCrossOriginAttributeNotSet) {
- params.SetCrossOriginAccessControl(element_document->GetSecurityOrigin(),
- cross_origin);
- }
+ // "... cryptographic nonce, ..."
+ params.SetContentSecurityPolicyNonce(nonce);
- params.SetCharset(encoding);
-
- // 17. "If the script element has a nonce attribute,
- // then let cryptographic nonce be that attribute's value.
- // Otherwise, let cryptographic nonce be the empty string."
- if (element_->IsNonceableElement())
- params.SetContentSecurityPolicyNonce(element_->nonce());
-
- // 19. "Let parser state be "parser-inserted"
- // if the script element has been flagged as "parser-inserted",
- // and "not parser-inserted" otherwise."
- params.SetParserDisposition(IsParserInserted() ? kParserInserted
- : kNotParserInserted);
-
- params.SetDefer(defer);
-
- // 18. "If the script element has an integrity attribute,
- // then let integrity metadata be that attribute's value.
- // Otherwise, let integrity metadata be the empty string."
- String integrity_attr = element_->IntegrityAttributeValue();
- if (!integrity_attr.IsEmpty()) {
- IntegrityMetadataSet metadata_set;
- SubresourceIntegrity::ParseIntegrityAttribute(
- integrity_attr, metadata_set, element_document);
- params.SetIntegrityMetadata(metadata_set);
- }
+ // "... integrity metadata, ..."
+ params.SetIntegrityMetadata(integrity_metadata);
- // 21.6. "Switch on the script's type:"
+ // "... parser state, ..."
+ params.SetParserDisposition(parser_state);
- // - "classic":
- // "Fetch a classic script given url, settings, cryptographic nonce,
- // integrity metadata, parser state, CORS setting, and encoding."
- resource_ = ScriptResource::Fetch(params, element_document->Fetcher());
+ // "... CORS setting, ..."
+ if (cross_origin != kCrossOriginAttributeNotSet) {
+ params.SetCrossOriginAccessControl(security_origin, cross_origin);
+ }
- // - "module":
- // "Fetch a module script graph given url, settings, "script",
- // cryptographic nonce, parser state, and
- // module script credentials mode."
- // TODO(kouhei, hiroshige): Implement this.
+ // "... and encoding."
+ params.SetCharset(encoding);
- // "When the chosen algorithm asynchronously completes, set
- // the script's script to the result. At that time, the script is ready."
- // When the script is ready, PendingScriptClient::pendingScriptFinished()
- // is used as the notification, and the action to take when
- // the script is ready is specified later, in
- // - ScriptLoader::prepareScript(), or
- // - HTMLParserScriptRunner,
- // depending on the conditions in Step 23 of "prepare a script".
+ // This DeferOption logic is only for classic scripts, as we always set
+ // |kLazyLoad| for module scripts in ModuleScriptLoader.
+ FetchParameters::DeferOption defer = FetchParameters::kNoDefer;
+ if (!parser_inserted_ || element_->AsyncAttributeValue() ||
+ element_->DeferAttributeValue())
+ defer = FetchParameters::kLazyLoad;
+ if (document_write_intervention_ ==
+ DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle)
+ defer = FetchParameters::kIdleLoad;
+ params.SetDefer(defer);
- // 21.3. "Set the element's from an external file flag."
- is_external_script_ = true;
- }
+ resource_ = ScriptResource::Fetch(params, fetcher);
- if (!resource_) {
- // 21.2. "If src is the empty string, queue a task to
- // fire an event named error at the element, and abort these steps."
- // 21.5. "If the previous step failed, queue a task to
- // fire an event named error at the element, and abort these steps."
- // TODO(hiroshige): Make this asynchronous.
- DispatchErrorEvent();
+ if (!resource_)
return false;
- }
// [Intervention]
if (created_during_document_write_ &&
@@ -591,9 +733,36 @@ bool ScriptLoader::FetchScript(const String& source_url,
return true;
}
+void ScriptLoader::FetchModuleScriptTree(
+ const KURL& url,
+ Modulator* modulator,
+ const String& nonce,
+ ParserDisposition parser_state,
+ WebURLRequest::FetchCredentialsMode credentials_mode) {
+ // https://html.spec.whatwg.org/#prepare-a-script
+ // 21.6, "module":
+ // "Fetch a module script graph given url, settings, "script",
+ // cryptographic nonce, parser state, and
+ // module script credentials mode."
+ ModuleScriptFetchRequest module_request(url, nonce, parser_state,
+ credentials_mode);
+
+ module_tree_client_ = ModulePendingScriptTreeClient::Create();
+
+ modulator->FetchTree(module_request, module_tree_client_);
+}
+
PendingScript* ScriptLoader::CreatePendingScript() {
- CHECK(resource_);
- return PendingScript::Create(element_, resource_);
+ switch (GetScriptType()) {
+ case ScriptType::kClassic:
+ CHECK(resource_);
+ return ClassicPendingScript::Create(element_, resource_);
+ case ScriptType::kModule:
+ CHECK(module_tree_client_);
+ return ModulePendingScript::Create(element_, module_tree_client_);
+ }
+ NOTREACHED();
+ return nullptr;
}
bool ScriptLoader::ExecuteScript(const Script* script) {
@@ -620,6 +789,7 @@ bool ScriptLoader::ExecuteScript(const Script* script) {
// TODO(hiroshige): Move event dispatching code to doExecuteScript().
bool ScriptLoader::DoExecuteScript(const Script* script) {
DCHECK(already_started_);
+ CHECK_EQ(script->GetScriptType(), GetScriptType());
if (script->IsEmpty())
return true;
@@ -662,10 +832,13 @@ bool ScriptLoader::DoExecuteScript(const Script* script) {
// or the script's type is module",
// then increment the ignore-destructive-writes counter of the
// script element's node document. Let neutralized doc be that Document."
- // TODO(hiroshige): Implement "module" case.
IgnoreDestructiveWriteCountIncrementer
ignore_destructive_write_count_incrementer(
- is_external_script_ || is_imported_script ? context_document : 0);
+ is_external_script_ ||
+ script->GetScriptType() == ScriptType::kModule ||
+ is_imported_script
+ ? context_document
+ : 0);
// 4. "Let old script element be the value to which the script element's
// node document's currentScript object was most recently set."
@@ -676,18 +849,24 @@ bool ScriptLoader::DoExecuteScript(const Script* script) {
// 1. "If the script element's root is not a shadow root,
// then set the script element's node document's currentScript
// attribute to the script element. Otherwise, set it to null."
- context_document->PushCurrentScript(element_.Get());
+ // - "module":
+ // 1. "Set the script element's node document's currentScript attribute
+ // to null."
+ ScriptElementBase* current_script = nullptr;
+ if (script->GetScriptType() == ScriptType::kClassic)
+ current_script = element_;
+ context_document->PushCurrentScript(current_script);
+ // - "classic":
// 2. "Run the classic script given by the script's script."
// Note: This is where the script is compiled and actually executed.
- script->RunScript(frame, element_->GetDocument().GetSecurityOrigin());
-
// - "module":
- // TODO(hiroshige): Implement this.
+ // 2. "Run the module script given by the script's script."
+ script->RunScript(frame, element_->GetDocument().GetSecurityOrigin());
// 6. "Set the script element's node document's currentScript attribute
// to old script element."
- context_document->PopCurrentScript(element_.Get());
+ context_document->PopCurrentScript(current_script);
return true;
@@ -699,25 +878,27 @@ bool ScriptLoader::DoExecuteScript(const Script* script) {
void ScriptLoader::Execute() {
DCHECK(!will_be_parser_executed_);
DCHECK(async_exec_type_ != ScriptRunner::kNone);
- DCHECK(pending_script_->GetResource());
+ DCHECK(pending_script_->IsExternal());
bool error_occurred = false;
Script* script = pending_script_->GetSource(KURL(), error_occurred);
+ const bool wasCanceled = pending_script_->WasCanceled();
DetachPendingScript();
if (error_occurred) {
DispatchErrorEvent();
- } else if (!resource_->WasCanceled()) {
+ } else if (!wasCanceled) {
if (ExecuteScript(script))
DispatchLoadEvent();
else
DispatchErrorEvent();
}
resource_ = nullptr;
+ module_tree_client_ = nullptr;
}
void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) {
DCHECK(!will_be_parser_executed_);
DCHECK_EQ(pending_script_, pending_script);
- DCHECK_EQ(pending_script->GetResource(), resource_);
+ DCHECK_EQ(pending_script_->GetScriptType(), GetScriptType());
// We do not need this script in the memory cache. The primary goals of
// sending this fetch request are to let the third party server know
@@ -725,7 +906,8 @@ void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) {
// cache for subsequent uses.
if (document_write_intervention_ ==
DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
- GetMemoryCache()->Remove(pending_script_->GetResource());
+ DCHECK_EQ(pending_script_->GetScriptType(), ScriptType::kClassic);
+ pending_script_->RemoveFromMemoryCache();
pending_script_->StopWatchingForLoad();
return;
}

Powered by Google App Engine
This is Rietveld 408576698