[Trusted Types] Handle Trusted Types in xlink:href for SVG elements.
Bug: 933300
Change-Id: I58e72faa9f5cdbd0390c84842cc5d5641d0b7d21
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1634880
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Commit-Queue: Daniel Vogelheim <vogelheim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#670100}
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 9ee33d8..0359576f 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1589,6 +1589,24 @@
return getAttribute(QualifiedName(g_null_atom, local_name, namespace_uri));
}
+std::pair<wtf_size_t, const QualifiedName>
+Element::LookupAttributeQNameInternal(const AtomicString& local_name) const {
+ AtomicString case_adjusted_local_name = LowercaseIfNecessary(local_name);
+ if (!GetElementData()) {
+ return std::make_pair(
+ kNotFound,
+ QualifiedName(g_null_atom, case_adjusted_local_name, g_null_atom));
+ }
+
+ AttributeCollection attributes = GetElementData()->Attributes();
+ wtf_size_t index = attributes.FindIndex(case_adjusted_local_name);
+ return std::make_pair(
+ index,
+ index != kNotFound
+ ? attributes[index].GetName()
+ : QualifiedName(g_null_atom, case_adjusted_local_name, g_null_atom));
+}
+
void Element::setAttribute(const AtomicString& local_name,
const AtomicString& value,
ExceptionState& exception_state) {
@@ -1600,22 +1618,9 @@
}
SynchronizeAttribute(local_name);
- AtomicString case_adjusted_local_name = LowercaseIfNecessary(local_name);
-
- if (!GetElementData()) {
- SetAttributeInternal(
- kNotFound,
- QualifiedName(g_null_atom, case_adjusted_local_name, g_null_atom),
- value, kNotInSynchronizationOfLazyAttribute);
- return;
- }
-
- AttributeCollection attributes = GetElementData()->Attributes();
- wtf_size_t index = attributes.FindIndex(case_adjusted_local_name);
- const QualifiedName& q_name =
- index != kNotFound
- ? attributes[index].GetName()
- : QualifiedName(g_null_atom, case_adjusted_local_name, g_null_atom);
+ wtf_size_t index;
+ QualifiedName q_name = QualifiedName::Null();
+ std::tie(index, q_name) = LookupAttributeQNameInternal(local_name);
SetAttributeInternal(index, q_name, value,
kNotInSynchronizationOfLazyAttribute);
}
@@ -1644,36 +1649,28 @@
}
void Element::setAttribute(
- const AtomicString& name,
+ const AtomicString& local_name,
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&
string_or_TT,
ExceptionState& exception_state) {
- // TODO(vogelheim): Check whether this applies to non-HTML documents, too.
- AtomicString name_lowercase = LowercaseIfNecessary(name);
- const AttrNameToTrustedType* attribute_types = &GetCheckedAttributeTypes();
- AttrNameToTrustedType::const_iterator it =
- attribute_types->find(name_lowercase);
- if (it != attribute_types->end()) {
- String attr_value = GetStringFromSpecificTrustedType(
- string_or_TT, it->value, &GetDocument(), exception_state);
- if (!exception_state.HadException())
- setAttribute(name_lowercase, AtomicString(attr_value), exception_state);
- return;
- } else if (name_lowercase.StartsWith("on")) {
- // TODO(jakubvrana): This requires TrustedScript in all attributes starting
- // with "on", including e.g. "one". We use this pattern elsewhere (e.g. in
- // IsEventHandlerAttribute) but it's not ideal. Consider using the event
- // attribute of the resulting AttributeTriggers.
- String attr_value = GetStringFromSpecificTrustedType(
- string_or_TT, SpecificTrustedType::kTrustedScript, &GetDocument(),
- exception_state);
- if (!exception_state.HadException())
- setAttribute(name_lowercase, AtomicString(attr_value), exception_state);
+ if (!Document::IsValidName(local_name)) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidCharacterError,
+ "'" + local_name + "' is not a valid attribute name.");
return;
}
- AtomicString value_string =
- AtomicString(GetStringFromTrustedTypeWithoutCheck(string_or_TT));
- setAttribute(name_lowercase, value_string, exception_state);
+
+ SynchronizeAttribute(local_name);
+ wtf_size_t index;
+ QualifiedName q_name = QualifiedName::Null();
+ std::tie(index, q_name) = LookupAttributeQNameInternal(local_name);
+ String value = GetStringFromSpecificTrustedType(
+ string_or_TT, ExpectedTrustedTypeForAttribute(q_name), &GetDocument(),
+ exception_state);
+ if (exception_state.HadException())
+ return;
+ SetAttributeInternal(index, q_name, AtomicString(value),
+ kNotInSynchronizationOfLazyAttribute);
}
const AttrNameToTrustedType& Element::GetCheckedAttributeTypes() const {
@@ -1681,6 +1678,35 @@
return attribute_map;
}
+SpecificTrustedType Element::ExpectedTrustedTypeForAttribute(
+ const QualifiedName& q_name) const {
+ // There are only a handful of namespaced attributes we care about
+ // (xlink:href), and all of those have identical Trusted Types
+ // properties to their namespace-less counterpart. So we check whether this
+ // is one of SVG's 'known' attributes, and if so just check the local
+ // name part as usual.
+ if (!q_name.NamespaceURI().IsNull() &&
+ !SVGAnimatedHref::IsKnownAttribute(q_name)) {
+ return SpecificTrustedType::kNone;
+ }
+
+ const AttrNameToTrustedType* attribute_types = &GetCheckedAttributeTypes();
+ AttrNameToTrustedType::const_iterator iter =
+ attribute_types->find(q_name.LocalName());
+ if (iter != attribute_types->end())
+ return iter->value;
+
+ if (q_name.LocalName().StartsWith("on")) {
+ // TODO(jakubvrana): This requires TrustedScript in all attributes
+ // starting with "on", including e.g. "one". We use this pattern elsewhere
+ // (e.g. in IsEventHandlerAttribute) but it's not ideal. Consider using
+ // the event attribute of the resulting AttributeTriggers.
+ return SpecificTrustedType::kTrustedScript;
+ }
+
+ return SpecificTrustedType::kNone;
+}
+
void Element::setAttribute(const QualifiedName& name,
const StringOrTrustedHTML& stringOrHTML,
ExceptionState& exception_state) {
@@ -3279,14 +3305,17 @@
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&
string_or_TT,
ExceptionState& exception_state) {
- String value =
- GetStringFromTrustedType(string_or_TT, &GetDocument(), exception_state);
- if (exception_state.HadException())
- return;
QualifiedName parsed_name = g_any_name;
if (!ParseAttributeName(parsed_name, namespace_uri, qualified_name,
exception_state))
return;
+
+ String value = GetStringFromSpecificTrustedType(
+ string_or_TT, ExpectedTrustedTypeForAttribute(parsed_name),
+ &GetDocument(), exception_state);
+ if (exception_state.HadException())
+ return;
+
setAttribute(parsed_name, AtomicString(value));
}
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 73d2c81..d14474df 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -1078,6 +1078,10 @@
SynchronizationOfLazyAttribute);
void RemoveAttributeInternal(wtf_size_t index,
SynchronizationOfLazyAttribute);
+ std::pair<wtf_size_t, const QualifiedName> LookupAttributeQNameInternal(
+ const AtomicString& local_name) const;
+ SpecificTrustedType ExpectedTrustedTypeForAttribute(
+ const QualifiedName&) const;
void CancelFocusAppearanceUpdate();
diff --git a/third_party/blink/renderer/core/svg/svg_a_element.h b/third_party/blink/renderer/core/svg/svg_a_element.h
index 0302bca..19cfd753 100644
--- a/third_party/blink/renderer/core/svg/svg_a_element.h
+++ b/third_party/blink/renderer/core/svg/svg_a_element.h
@@ -38,6 +38,10 @@
explicit SVGAElement(Document&);
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override {
+ return SVGURIReference::GetCheckedAttributeTypes();
+ }
+
void Trace(blink::Visitor*) override;
private:
diff --git a/third_party/blink/renderer/core/svg/svg_fe_image_element.h b/third_party/blink/renderer/core/svg/svg_fe_image_element.h
index af5dcd70..a21fb8e 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_image_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_image_element.h
@@ -46,6 +46,10 @@
return preserve_aspect_ratio_.Get();
}
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override {
+ return SVGURIReference::GetCheckedAttributeTypes();
+ }
+
// Promptly remove as a ImageResource client.
EAGERLY_FINALIZE();
void Trace(blink::Visitor*) override;
diff --git a/third_party/blink/renderer/core/svg/svg_filter_element.h b/third_party/blink/renderer/core/svg/svg_filter_element.h
index 02c1c25..46c123b 100644
--- a/third_party/blink/renderer/core/svg/svg_filter_element.h
+++ b/third_party/blink/renderer/core/svg/svg_filter_element.h
@@ -68,6 +68,10 @@
// Get the associated SVGResource object, if any.
LocalSVGResource* AssociatedResource() const;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override {
+ return SVGURIReference::GetCheckedAttributeTypes();
+ }
+
private:
void SvgAttributeChanged(const QualifiedName&) override;
void ChildrenChanged(const ChildrenChange&) override;
diff --git a/third_party/blink/renderer/core/svg/svg_gradient_element.h b/third_party/blink/renderer/core/svg/svg_gradient_element.h
index 0376e5d..4fac3d3 100644
--- a/third_party/blink/renderer/core/svg/svg_gradient_element.h
+++ b/third_party/blink/renderer/core/svg/svg_gradient_element.h
@@ -64,6 +64,10 @@
const SVGGradientElement* ReferencedElement() const;
void CollectCommonAttributes(GradientAttributes&) const;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override {
+ return SVGURIReference::GetCheckedAttributeTypes();
+ }
+
void Trace(blink::Visitor*) override;
protected:
diff --git a/third_party/blink/renderer/core/svg/svg_image_element.h b/third_party/blink/renderer/core/svg/svg_image_element.h
index 7c7c3ee0..b5e3a36 100644
--- a/third_party/blink/renderer/core/svg/svg_image_element.h
+++ b/third_party/blink/renderer/core/svg/svg_image_element.h
@@ -78,6 +78,10 @@
GetImageLoader().SetImageForTest(content);
}
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override {
+ return SVGURIReference::GetCheckedAttributeTypes();
+ }
+
private:
bool IsStructurallyExternal() const override {
return !HrefString().IsNull();
diff --git a/third_party/blink/renderer/core/svg/svg_mpath_element.h b/third_party/blink/renderer/core/svg/svg_mpath_element.h
index ee6fa88..59e2871 100644
--- a/third_party/blink/renderer/core/svg/svg_mpath_element.h
+++ b/third_party/blink/renderer/core/svg/svg_mpath_element.h
@@ -39,6 +39,10 @@
void TargetPathChanged();
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override {
+ return SVGURIReference::GetCheckedAttributeTypes();
+ }
+
void Trace(blink::Visitor*) override;
private:
diff --git a/third_party/blink/renderer/core/svg/svg_pattern_element.h b/third_party/blink/renderer/core/svg/svg_pattern_element.h
index 45b7af1..1a4e2cbf 100644
--- a/third_party/blink/renderer/core/svg/svg_pattern_element.h
+++ b/third_party/blink/renderer/core/svg/svg_pattern_element.h
@@ -80,6 +80,10 @@
const SVGPatternElement* ReferencedElement() const;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override {
+ return SVGURIReference::GetCheckedAttributeTypes();
+ }
+
void Trace(blink::Visitor*) override;
private:
diff --git a/third_party/blink/renderer/core/svg/svg_script_element.cc b/third_party/blink/renderer/core/svg/svg_script_element.cc
index 5d3ac543..0147e9df 100644
--- a/third_party/blink/renderer/core/svg/svg_script_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_script_element.cc
@@ -173,6 +173,16 @@
}
#endif
+const AttrNameToTrustedType& SVGScriptElement::GetCheckedAttributeTypes()
+ const {
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({
+ {svg_names::kHrefAttr.LocalName(),
+ SpecificTrustedType::kTrustedScriptURL},
+ }));
+ return attribute_map;
+}
+
void SVGScriptElement::Trace(blink::Visitor* visitor) {
visitor->Trace(loader_);
SVGElement::Trace(visitor);
diff --git a/third_party/blink/renderer/core/svg/svg_script_element.h b/third_party/blink/renderer/core/svg/svg_script_element.h
index c1222ee2..cb4b1763 100644
--- a/third_party/blink/renderer/core/svg/svg_script_element.h
+++ b/third_party/blink/renderer/core/svg/svg_script_element.h
@@ -49,6 +49,8 @@
bool IsScriptElement() const override { return true; }
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
+
void Trace(blink::Visitor*) override;
private:
diff --git a/third_party/blink/renderer/core/svg/svg_text_path_element.h b/third_party/blink/renderer/core/svg/svg_text_path_element.h
index 0576602..17c7f3c8 100644
--- a/third_party/blink/renderer/core/svg/svg_text_path_element.h
+++ b/third_party/blink/renderer/core/svg/svg_text_path_element.h
@@ -66,6 +66,10 @@
return spacing_.Get();
}
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override {
+ return SVGURIReference::GetCheckedAttributeTypes();
+ }
+
void Trace(blink::Visitor*) override;
private:
diff --git a/third_party/blink/renderer/core/svg/svg_uri_reference.cc b/third_party/blink/renderer/core/svg/svg_uri_reference.cc
index 99471e10..3153f223 100644
--- a/third_party/blink/renderer/core/svg/svg_uri_reference.cc
+++ b/third_party/blink/renderer/core/svg/svg_uri_reference.cc
@@ -151,4 +151,13 @@
observer = nullptr;
}
+const AttrNameToTrustedType& SVGURIReference::GetCheckedAttributeTypes() const {
+ DEFINE_STATIC_LOCAL(
+ AttrNameToTrustedType, attribute_map,
+ ({
+ {svg_names::kHrefAttr.LocalName(), SpecificTrustedType::kTrustedURL},
+ }));
+ return attribute_map;
+}
+
} // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_uri_reference.h b/third_party/blink/renderer/core/svg/svg_uri_reference.h
index 9b0d505..b15cb9d5 100644
--- a/third_party/blink/renderer/core/svg/svg_uri_reference.h
+++ b/third_party/blink/renderer/core/svg/svg_uri_reference.h
@@ -24,6 +24,7 @@
#include <memory>
#include "base/callback.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/svg/svg_animated_href.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -31,7 +32,6 @@
namespace blink {
class Document;
-class Element;
class IdTargetObserver;
class SVGElement;
class TreeScope;
@@ -81,6 +81,8 @@
// JS API
SVGAnimatedHref* href() const { return href_.Get(); }
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const;
+
void Trace(blink::Visitor*) override;
protected:
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.h b/third_party/blink/renderer/core/svg/svg_use_element.h
index 7c40606..b1ce459 100644
--- a/third_party/blink/renderer/core/svg/svg_use_element.h
+++ b/third_party/blink/renderer/core/svg/svg_use_element.h
@@ -59,6 +59,10 @@
void DispatchPendingEvent();
Path ToClipPath() const;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override {
+ return SVGURIReference::GetCheckedAttributeTypes();
+ }
+
void Trace(blink::Visitor*) override;
private:
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
index ea8ed8d0..695d0dd2 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
@@ -171,6 +171,8 @@
const ExecutionContext* execution_context,
ExceptionState& exception_state) {
switch (specific_trusted_type) {
+ case SpecificTrustedType::kNone:
+ return GetStringFromTrustedTypeWithoutCheck(string_or_trusted_type);
case SpecificTrustedType::kTrustedHTML: {
StringOrTrustedHTML string_or_trusted_html =
string_or_trusted_type.IsTrustedHTML()
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.h b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.h
index 4dac44bb..31c9f6ce 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.h
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.h
@@ -21,6 +21,7 @@
class USVStringOrTrustedURL;
enum class SpecificTrustedType {
+ kNone,
kTrustedHTML,
kTrustedScript,
kTrustedScriptURL,
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/Element-setAttributeNS.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/Element-setAttributeNS.tentative.html
index 80128cf..374e6a9 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/Element-setAttributeNS.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/Element-setAttributeNS.tentative.html
@@ -21,4 +21,15 @@
test(t => {
assert_element_accepts_trusted_url_set_ns(window, '3', t, 'a', 'b', RESULTS.URL);
}, "Element.setAttributeNS assigned via policy (successful URL transformation)");
+
+ test(t => {
+ let p = createURL_policy(window, '5');
+ let url = p.createURL(INPUTS.URL);
+
+ let elem = document.createElementNS("http://www.w3.org/2000/svg", "image");
+ elem.setAttributeNS("http://www.w3.org/1999/xlink", "href", url);
+ let attr_node = elem.getAttributeNodeNS("http://www.w3.org/1999/xlink", "href");
+ assert_equals(attr_node.value + "", RESULTS.URL);
+ }, "Element.setAttributeNS accepts a URL on <svg:image xlink:href/>");
+
</script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html
index 3ad27e2..4bb9569 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html
@@ -25,11 +25,110 @@
assert_element_accepts_trusted_url_set_ns(window, '3', t, 'a', 'b', RESULTS.URL);
}, "Element.setAttributeNS assigned via policy (successful URL transformation)");
+ // Unknown, namespaced attributes should not be TT checked:
test(t => {
- assert_throws_no_trusted_type_set_ns('a', 'b', 'A string');
- }, "`Element.setAttributeNS = string` throws");
+ assert_element_accepts_non_trusted_type_set_ns('a', 'b', 'A string', 'A string');
+ }, "Element.setAttributeNS accepts untrusted string for non-specced accessor");
test(t => {
- assert_throws_no_trusted_type_set_ns('a', 'b', null);
- }, "`Element.setAttributeNS = null` throws");
+ assert_element_accepts_non_trusted_type_set_ns('a', 'b', null, 'null');
+ }, "Element.setAttributeNS accepts null for non-specced accessor");
+
+ // Setup trusted values for use in subsequent tests.
+ const url = createURL_policy(window, '4').createURL(INPUTS.URL);
+ const script_url = createScriptURL_policy(window, '5').createScriptURL(INPUTS.ScriptURL);
+ const html = createHTML_policy(window, '6').createHTML(INPUTS.HTML);
+ const script = createScript_policy(window, '7').createScript(INPUTS.Script);
+
+ // SVG elements that use xlink:href (SVGURIReference) and that expect
+ // TrustedURL.
+ // There a number of affected elements, and there are several ways to set
+ // a namespaced attribute. Let's iterate over all combinations.
+ // TODO(vogelheim): Also SMIL timed elements.
+ const xlink = "http://www.w3.org/1999/xlink";
+ const svg = "http://www.w3.org/2000/svg";
+ const elems = [ "a", "feImage", "filter", "image", "linearGradient",
+ "mpath", "pattern", "radialGradient", "textPath", "use" ];
+
+ // There are multiple ways to set a namespaced attribute. Let's encapsulate
+ // each in a function.
+ const variants = {
+ "setAttributeNS with prefix": (element_name, value) => {
+ let elem = document.createElementNS(svg, element_name);
+ elem.setAttributeNS(xlink, "xlink:href", value);
+ return elem;
+ },
+ "setAttributeNS without prefix": (element_name, value) => {
+ let elem = document.createElementNS(svg, element_name);
+ elem.setAttributeNS(xlink, "href", value);
+ return elem;
+ },
+ "setAttribute with prefix": (element_name, value) => {
+ let elem = document.createElementNS(svg, element_name);
+ // Create the namespaced attribute with setAttributeNS. Then refer
+ // to it with the prefix in setAttribute. This test will break
+ // if either setAttributeNS or setAttribtue functionality it broken.
+ elem.setAttributeNS(xlink, "xlink:href", url);
+ elem.setAttribute("xlink:href", value);
+ return elem;
+ }
+ };
+ for (const e of elems) {
+ for (const variant in variants) {
+ // Assigning a TrustedURL works.
+ test(t => {
+ let elem = variants[variant](e, url);
+ assert_equals("" + RESULTS.URL,
+ elem.getAttributeNodeNS(xlink, "href").value);
+ }, "Assigning TrustedURL to <svg:" + e + "> works via " + variant);
+
+ // Assigning things that ought to not work.
+ const values = ["abc", null, script_url, html, script];
+ values.forEach((value, index) => {
+ test(t => {
+ assert_throws(new TypeError(), _ => { variants[variant](e, value); });
+ }, "Blocking non-TrustedURL assignment to <svg:" + e + "> via " +
+ variant + " value no " + index);
+ });
+ }
+ }
+
+ // Test 'synchronization' of 'xlink:href'.
+ test(t => {
+ // ..setAttribute("xlink:href") will behave differently, depending on
+ // whether the element already has an attribute by that name. Make sure
+ // that Trusted Type handling respects that difference.
+
+ // Case 1: "xlink:href" on an empty element: This is an unknown attribute
+ // not processed by SVG, and string assignment should work.
+ let elem1 = document.createElementNS(svg, "a");
+ elem1.setAttribute("xlink:href", "abc");
+
+ // Case 2: "xlink:href", after a namespaced attribute has been set: Now
+ // this mirrors the SVG attribute, and string assignment should fail.
+ let elem2 = document.createElementNS(svg, "a");
+ elem2.setAttributeNS(xlink, "xlink:href", url);
+ assert_throws(new TypeError(), _ => {
+ elem2.setAttribute("xlink:href", "abc");
+ });
+ }, "Test synchronized, namespaced attributes.");
+
+ // svg:script xlink:href=... expects a TrustedScriptURL.
+ let elem = document.createElementNS(svg, "script");
+ // Assigning a TrustedScriptURL works.
+ test(t => {
+ elem.setAttributeNS(xlink, "href", script_url);
+ assert_equals("" + RESULTS.ScriptURL,
+ elem.getAttributeNodeNS(xlink, "href").value);
+ }, "Assigning TrustedScriptURL to <svg:script xlink:href=...> works");
+
+ // Assigning things that ought to not work.
+ test(t => {
+ const values = [ "abc", null, url, html, script ];
+ for (const v of values) {
+ assert_throws(new TypeError(), _ => {
+ elem.setAttributeNS(xlink, "href", v);
+ });
+ }
+ }, "Blocking non-TrustedScriptURL assignment to <svg:script xlink:href=...> works");
</script>