diff options
Diffstat (limited to 'dom')
-rw-r--r-- | dom/base/nsGkAtomList.h | 1 | ||||
-rw-r--r-- | dom/base/nsScriptLoader.cpp | 65 | ||||
-rw-r--r-- | dom/base/nsScriptLoader.h | 2 | ||||
-rw-r--r-- | dom/html/HTMLScriptElement.cpp | 12 | ||||
-rw-r--r-- | dom/html/HTMLScriptElement.h | 2 | ||||
-rw-r--r-- | dom/html/test/file_script_module.html | 42 | ||||
-rw-r--r-- | dom/html/test/file_script_nomodule.html | 32 | ||||
-rw-r--r-- | dom/html/test/mochitest.ini | 4 | ||||
-rw-r--r-- | dom/html/test/test_script_module.html | 56 | ||||
-rw-r--r-- | dom/webidl/HTMLScriptElement.webidl | 2 |
10 files changed, 203 insertions, 15 deletions
diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 8fefa0e02..73a3a02b1 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -665,6 +665,7 @@ GK_ATOM(noembed, "noembed") GK_ATOM(noframes, "noframes") GK_ATOM(nohref, "nohref") GK_ATOM(noisolation, "noisolation") +GK_ATOM(nomodule, "nomodule") GK_ATOM(nonce, "nonce") GK_ATOM(none, "none") GK_ATOM(noresize, "noresize") diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index a6d20e363..61d122386 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -647,6 +647,19 @@ nsScriptLoader::CheckContentPolicy(nsIDocument* aDocument, } bool +nsScriptLoader::ModuleScriptsEnabled() +{ + static bool sEnabledForContent = false; + static bool sCachedPref = false; + if (!sCachedPref) { + sCachedPref = true; + Preferences::AddBoolVarCache(&sEnabledForContent, "dom.moduleScripts.enabled", false); + } + + return nsContentUtils::IsChromeDoc(mDocument) || sEnabledForContent; +} + +bool nsScriptLoader::ModuleMapContainsModule(nsModuleLoadRequest *aRequest) const { // Returns whether we have fetched, or are currently fetching, a module script @@ -1223,15 +1236,27 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, nsCOMPtr<nsIInterfaceRequestor> prompter(do_QueryInterface(docshell)); nsSecurityFlags securityFlags; - // TODO: the spec currently gives module scripts different CORS behaviour to - // classic scripts. - securityFlags = aRequest->mCORSMode == CORS_NONE - ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL - : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; - if (aRequest->mCORSMode == CORS_ANONYMOUS) { - securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN; - } else if (aRequest->mCORSMode == CORS_USE_CREDENTIALS) { - securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE; + if (aRequest->IsModuleRequest()) { + // According to the spec, module scripts have different behaviour to classic + // scripts and always use CORS. + securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; + if (aRequest->mCORSMode == CORS_NONE) { + securityFlags |= nsILoadInfo::SEC_COOKIES_OMIT; + } else if (aRequest->mCORSMode == CORS_ANONYMOUS) { + securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN; + } else { + MOZ_ASSERT(aRequest->mCORSMode == CORS_USE_CREDENTIALS); + securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE; + } + } else { + securityFlags = aRequest->mCORSMode == CORS_NONE + ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL + : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; + if (aRequest->mCORSMode == CORS_ANONYMOUS) { + securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN; + } else if (aRequest->mCORSMode == CORS_USE_CREDENTIALS) { + securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE; + } } securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME; @@ -1427,7 +1452,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) nsCOMPtr<nsIContent> scriptContent = do_QueryInterface(aElement); - // Step 12. Check that the script is not an eventhandler + // Step 13. Check that the script is not an eventhandler if (IsScriptEventHandler(scriptContent)) { return false; } @@ -1441,8 +1466,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) nsScriptKind scriptKind = nsScriptKind::Classic; if (!type.IsEmpty()) { - // Support type="module" only for chrome documents. - if (nsContentUtils::IsChromeDoc(mDocument) && type.LowerCaseEqualsASCII("module")) { + if (ModuleScriptsEnabled() && type.LowerCaseEqualsASCII("module")) { scriptKind = nsScriptKind::Module; } else { NS_ENSURE_TRUE(ParseTypeAttribute(type, &version), false); @@ -1462,7 +1486,18 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) } } - // Step 14. in the HTML5 spec + // "In modern user agents that support module scripts, the script element with + // the nomodule attribute will be ignored". + // "The nomodule attribute must not be specified on module scripts (and will + // be ignored if it is)." + if (ModuleScriptsEnabled() && + scriptKind == nsScriptKind::Classic && + scriptContent->IsHTMLElement() && + scriptContent->HasAttr(kNameSpaceID_None, nsGkAtoms::nomodule)) { + return false; + } + + // Step 15. and later in the HTML5 spec nsresult rv = NS_OK; RefPtr<nsScriptLoadRequest> request; if (aElement->GetScriptExternal()) { @@ -1570,7 +1605,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) } return false; } - if (!aElement->GetParserCreated() && !request->IsModuleRequest()) { + if (!aElement->GetParserCreated()) { // Violate the HTML5 spec in order to make LABjs and the "order" plug-in // for RequireJS work with their Gecko-sniffed code path. See // http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html @@ -2761,7 +2796,7 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset, } // TODO: Preload module scripts. - if (nsContentUtils::IsChromeDoc(mDocument) && aType.LowerCaseEqualsASCII("module")) { + if (ModuleScriptsEnabled() && aType.LowerCaseEqualsASCII("module")) { return; } diff --git a/dom/base/nsScriptLoader.h b/dom/base/nsScriptLoader.h index d30a58441..a00239be5 100644 --- a/dom/base/nsScriptLoader.h +++ b/dom/base/nsScriptLoader.h @@ -568,6 +568,8 @@ private: JS::SourceBufferHolder GetScriptSource(nsScriptLoadRequest* aRequest, nsAutoString& inlineData); + bool ModuleScriptsEnabled(); + void SetModuleFetchStarted(nsModuleLoadRequest *aRequest); void SetModuleFetchFinishedAndResumeWaitingRequests(nsModuleLoadRequest *aRequest, nsresult aResult); diff --git a/dom/html/HTMLScriptElement.cpp b/dom/html/HTMLScriptElement.cpp index 94d09c12c..095b9b77d 100644 --- a/dom/html/HTMLScriptElement.cpp +++ b/dom/html/HTMLScriptElement.cpp @@ -218,6 +218,18 @@ HTMLScriptElement::SetAsync(bool aValue, ErrorResult& rv) SetHTMLBoolAttr(nsGkAtoms::async, aValue, rv); } +bool +HTMLScriptElement::NoModule() +{ + return GetBoolAttr(nsGkAtoms::nomodule); +} + +void +HTMLScriptElement::SetNoModule(bool aValue, ErrorResult& aRv) +{ + SetHTMLBoolAttr(nsGkAtoms::nomodule, aValue, aRv); +} + nsresult HTMLScriptElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName, const nsAttrValue* aValue, bool aNotify) diff --git a/dom/html/HTMLScriptElement.h b/dom/html/HTMLScriptElement.h index 00628bd6d..19ceb414f 100644 --- a/dom/html/HTMLScriptElement.h +++ b/dom/html/HTMLScriptElement.h @@ -89,6 +89,8 @@ public: } bool Async(); void SetAsync(bool aValue, ErrorResult& rv); + bool NoModule(); + void SetNoModule(bool aValue, ErrorResult& rv); protected: virtual ~HTMLScriptElement(); diff --git a/dom/html/test/file_script_module.html b/dom/html/test/file_script_module.html new file mode 100644 index 000000000..78c499265 --- /dev/null +++ b/dom/html/test/file_script_module.html @@ -0,0 +1,42 @@ +<html> +<body> + <script> +// Helper methods. +function ok(a, msg) { + parent.postMessage({ check: !!a, msg }, "*") +} + +function is(a, b, msg) { + ok(a === b, msg); +} + +function finish() { + parent.postMessage({ done: true }, "*"); +} + </script> + + <script id="a" nomodule>42</script> + <script id="b">42</script> + <script> +// Let's test the behavior of nomodule attribute and noModule getter/setter. +var a = document.getElementById("a"); +is(a.noModule, true, "HTMLScriptElement with nomodule attribute has noModule set to true"); +a.removeAttribute("nomodule"); +is(a.noModule, false, "HTMLScriptElement without nomodule attribute has noModule set to false"); +a.noModule = true; +ok(a.hasAttribute('nomodule'), "HTMLScriptElement.noModule = true add the nomodule attribute"); + +var b = document.getElementById("b"); +is(b.noModule, false, "HTMLScriptElement without nomodule attribute has noModule set to false"); +b.noModule = true; +ok(b.hasAttribute('nomodule'), "HTMLScriptElement.noModule = true add the nomodule attribute"); + </script> + + <script>var foo = 42;</script> + <script nomodule>foo = 43;</script> + <script> +is(foo, 42, "nomodule HTMLScriptElements should not be executed in modern browsers"); +finish(); + </script> +</body> +</html> diff --git a/dom/html/test/file_script_nomodule.html b/dom/html/test/file_script_nomodule.html new file mode 100644 index 000000000..303edb90b --- /dev/null +++ b/dom/html/test/file_script_nomodule.html @@ -0,0 +1,32 @@ +<html> +<body> + <script> +// Helper methods. +function ok(a, msg) { + parent.postMessage({ check: !!a, msg }, "*") +} + +function is(a, b, msg) { + ok(a === b, msg); +} + +function finish() { + parent.postMessage({ done: true }, "*"); +} + </script> + + <script id="a" nomodule>42</script> + <script> +// Let's test the behavior of nomodule attribute and noModule getter/setter. +var a = document.getElementById("a"); +ok(!("noModule" in a), "When modules are disabled HTMLScriptElement.noModule is not defined"); + </script> + + <script>var foo = 42;</script> + <script nomodule>foo = 43;</script> + <script> +is(foo, 43, "nomodule attribute is ignored when modules are disabled"); +finish(); + </script> +</body> +</html> diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index 99b425df8..0c0ba847c 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -606,3 +606,7 @@ skip-if = os == "android" # up/down arrow keys not supported on android [test_bug1295719_event_sequence_for_number_keys.html] [test_bug1310865.html] [test_bug1315146.html] ++[test_script_module.html] ++support-files = ++ file_script_module.html ++ file_script_nomodule.html
\ No newline at end of file diff --git a/dom/html/test/test_script_module.html b/dom/html/test/test_script_module.html new file mode 100644 index 000000000..4878bb379 --- /dev/null +++ b/dom/html/test/test_script_module.html @@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLScriptElement with nomodule attribute</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> + +<body> + <script> +onmessage = (e) => { + if ("done" in e.data) { + next(); + } else if ("check" in e.data) { + ok(e.data.check, e.data.msg); + } else { + ok(false, "Unknown message"); + } +} + +var tests = [ + function() { + SpecialPowers.pushPrefEnv({"set":[["dom.moduleScripts.enabled", true]]}) + .then(() => { + var ifr = document.createElement('iframe'); + ifr.src = "file_script_module.html"; + document.body.appendChild(ifr); + }); + }, + + function() { + SpecialPowers.pushPrefEnv({"set":[["dom.moduleScripts.enabled", false]]}) + .then(() => { + var ifr = document.createElement('iframe'); + ifr.src = "file_script_nomodule.html"; + document.body.appendChild(ifr); + }); + }, +]; + +SimpleTest.waitForExplicitFinish(); +next(); + +function next() { + if (!tests.length) { + SimpleTest.finish(); + return; + } + + var test = tests.shift(); + test(); +} + </script> + +</body> +</html> diff --git a/dom/webidl/HTMLScriptElement.webidl b/dom/webidl/HTMLScriptElement.webidl index 377056366..5b64c42d7 100644 --- a/dom/webidl/HTMLScriptElement.webidl +++ b/dom/webidl/HTMLScriptElement.webidl @@ -13,6 +13,8 @@ interface HTMLScriptElement : HTMLElement { attribute DOMString src; [SetterThrows] attribute DOMString type; + [SetterThrows, Pref="dom.moduleScripts.enabled"] + attribute boolean noModule; [SetterThrows] attribute DOMString charset; [SetterThrows] |