Merge pull request #1711 from lightpanda-io/iframe_about_blank

iframe handling for src = "about:blank"
This commit is contained in:
Karl Seguin
2026-03-04 15:56:26 +08:00
committed by GitHub
3 changed files with 46 additions and 21 deletions

View File

@@ -463,8 +463,12 @@ pub fn navigate(self: *Page, request_url: [:0]const u8, opts: NavigateOpts) !voi
// It's important to force a reset during the following navigation.
self._parse_state = .complete;
// We do not processHTMLDoc here as we know we don't have any scripts
// This assumption may be false when CDP Page.addScriptToEvaluateOnNewDocument is implemented
{
const parse_arena = try self.getArena(.{ .debug = "about:blank parse" });
defer self.releaseArena(parse_arena);
var parser = Parser.init(parse_arena, self.document.asNode(), self);
parser.parse("<html><head></head><body></body></html>");
}
self.documentIsComplete();
session.notification.dispatch(.page_navigate, &.{
@@ -710,18 +714,19 @@ pub fn documentIsComplete(self: *Page) void {
log.err(.page, "document is complete", .{ .err = err, .type = self._type, .url = self.url });
};
if (IS_DEBUG) {
std.debug.assert(self._navigated_options != null);
}
if (self._navigated_options) |no| {
// _navigated_options will be null in special short-circuit cases, like
// "navigating" to about:blank, in which case this notification has
// already been sent
self._session.notification.dispatch(.page_navigated, &.{
.frame_id = self._frame_id,
.req_id = self._req_id,
.opts = self._navigated_options.?,
.opts = no,
.url = self.url,
.timestamp = timestamp(.monotonic),
});
}
}
fn _documentIsComplete(self: *Page) !void {
self.document._ready_state = .complete;
@@ -1001,13 +1006,17 @@ pub fn iframeAddedCallback(self: *Page, iframe: *Element.Html.IFrame) !void {
iframe._content_window = page_frame.window;
errdefer iframe._content_window = null;
// navigate will dupe the url
const url = try URL.resolve(
self.call_arena,
const url = blk: {
if (std.mem.eql(u8, src, "about:blank")) {
break :blk "about:blank"; // navigate will handle this special case
}
break :blk try URL.resolve(
self.call_arena, // ok to use, page.navigate dupes this
self.base(),
src,
.{ .encode = true },
);
};
if (existing_window == null) {
// on first load, dispatch frame_created evnet
@@ -2520,7 +2529,7 @@ pub fn insertNodeRelative(self: *Page, parent: *Node, child: *Node, relative: In
pub fn _insertNodeRelative(self: *Page, comptime from_parser: bool, parent: *Node, child: *Node, relative: InsertNodeRelative, opts: InsertNodeOpts) !void {
// caller should have made sure this was the case
lp.assert(child._parent == null, "Page.insertNodeRelative parent", .{ .url = self.url });
lp.assert(child._parent == null, "Page.insertNodeRelative parent", .{});
const children = blk: {
// expand parent._children so that it can take another child

View File

@@ -961,6 +961,10 @@ test "URL: ensureEncoded" {
.url = "https://example.com/path?value=100% done",
.expected = "https://example.com/path?value=100%25%20done",
},
.{
.url = "about:blank",
.expected = "about:blank",
},
};
for (cases) |case| {

View File

@@ -75,8 +75,20 @@
}
</script>
<script id=onload>
{
let f4 = document.createElement('iframe');
f4.src = "about:blank";
document.documentElement.appendChild(f4);
testing.eventually(() => {
testing.expectEqual("<html><head></head><body></body></html>", f4.contentDocument.documentElement.outerHTML);
});
}
</script>
<script id=count>
testing.eventually(() => {
testing.expectEqual(3, window.length);
testing.expectEqual(4, window.length);
});
</script>