Skip to content

Commit 64168e4

Browse files
committed
[CSS Module Scripts] Verify if a module type is allowed before fetching
rdar://186415342 https://bugs.webkit.org/show_bug.cgi?id=323170 Reviewed by Yusuke Suzuki. As defined in the HTML spec [1], when loading a module script, there's a check to ensure the module script type is allowed (understood as "supported by the environment"). This wasn't needed before, as the available module script types (JS/WASM, JSON, text) are always supported by JSC. But CSS is a DOM concept, so CSS module scripts can only be loaded in DOM environments (not worker/worklets or non-DOM.) Therefore to implement CSS module scripts, the type check must be present to avoid loading CSS modules in unsupported environments. The check is implemented in both JSC and host. First, JSC checks if it's one of JS/WASM/JSON/text, which it supports. If it's not, JSC vends it out to the host through the new moduleTypeIsAllowed method in the global object method table. A host should implement this method if it can handle other module types not supported by JSC. For example, a DOM host can indicate it supports CSS module scripts. This will be tested by CSS module script tests once it's fully implemented. [1]: https://html.spec.whatwg.org/multipage/webappapis.html#module-type-allowed * Source/JavaScriptCore/API/JSAPIGlobalObject.cpp: (JSC::JSAPIGlobalObject::globalObjectMethodTable): * Source/JavaScriptCore/API/JSAPIGlobalObject.h: * Source/JavaScriptCore/API/JSAPIGlobalObject.mm: (JSC::JSAPIGlobalObject::globalObjectMethodTable): * Source/JavaScriptCore/jsc.cpp: * Source/JavaScriptCore/runtime/GlobalObjectMethodTable.h: * Source/JavaScriptCore/runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::baseGlobalObjectMethodTable): * Source/JavaScriptCore/runtime/JSModuleLoader.cpp: (JSC::moduleTypeIsAllowed): (JSC::JSModuleLoader::importModule): (JSC::JSModuleLoader::fetch): (JSC::JSModuleLoader::hostLoadImportedModule): * Source/WebCore/bindings/js/JSDOMWindowBase.cpp: (WebCore::JSDOMWindowBase::globalObjectMethodTable): * Source/WebCore/bindings/js/JSShadowRealmGlobalScopeBase.cpp: (WebCore::JSShadowRealmGlobalScopeBase::globalObjectMethodTable): * Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp: (WebCore::JSWorkerGlobalScopeBase::globalObjectMethodTable): * Source/WebCore/bindings/js/JSWorkletGlobalScopeBase.cpp: (WebCore::JSWorkletGlobalScopeBase::globalObjectMethodTable): Canonical link: https://commits.webkit.org/320535@main
1 parent 054171f commit 64168e4

11 files changed

Lines changed: 63 additions & 2 deletions

‎Source/JavaScriptCore/API/JSAPIGlobalObject.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const GlobalObjectMethodTable* JSAPIGlobalObject::globalObjectMethodTable()
4343
&shouldInterruptScript,
4444
&javaScriptRuntimeFlags,
4545
&shouldInterruptScriptBeforeTimeout,
46+
nullptr, // moduleTypeIsAllowed
4647
nullptr, // moduleLoaderImportModule
4748
nullptr, // moduleLoaderResolve
4849
nullptr, // moduleLoaderFetch

‎Source/JavaScriptCore/API/JSAPIGlobalObject.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@
2626
#pragma once
2727

2828
#include "JSGlobalObject.h"
29+
#include "ScriptFetchParameters.h"
2930
#include <wtf/RefPtr.h>
3031

3132
OBJC_CLASS JSScript;
3233

3334
namespace JSC {
3435

3536
class ScriptFetcher;
36-
class ScriptFetchParameters;
3737

3838
class JSAPIGlobalObject final : public JSGlobalObject {
3939
public:

‎Source/JavaScriptCore/API/JSAPIGlobalObject.mm‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
&shouldInterruptScript,
6262
&javaScriptRuntimeFlags,
6363
&shouldInterruptScriptBeforeTimeout,
64+
nullptr, // moduleTypeIsAllowed
6465
&moduleLoaderImportModule, // moduleLoaderImportModule
6566
&moduleLoaderResolve, // moduleLoaderResolve
6667
&moduleLoaderFetch, // moduleLoaderFetch

‎Source/JavaScriptCore/jsc.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,7 @@ const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = {
978978
&shouldInterruptScript,
979979
&javaScriptRuntimeFlags,
980980
&shouldInterruptScriptBeforeTimeout,
981+
nullptr, // moduleTypeIsAllowed
981982
&moduleLoaderImportModule,
982983
&moduleLoaderResolve,
983984
&moduleLoaderFetch,

‎Source/JavaScriptCore/runtime/GlobalObjectMethodTable.h‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#pragma once
2323

2424
#include <JavaScriptCore/Exception.h>
25+
#include <JavaScriptCore/ScriptFetchParameters.h>
2526
#include <wtf/Forward.h>
2627
#include <wtf/RefPtr.h>
2728

@@ -42,7 +43,6 @@ class JSValue;
4243
class Microtask;
4344
class RuntimeFlags;
4445
class ScriptFetcher;
45-
class ScriptFetchParameters;
4646
class SourceOrigin;
4747
class Structure;
4848
class QueuedTask;
@@ -61,6 +61,11 @@ struct GlobalObjectMethodTable {
6161
RuntimeFlags (*javaScriptRuntimeFlags)(const JSGlobalObject*);
6262
bool (*shouldInterruptScriptBeforeTimeout)(const JSGlobalObject*);
6363

64+
// Allows the host to define which module type is allowed (can be handled by the host)
65+
// besides JS/WASM/JSON/text, which are handled by JSC.
66+
// https://html.spec.whatwg.org/multipage/webappapis.html#module-type-allowed
67+
bool (*moduleTypeIsAllowed)(ScriptFetchParameters::Type);
68+
6469
JSPromise* (*moduleLoaderImportModule)(JSGlobalObject*, JSModuleLoader*, JSString*, RefPtr<ScriptFetchParameters>, const SourceOrigin&, bool deferred);
6570
Identifier (*moduleLoaderResolve)(JSGlobalObject*, JSModuleLoader*, JSValue, JSValue, RefPtr<ScriptFetcher>, bool useImportMap);
6671
JSPromise* (*moduleLoaderFetch)(JSGlobalObject*, JSModuleLoader*, JSValue key, const String& referrer, RefPtr<ScriptFetchParameters>, RefPtr<ScriptFetcher>);

‎Source/JavaScriptCore/runtime/JSGlobalObject.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,7 @@ const GlobalObjectMethodTable* JSGlobalObject::baseGlobalObjectMethodTable()
678678
&shouldInterruptScript,
679679
&javaScriptRuntimeFlags,
680680
&shouldInterruptScriptBeforeTimeout,
681+
nullptr, // moduleTypeIsAllowed
681682
nullptr, // moduleLoaderImportModule
682683
nullptr, // moduleLoaderResolve
683684
nullptr, // moduleLoaderFetch

‎Source/JavaScriptCore/runtime/JSModuleLoader.cpp‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,25 @@ JSPromise* JSModuleLoader::requestImportModule(JSGlobalObject* globalObject, con
463463
return resultPromise;
464464
}
465465

466+
// https://html.spec.whatwg.org/multipage/webappapis.html#module-type-allowed
467+
static bool moduleTypeIsAllowed(JSGlobalObject* globalObject, ScriptFetchParameters::Type type)
468+
{
469+
switch (type) {
470+
case ScriptFetchParameters::JavaScript:
471+
case ScriptFetchParameters::WebAssembly:
472+
case ScriptFetchParameters::JSON:
473+
case ScriptFetchParameters::Text:
474+
case ScriptFetchParameters::None:
475+
return true;
476+
477+
default:
478+
if (globalObject->globalObjectMethodTable()->moduleTypeIsAllowed)
479+
return globalObject->globalObjectMethodTable()->moduleTypeIsAllowed(type);
480+
481+
return false;
482+
};
483+
}
484+
466485
JSPromise* JSModuleLoader::importModule(JSGlobalObject* globalObject, JSString* moduleName, JSValue parameters, const SourceOrigin& referrer, bool deferred)
467486
{
468487
dataLogLnIf(Options::dumpModuleLoadingState(), "Loader [import] ", printableModuleKey(globalObject, moduleName));
@@ -476,6 +495,12 @@ JSPromise* JSModuleLoader::importModule(JSGlobalObject* globalObject, JSString*
476495
auto type = retrieveTypeImportAttribute(globalObject, attributes);
477496
RETURN_IF_EXCEPTION(scope, nullptr);
478497

498+
if (type && !moduleTypeIsAllowed(globalObject, *type)) {
499+
auto* promise = JSPromise::create(vm, globalObject->promiseStructure());
500+
promise->reject(vm, createTypeError(globalObject, "Module type not supported by environment"_s));
501+
RELEASE_AND_RETURN(scope, promise);
502+
}
503+
479504
RefPtr<ScriptFetchParameters> fetchParams;
480505
if (type)
481506
fetchParams = ScriptFetchParameters::create(type.value());
@@ -522,6 +547,13 @@ JSPromise* JSModuleLoader::fetch(JSGlobalObject* globalObject, JSValue key, cons
522547
VM& vm = globalObject->vm();
523548
auto scope = DECLARE_THROW_SCOPE(vm);
524549

550+
// https://html.spec.whatwg.org/multipage/webappapis.html#fetching-scripts:module-type-allowed
551+
// Assert: the result of running the module type allowed steps given moduleType and settingsObject is true.
552+
// Otherwise, we would not have reached this point because a failure would have been raised when inspecting
553+
// moduleRequest.[[Attributes]] in HostLoadImportedModule or fetch a single imported module script.
554+
if (parameters)
555+
ASSERT(moduleTypeIsAllowed(globalObject, parameters->type()));
556+
525557
if (globalObject->globalObjectMethodTable()->moduleLoaderFetch)
526558
RELEASE_AND_RETURN(scope, globalObject->globalObjectMethodTable()->moduleLoaderFetch(globalObject, this, key, referrer, WTF::move(parameters), WTF::move(scriptFetcher)));
527559

@@ -606,6 +638,22 @@ JSPromise* JSModuleLoader::hostLoadImportedModule(JSGlobalObject* globalObject,
606638
const Identifier& specifier = moduleRequest.m_specifier;
607639
auto type = moduleRequest.type();
608640

641+
// Step 14 calls for calling "fetch a single imported module script"
642+
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-imported-module-script
643+
// 3. If the result of running the module type allowed steps given moduleType and settingsObject is false,
644+
// then run onComplete given null, and return.
645+
if (!moduleTypeIsAllowed(globalObject, type)) {
646+
JSPromise* promise = JSPromise::create(vm, globalObject->promiseStructure());
647+
648+
auto error = createTypeError(globalObject, "Module type not supported by environment"_s);
649+
promise->reject(vm, error);
650+
651+
auto exception = Exception::create(vm, error);
652+
finishLoadingImportedModule(globalObject, referrer, moduleRequest, payload, exception, scriptFetcher);
653+
654+
RELEASE_AND_RETURN(scope, promise);
655+
}
656+
609657
ModuleMapKey moduleMapKey { specifier.impl(), type };
610658

611659
// HostLoadImportedModule is required to be idempotent for the same

‎Source/WebCore/bindings/js/JSDOMWindowBase.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ const GlobalObjectMethodTable* JSDOMWindowBase::globalObjectMethodTable()
9595
shouldInterruptScript,
9696
javaScriptRuntimeFlags,
9797
shouldInterruptScriptBeforeTimeout,
98+
nullptr, // moduleTypeIsAllowed
9899
moduleLoaderImportModule,
99100
moduleLoaderResolve,
100101
moduleLoaderFetch,

‎Source/WebCore/bindings/js/JSShadowRealmGlobalScopeBase.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const GlobalObjectMethodTable* JSShadowRealmGlobalScopeBase::globalObjectMethodT
5151
&shouldInterruptScript,
5252
&javaScriptRuntimeFlags,
5353
&shouldInterruptScriptBeforeTimeout,
54+
nullptr, // moduleTypeIsAllowed
5455
&moduleLoaderImportModule,
5556
&moduleLoaderResolve,
5657
&moduleLoaderFetch,

‎Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const GlobalObjectMethodTable* JSWorkerGlobalScopeBase::globalObjectMethodTable(
5757
&shouldInterruptScript,
5858
&javaScriptRuntimeFlags,
5959
&shouldInterruptScriptBeforeTimeout,
60+
nullptr, // moduleTypeIsAllowed
6061
&moduleLoaderImportModule,
6162
&moduleLoaderResolve,
6263
&moduleLoaderFetch,

0 commit comments

Comments
 (0)