mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-31 17:55:59 -04:00
webapi: script-created documents are UTF-8; URLs use the document encoding
Fixes the last failing subtest of WPT
/dom/nodes/DOMImplementation-createHTMLDocument.html ("URL parsing"):
resolving `a.href = "http://example.org/?ä"` on an anchor inside a
createHTMLDocument() document returned "?%E4" instead of "?%C3%A4".
Two spec violations combined:
- Per DOM, documents synthesized by script (createHTMLDocument,
createDocument, new Document()) have the UTF-8 encoding. We had no
per-document encoding at all: document.characterSet always reflected
the frame's charset, so the new document inherited windows-1252 from
the test page (which uses that encoding deliberately to catch this).
Document gains a _charset override (same pattern as _content_type),
set to UTF-8 in DOMImplementation.createHTMLDocument/createDocument
and the Document constructor.
- Node.resolveURL encoded the query string with the frame's charset.
Per the URL/HTML specs the query percent-encoding uses the encoding
of the element's node document, so it now resolves the owning
document and uses its encoding, falling back to the frame's.
Coverage:
- /dom/nodes/DOMImplementation-createHTMLDocument.html 12/13 -> 13/13
(fully green)
- /dom/nodes/Document-constructor.html 3/5 -> 4/5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Karl Seguin
parent
fd174986cf
commit
152f1eb8eb
@@ -50,6 +50,7 @@ pub fn createHTMLDocument(_: *const DOMImplementation, title: ?js.NullableString
|
||||
const document = (try frame._factory.document(Node.Document.HTMLDocument{ ._proto = undefined })).asDocument();
|
||||
document._ready_state = .complete;
|
||||
document._url = "about:blank";
|
||||
document._charset = "UTF-8";
|
||||
|
||||
{
|
||||
const doctype = try frame._factory.node(DocumentType{
|
||||
@@ -101,6 +102,7 @@ pub fn createDocument(_: *const DOMImplementation, namespace_nullable: js.Nullab
|
||||
// Create XML Document
|
||||
const document = (try frame._factory.document(Node.Document.XMLDocument{ ._proto = undefined })).asDocument();
|
||||
document._url = "about:blank";
|
||||
document._charset = "UTF-8";
|
||||
// Per spec the content type depends on the requested namespace.
|
||||
document._content_type = blk: {
|
||||
const ns = namespace_ orelse break :blk "application/xml";
|
||||
|
||||
@@ -56,6 +56,9 @@ _frame: ?*Frame = null,
|
||||
_url: ?[:0]const u8 = null, // URL for documents created via DOMImplementation (about:blank)
|
||||
// content type override for documents created via DOMImplementation.createDocument
|
||||
_content_type: ?[]const u8 = null,
|
||||
// encoding override: documents synthesized by script (createHTMLDocument,
|
||||
// createDocument) are UTF-8 regardless of the frame's encoding
|
||||
_charset: ?[]const u8 = null,
|
||||
_ready_state: ReadyState = .loading,
|
||||
_current_script: ?*Element.Html.Script = null,
|
||||
_elements_by_id: std.StringHashMapUnmanaged(*Element) = .empty,
|
||||
@@ -159,6 +162,14 @@ pub fn setLocation(self: *Document, url: [:0]const u8) !void {
|
||||
return frame.scheduleNavigation(url, .{ .reason = .script, .kind = .{ .push = null } }, .{ .script = frame });
|
||||
}
|
||||
|
||||
pub fn getCharset(self: *const Document) []const u8 {
|
||||
if (self._charset) |charset| {
|
||||
return charset;
|
||||
}
|
||||
const doc_frame = self._frame orelse return "UTF-8";
|
||||
return doc_frame.charset;
|
||||
}
|
||||
|
||||
pub fn getContentType(self: *const Document) []const u8 {
|
||||
if (self._content_type) |content_type| {
|
||||
return content_type;
|
||||
@@ -1417,6 +1428,7 @@ pub const JsApi = struct {
|
||||
return frame._factory.node(Document{
|
||||
._proto = undefined,
|
||||
._type = .generic,
|
||||
._charset = "UTF-8",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1508,8 +1520,7 @@ pub const JsApi = struct {
|
||||
pub const compatMode = bridge.property("CSS1Compat", .{ .template = false });
|
||||
|
||||
fn getCharacterSet(self: *const Document) []const u8 {
|
||||
const doc_frame = self._frame orelse return "UTF-8";
|
||||
return doc_frame.charset;
|
||||
return self.getCharset();
|
||||
}
|
||||
pub const referrer = bridge.property("", .{ .template = false });
|
||||
|
||||
|
||||
@@ -582,7 +582,11 @@ pub const ResolveURLOpts = struct {
|
||||
pub fn resolveURL(self: *const Node, url: anytype, frame: *Frame, opts: ResolveURLOpts) ![:0]const u8 {
|
||||
const owner_frame = self.ownerFrame(frame);
|
||||
const allocator = opts.allocator orelse frame.call_arena;
|
||||
return URL.resolve(allocator, owner_frame.base(), url, .{ .encoding = owner_frame.charset });
|
||||
// The owning document's encoding, not the frame's: script-created
|
||||
// documents (e.g. createHTMLDocument) are always UTF-8.
|
||||
const doc: ?*const Document = if (self._type == .document) self._type.document else self.ownerDocument(frame);
|
||||
const encoding = if (doc) |d| d.getCharset() else owner_frame.charset;
|
||||
return URL.resolve(allocator, owner_frame.base(), url, .{ .encoding = encoding });
|
||||
}
|
||||
|
||||
// Same as `resolveURL` but can't return `TypeError`, this is needed for multiple
|
||||
|
||||
Reference in New Issue
Block a user