Skip to content

Commit

Permalink
Update implementation of TT enforcement for document.write(ln)
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=273819

Reviewed by Darin Adler.

This patch switches document.write and writeln to use a union IDL type and single call to default policy.

See whatwg/html#10328

* LayoutTests/imported/w3c/web-platform-tests/trusted-types/block-string-assignment-to-Document-write-expected.txt:
* Source/WebCore/dom/DOMImplementation.cpp:
(WebCore::DOMImplementation::createHTMLDocument):
* Source/WebCore/dom/Document+HTML.idl:
* Source/WebCore/dom/Document.cpp:
(WebCore::Document::write):
(WebCore::Document::writeln):
* Source/WebCore/dom/Document.h:
* Source/WebKitLegacy/mac/DOM/DOMHTMLDocument.mm:
(-[DOMHTMLDocument write:]):
(-[DOMHTMLDocument writeln:]):

Canonical link: https://commits.webkit.org/279904@main
  • Loading branch information
lukewarlow committed Jun 11, 2024
1 parent 779b597 commit cfe83d0
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ CONSOLE MESSAGE: This requires a TrustedHTML value else it violates the followin
CONSOLE MESSAGE: This requires a TrustedHTML value else it violates the following Content Security Policy directive: "require-trusted-types-for 'script'"
CONSOLE MESSAGE: This requires a TrustedHTML value else it violates the following Content Security Policy directive: "require-trusted-types-for 'script'"
CONSOLE MESSAGE: This requires a TrustedHTML value else it violates the following Content Security Policy directive: "require-trusted-types-for 'script'"
abcdefghijkl
abczxcvbnjkl

PASS document.write with html assigned via policy (successful URL transformation).
PASS document.write with multiple trusted arguments.
Expand All @@ -21,9 +21,9 @@ PASS `document.writeln(string, TrustedHTML)` throws
PASS `document.write(null)` throws
PASS `document.writeln(null)` throws
PASS `document.write(string)` observes default policy
FAIL `document.write(string, string)` observes default policy assert_equals: expected "abczxcvbnjkl" but got "abcdefghijkl"
FAIL `document.write(string, TrustedHTML)` observes default policy assert_equals: expected "abczxcvbnjkl" but got "abcdefghijkl"
PASS `document.write(string, string)` observes default policy
PASS `document.write(string, TrustedHTML)` observes default policy
PASS `document.writeln(string)` observes default policy
FAIL `document.writeln(string, string)` observes default policy assert_equals: expected "abczxcvbnjkl" but got "abcdefghijkl"
FAIL `document.writeln(string, TrustedHTML)` observes default policy assert_equals: expected "abczxcvbnjkl" but got "abcdefghijkl"
PASS `document.writeln(string, string)` observes default policy
PASS `document.writeln(string, TrustedHTML)` observes default policy

2 changes: 1 addition & 1 deletion Source/WebCore/dom/DOMImplementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Ref<HTMLDocument> DOMImplementation::createHTMLDocument(String&& title)
Ref document = HTMLDocument::create(nullptr, m_document->protectedSettings(), URL(), { });
document->setParserContentPolicy({ ParserContentPolicy::AllowScriptingContent });
document->open();
document->write(nullptr, { "<!doctype html><html><head></head><body></body></html>"_s });
document->write(nullptr, FixedVector<String> { "<!doctype html><html><head></head><body></body></html>"_s });
if (!title.isNull()) {
auto titleElement = HTMLTitleElement::create(titleTag, document);
titleElement->appendChild(document->createTextNode(WTFMove(title)));
Expand Down
6 changes: 2 additions & 4 deletions Source/WebCore/dom/Document+HTML.idl
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ partial interface Document {
[CEReactions=Needed, CallWith=EntryDocument, ImplementedAs=openForBindings] Document open(optional DOMString unused1, optional DOMString unused2); // both arguments are ignored.
[CallWith=ActiveWindow&FirstWindow, ImplementedAs=openForBindings] WindowProxy open(USVString url, [AtomString] DOMString name, DOMString features);
[CEReactions=Needed, ImplementedAs=closeForBindings] undefined close();
[CEReactions=Needed, CallWith=EntryDocument] undefined write(HTMLString... text);
[CEReactions=Needed, CallWith=EntryDocument] undefined writeln(HTMLString... text);
[CEReactions=Needed, CallWith=EntryDocument] undefined write((TrustedHTML or DOMString)... text);
[CEReactions=Needed, CallWith=EntryDocument] undefined writeln((TrustedHTML or DOMString)... text);

// user interaction
[ImplementedAs=windowProxy] readonly attribute WindowProxy? defaultView;
Expand All @@ -78,5 +78,3 @@ partial interface Document {
// special event handler IDL attributes that only apply to Document objects
[LegacyLenientThis] attribute EventHandler onreadystatechange;
};

typedef [StringContext=TrustedHTML] DOMString HTMLString;
51 changes: 43 additions & 8 deletions Source/WebCore/dom/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3911,6 +3911,9 @@ void Document::enqueuePaintTimingEntryIfNeeded()

ExceptionOr<void> Document::write(Document* entryDocument, SegmentedString&& text)
{
if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount)
return Exception { ExceptionCode::InvalidStateError };

if (m_activeParserWasAborted)
return { };

Expand All @@ -3937,27 +3940,59 @@ ExceptionOr<void> Document::write(Document* entryDocument, SegmentedString&& tex
return { };
}

ExceptionOr<void> Document::write(Document* entryDocument, FixedVector<String>&& strings)
ExceptionOr<void> Document::write(Document* entryDocument, FixedVector<std::variant<RefPtr<TrustedHTML>, String>>&& strings, ASCIILiteral lineFeed)
{
if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount)
return Exception { ExceptionCode::InvalidStateError };
auto isTrusted = true;
SegmentedString text;
for (auto& entry : strings) {
text.append(WTF::switchOn(WTFMove(entry),
[&isTrusted](const String& string) {
isTrusted = false;
return string;
},
[](const RefPtr<TrustedHTML>& html) {
return html->toString();
}
));
}

if (isTrusted || !scriptExecutionContext()->settingsValues().trustedTypesEnabled) {
text.append(lineFeed);
return write(entryDocument, WTFMove(text));
}

String textString = text.toString();
auto stringValueHolder = trustedTypeCompliantString(TrustedType::TrustedHTML, *scriptExecutionContext(), textString, lineFeed.isEmpty() ? "Document write"_s : "Document writeln"_s);
if (stringValueHolder.hasException())
return stringValueHolder.releaseException();
SegmentedString trustedText(stringValueHolder.releaseReturnValue());
trustedText.append(lineFeed);
return write(entryDocument, WTFMove(trustedText));
}

ExceptionOr<void> Document::write(Document* entryDocument, FixedVector<std::variant<RefPtr<TrustedHTML>, String>>&& strings)
{
return write(entryDocument, WTFMove(strings), ""_s);
}

ExceptionOr<void> Document::write(Document* entryDocument, FixedVector<String>&& strings)
{
SegmentedString text;
for (auto& string : strings)
text.append(WTFMove(string));

return write(entryDocument, WTFMove(text));
}

ExceptionOr<void> Document::writeln(Document* entryDocument, FixedVector<String>&& strings)
ExceptionOr<void> Document::writeln(Document* entryDocument, FixedVector<std::variant<RefPtr<TrustedHTML>, String>>&& strings)
{
if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount)
return Exception { ExceptionCode::InvalidStateError };
return write(entryDocument, WTFMove(strings), "\n"_s);
}

ExceptionOr<void> Document::writeln(Document* entryDocument, FixedVector<String>&& strings)
{
SegmentedString text;
for (auto& string : strings)
text.append(WTFMove(string));

text.append("\n"_s);
return write(entryDocument, WTFMove(text));
}
Expand Down
4 changes: 4 additions & 0 deletions Source/WebCore/dom/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,8 @@ class Document
void cancelParsing();

ExceptionOr<void> write(Document* entryDocument, SegmentedString&&);
ExceptionOr<void> write(Document* entryDocument, FixedVector<std::variant<RefPtr<TrustedHTML>, String>>&&);
ExceptionOr<void> writeln(Document* entryDocument, FixedVector<std::variant<RefPtr<TrustedHTML>, String>>&&);
WEBCORE_EXPORT ExceptionOr<void> write(Document* entryDocument, FixedVector<String>&&);
WEBCORE_EXPORT ExceptionOr<void> writeln(Document* entryDocument, FixedVector<String>&&);

Expand Down Expand Up @@ -1961,6 +1963,8 @@ class Document

void commonTeardown();

ExceptionOr<void> write(Document* entryDocument, FixedVector<std::variant<RefPtr<TrustedHTML>, String>>&&, ASCIILiteral lineFeed);

WEBCORE_EXPORT Quirks& ensureQuirks();
WEBCORE_EXPORT CachedResourceLoader& ensureCachedResourceLoader();
WEBCORE_EXPORT ExtensionStyleSheets& ensureExtensionStyleSheets();
Expand Down
4 changes: 2 additions & 2 deletions Source/WebKitLegacy/mac/DOM/DOMHTMLDocument.mm
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,13 @@ - (void)close
- (void)write:(NSString *)text
{
WebCore::JSMainThreadNullState state;
IMPL->write(nullptr, { String { text } });
IMPL->write(nullptr, FixedVector<String> { String { text } });
}

- (void)writeln:(NSString *)text
{
WebCore::JSMainThreadNullState state;
IMPL->writeln(nullptr, { String { text} });
IMPL->writeln(nullptr, FixedVector<String> { String { text } });
}

- (void)clear
Expand Down

0 comments on commit cfe83d0

Please sign in to comment.