Support Inline module script
This CL
- Enables inline module scripts in ScriptLoader.
- Adds ModuleTreeLinker::FetchDescendantsForInlineScript() and
related plumbing to ModuleTreeLinkerRegistry and Modulator.
This is not yet spec'ed and we might need revisit once the spec is
updated. https://github.com/whatwg/html/issues/2544
- Makes ModuleScript to store its |source_text| for CSP of inline scripts.
BUG=715369, 594639
Review-Url: https://codereview.chromium.org/2842923002
Cr-Commit-Position: refs/heads/master@{#468087}
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index e1ddf5cd..ee896fe 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2334,19 +2334,13 @@
# This test fails with the stable release mode.
crbug.com/694958 virtual/stable/http/tests/navigation/same-and-different-back.html [ Skip ]
-# Failing because of module-related implementation/test issues and
-# lack of inline module script support.
+# Failing because of module-related implementation/test issues.
crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/crossorigin.html [ Failure ]
crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/errorhandling.html [ Failure ]
crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/imports.html [ Failure Crash ]
-crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html [ Failure Timeout ]
+crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html [ Pass Timeout ]
crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html [ Failure Crash ]
-# Inline module scripts are not yet supported.
-crbug.com/715369 external/wpt/html/semantics/scripting-1/the-script-element/nomodule-set-on-inline-module-script.html [ Failure ]
-crbug.com/715369 fast/dom/HTMLScriptElement/module-script.html [ Failure ]
-crbug.com/715369 virtual/sharedarraybuffer/fast/dom/HTMLScriptElement/module-script.html [ Failure ]
-
# This test has a failure console message with specific performance
# numbers so a consistent baseline cannot be added. This test could be
# imported if the test passed or if the results for testharness tests
diff --git a/third_party/WebKit/Source/core/dom/Modulator.h b/third_party/WebKit/Source/core/dom/Modulator.h
index 98bdad2..da1d8a0 100644
--- a/third_party/WebKit/Source/core/dom/Modulator.h
+++ b/third_party/WebKit/Source/core/dom/Modulator.h
@@ -87,6 +87,9 @@
ModuleGraphLevel,
SingleModuleClient*) = 0;
+ virtual void FetchDescendantsForInlineScript(ModuleScript*,
+ ModuleTreeClient*) = 0;
+
// Synchronously retrieves a single module script from existing module map
// entry.
// Note: returns nullptr if the module map entry is still "fetching".
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp b/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
index 1be380b8..e5e4f35d 100644
--- a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
+++ b/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
@@ -84,6 +84,12 @@
tree_linker_registry_->Fetch(request, ancestor_list, level, this, client);
}
+void ModulatorImpl::FetchDescendantsForInlineScript(ModuleScript* module_script,
+ ModuleTreeClient* client) {
+ tree_linker_registry_->FetchDescendantsForInlineScript(module_script, this,
+ client);
+}
+
void ModulatorImpl::FetchSingle(const ModuleScriptFetchRequest& request,
ModuleGraphLevel level,
SingleModuleClient* client) {
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImpl.h b/third_party/WebKit/Source/core/dom/ModulatorImpl.h
index 2819a57..1087f69 100644
--- a/third_party/WebKit/Source/core/dom/ModulatorImpl.h
+++ b/third_party/WebKit/Source/core/dom/ModulatorImpl.h
@@ -46,6 +46,8 @@
SecurityOrigin* GetSecurityOrigin() override;
void FetchTree(const ModuleScriptFetchRequest&, ModuleTreeClient*) override;
+ void FetchDescendantsForInlineScript(ModuleScript*,
+ ModuleTreeClient*) override;
void FetchTreeInternal(const ModuleScriptFetchRequest&,
const AncestorList&,
ModuleGraphLevel,
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.cpp b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
index bd911121..20cdc1e 100644
--- a/third_party/WebKit/Source/core/dom/ModuleScript.cpp
+++ b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
@@ -33,11 +33,12 @@
if (result.IsNull())
return nullptr;
- return CreateInternal(modulator, result, base_url, nonce, parser_state,
- credentials_mode);
+ return CreateInternal(source_text, modulator, result, base_url, nonce,
+ parser_state, credentials_mode);
}
ModuleScript* ModuleScript::CreateInternal(
+ const String& source_text,
Modulator* modulator,
ScriptModule result,
const KURL& base_url,
@@ -52,8 +53,10 @@
// Step 10. Set script's parser state to the parser state.
// Step 11. Set script's credentials mode to the credentials mode provided.
// Step 12. Return script.
- ModuleScript* module_script = new ModuleScript(
- modulator, result, base_url, nonce, parser_state, credentials_mode);
+ // [not specced] |source_text| is saved for CSP checks.
+ ModuleScript* module_script =
+ new ModuleScript(modulator, result, base_url, nonce, parser_state,
+ credentials_mode, source_text);
// Step 5, a part of ParseModule(): Passing script as the last parameter
// here ensures result.[[HostDefined]] will be script.
@@ -69,8 +72,9 @@
const String& nonce,
ParserDisposition parser_state,
WebURLRequest::FetchCredentialsMode credentials_mode) {
- return CreateInternal(modulator, record, base_url, nonce, parser_state,
- credentials_mode);
+ String dummy_source_text = "";
+ return CreateInternal(dummy_source_text, modulator, record, base_url, nonce,
+ parser_state, credentials_mode);
}
void ModuleScript::SetInstantiationErrorAndClearRecord(ScriptValue error) {
@@ -125,10 +129,7 @@
}
String ModuleScript::InlineSourceTextForCSP() const {
- // Currently we don't support inline module scripts.
- // TODO(hiroshige): Implement this.
- NOTREACHED();
- return String();
+ return source_text_;
}
} // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.h b/third_party/WebKit/Source/core/dom/ModuleScript.h
index 4b9c5dd7..22002a4 100644
--- a/third_party/WebKit/Source/core/dom/ModuleScript.h
+++ b/third_party/WebKit/Source/core/dom/ModuleScript.h
@@ -79,16 +79,19 @@
const KURL& base_url,
const String& nonce,
ParserDisposition parser_state,
- WebURLRequest::FetchCredentialsMode credentials_mode)
+ WebURLRequest::FetchCredentialsMode credentials_mode,
+ const String& source_text)
: settings_object_(settings_object),
record_(record),
base_url_(base_url),
instantiation_error_(this),
nonce_(nonce),
parser_state_(parser_state),
- credentials_mode_(credentials_mode) {}
+ credentials_mode_(credentials_mode),
+ source_text_(source_text) {}
- static ModuleScript* CreateInternal(Modulator*,
+ static ModuleScript* CreateInternal(const String& source_text,
+ Modulator*,
ScriptModule,
const KURL& base_url,
const String& nonce,
@@ -142,6 +145,9 @@
// https://html.spec.whatwg.org/multipage/webappapis.html#concept-module-script-credentials-mode
const WebURLRequest::FetchCredentialsMode credentials_mode_;
+
+ // For CSP check.
+ const String source_text_;
};
} // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index 31c1d93..3ca2f29e 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -321,7 +321,21 @@
CrossOriginAttributeValue cross_origin =
GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue());
- // 16. is handled below.
+ // 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;
+ }
// 17. "If the script element has a nonce attribute,
// then let cryptographic nonce be that attribute's value.
@@ -390,9 +404,6 @@
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."
@@ -420,22 +431,6 @@
// 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()));
@@ -482,16 +477,34 @@
break;
// - "module":
- case ScriptType::kModule:
- // TODO(hiroshige): Implement inline module scripts.
- element_document.AddConsoleMessage(ConsoleMessage::Create(
- kJSMessageSource, kErrorMessageLevel,
- "Inline module script is not yet supported",
- SourceLocation::Create(element_document.Url().GetString(),
- script_start_position.line_.OneBasedInt(),
- script_start_position.column_.OneBasedInt(),
- nullptr)));
- return false;
+ case ScriptType::kModule: {
+ // 1. "Let base URL be the script element's node document's document
+ // base URL."
+ KURL base_url = element_document.BaseURL();
+
+ // 2. "Let script be the result of creating a module script using
+ // source text, settings, base URL, cryptographic nonce,
+ // parser state, and module script credentials mode."
+ Modulator* modulator = Modulator::From(
+ ToScriptStateForMainWorld(element_document.GetFrame()));
+ ModuleScript* module_script = ModuleScript::Create(
+ ScriptContent(), modulator, base_url, nonce, parser_state,
+ credentials_mode, kSharableCrossOrigin);
+
+ // 3. "If this returns null, set the script's script to null and abort
+ // these substeps; the script is ready."
+ if (!module_script)
+ return false;
+
+ // 4. "Fetch the descendants of script (using an empty ancestor list).
+ // When this asynchronously completes, set the script's script to
+ // the result. At that time, the script is ready."
+ DCHECK(!module_tree_client_);
+ module_tree_client_ = ModulePendingScriptTreeClient::Create();
+ modulator->FetchDescendantsForInlineScript(module_script,
+ module_tree_client_);
+ break;
+ }
}
}
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.cpp
index 9e1440b..e032e104 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.cpp
@@ -9,6 +9,7 @@
#include "core/dom/ModuleScript.h"
#include "core/loader/modulescript/ModuleScriptFetchRequest.h"
#include "core/loader/modulescript/ModuleTreeLinkerRegistry.h"
+#include "platform/WebTaskRunner.h"
#include "platform/loader/fetch/ResourceLoadingLog.h"
#include "platform/wtf/Vector.h"
@@ -30,6 +31,36 @@
return fetcher;
}
+ModuleTreeLinker* ModuleTreeLinker::FetchDescendantsForInlineScript(
+ ModuleScript* module_script,
+ Modulator* modulator,
+ ModuleTreeLinkerRegistry* registry,
+ ModuleTreeClient* client) {
+ AncestorList empty_ancestor_list;
+
+ // Substep 4 in "module" case in Step 22 of "prepare a script":"
+ // https://html.spec.whatwg.org/#prepare-a-script
+
+ // 4. "Fetch the descendants of script (using an empty ancestor list)."
+ ModuleTreeLinker* fetcher =
+ new ModuleTreeLinker(empty_ancestor_list, modulator, registry, client);
+ fetcher->module_script_ = module_script;
+ fetcher->AdvanceState(State::kFetchingSelf);
+
+ // "When this asynchronously completes, set the script's script to
+ // the result. At that time, the script is ready."
+ //
+ // Currently we execute "internal module script graph
+ // fetching procedure" Step 5- in addition to "fetch the descendants",
+ // which is not specced yet. https://github.com/whatwg/html/issues/2544
+ // TODO(hiroshige): Fix the implementation and/or comments once the spec
+ // is updated.
+ modulator->TaskRunner()->PostTask(
+ BLINK_FROM_HERE,
+ WTF::Bind(&ModuleTreeLinker::FetchDescendants, WrapPersistent(fetcher)));
+ return fetcher;
+}
+
ModuleTreeLinker::ModuleTreeLinker(const AncestorList& ancestor_list_with_url,
Modulator* modulator,
ModuleTreeLinkerRegistry* registry,
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.h b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.h
index 03daabf..ead8d19 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.h
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.h
@@ -31,6 +31,12 @@
Modulator*,
ModuleTreeLinkerRegistry*,
ModuleTreeClient*);
+ static ModuleTreeLinker* FetchDescendantsForInlineScript(
+ ModuleScript*,
+ Modulator*,
+ ModuleTreeLinkerRegistry*,
+ ModuleTreeClient*);
+
virtual ~ModuleTreeLinker() = default;
DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.cpp
index e07dd3e..0a2b6f34 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.cpp
@@ -27,6 +27,17 @@
return fetcher;
}
+ModuleTreeLinker* ModuleTreeLinkerRegistry::FetchDescendantsForInlineScript(
+ ModuleScript* module_script,
+ Modulator* modulator,
+ ModuleTreeClient* client) {
+ ModuleTreeLinker* fetcher = ModuleTreeLinker::FetchDescendantsForInlineScript(
+ module_script, modulator, this, client);
+ DCHECK(fetcher->IsFetching());
+ active_tree_linkers_.insert(fetcher);
+ return fetcher;
+}
+
void ModuleTreeLinkerRegistry::ReleaseFinishedFetcher(
ModuleTreeLinker* fetcher) {
DCHECK(fetcher->HasFinished());
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.h b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.h
index a038896..0f845fd7 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.h
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.h
@@ -16,6 +16,7 @@
class ModuleTreeClient;
class ModuleTreeLinker;
enum class ModuleGraphLevel;
+class ModuleScript;
// ModuleTreeLinkerRegistry keeps active ModuleTreeLinkers alive.
class CORE_EXPORT ModuleTreeLinkerRegistry
@@ -31,6 +32,9 @@
ModuleGraphLevel,
Modulator*,
ModuleTreeClient*);
+ ModuleTreeLinker* FetchDescendantsForInlineScript(ModuleScript*,
+ Modulator*,
+ ModuleTreeClient*);
private:
ModuleTreeLinkerRegistry() = default;
diff --git a/third_party/WebKit/Source/core/testing/DummyModulator.cpp b/third_party/WebKit/Source/core/testing/DummyModulator.cpp
index f58e35e..e5dcd699 100644
--- a/third_party/WebKit/Source/core/testing/DummyModulator.cpp
+++ b/third_party/WebKit/Source/core/testing/DummyModulator.cpp
@@ -75,6 +75,11 @@
NOTREACHED();
}
+void DummyModulator::FetchDescendantsForInlineScript(ModuleScript*,
+ ModuleTreeClient*) {
+ NOTREACHED();
+}
+
ModuleScript* DummyModulator::GetFetchedModuleScript(const KURL&) {
NOTREACHED();
return nullptr;
diff --git a/third_party/WebKit/Source/core/testing/DummyModulator.h b/third_party/WebKit/Source/core/testing/DummyModulator.h
index c665005..a3725c7 100644
--- a/third_party/WebKit/Source/core/testing/DummyModulator.h
+++ b/third_party/WebKit/Source/core/testing/DummyModulator.h
@@ -44,6 +44,8 @@
void FetchSingle(const ModuleScriptFetchRequest&,
ModuleGraphLevel,
SingleModuleClient*) override;
+ void FetchDescendantsForInlineScript(ModuleScript*,
+ ModuleTreeClient*) override;
ModuleScript* GetFetchedModuleScript(const KURL&) override;
void FetchNewSingleModule(const ModuleScriptFetchRequest&,
ModuleGraphLevel,