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,