generate always an HTML on pageDoneCallback

Add also image support
This commit is contained in:
Pierre Tachoire
2026-02-17 10:31:47 +01:00
parent c7b414492d
commit 7505aec706

View File

@@ -708,7 +708,10 @@ fn pageDataCallback(transfer: *Http.Transfer, data: []const u8) !void {
try arr.appendSlice(self.arena, "<html><head><meta charset=\"utf-8\"></head><body><pre>"); try arr.appendSlice(self.arena, "<html><head><meta charset=\"utf-8\"></head><body><pre>");
self._parse_state = .{ .text = arr }; self._parse_state = .{ .text = arr };
}, },
else => self._parse_state = .{ .raw = .{} }, .image_jpeg, .image_gif, .image_png, .image_webp => {
self._parse_state = .{ .image = .empty };
},
else => self._parse_state = .{ .raw = .empty },
} }
} }
@@ -730,7 +733,7 @@ fn pageDataCallback(transfer: *Http.Transfer, data: []const u8) !void {
v = v[index + 1 ..]; v = v[index + 1 ..];
} }
}, },
.raw => |*buf| try buf.appendSlice(self.arena, data), .raw, .image => |*buf| try buf.appendSlice(self.arena, data),
.pre => unreachable, .pre => unreachable,
.complete => unreachable, .complete => unreachable,
.err => unreachable, .err => unreachable,
@@ -753,12 +756,13 @@ fn pageDoneCallback(ctx: *anyopaque) !void {
log.debug(.page, "page.load.complete", .{ .url = self.url }); log.debug(.page, "page.load.complete", .{ .url = self.url });
}; };
const parse_arena = try self.getArena(.{ .debug = "Page.parse" });
defer self.releaseArena(parse_arena);
var parser = Parser.init(parse_arena, self.document.asNode(), self);
switch (self._parse_state) { switch (self._parse_state) {
.html => |buf| { .html => |buf| {
const parse_arena = try self.getArena(.{ .debug = "Page.parse" });
defer self.releaseArena(parse_arena);
var parser = Parser.init(parse_arena, self.document.asNode(), self);
parser.parse(buf.items); parser.parse(buf.items);
self._script_manager.staticScriptsDone(); self._script_manager.staticScriptsDone();
if (self._script_manager.isDone()) { if (self._script_manager.isDone()) {
@@ -770,16 +774,26 @@ fn pageDoneCallback(ctx: *anyopaque) !void {
}, },
.text => |*buf| { .text => |*buf| {
try buf.appendSlice(self.arena, "</pre></body></html>"); try buf.appendSlice(self.arena, "</pre></body></html>");
const parse_arena = try self.getArena(.{ .debug = "Page.parse" });
defer self.releaseArena(parse_arena);
var parser = Parser.init(parse_arena, self.document.asNode(), self);
parser.parse(buf.items); parser.parse(buf.items);
self.documentIsComplete(); self.documentIsComplete();
}, },
.image => |buf| {
self._parse_state = .{ .raw_done = buf.items };
// Use empty an HTML containing the image.
const html = try std.mem.concat(parse_arena, u8, &.{
"<html><head><meta charset=\"utf-8\"></head><body><img src=\"",
self.url,
"\"></body></htm>",
});
parser.parse(html);
self.documentIsComplete();
},
.raw => |buf| { .raw => |buf| {
self._parse_state = .{ .raw_done = buf.items }; self._parse_state = .{ .raw_done = buf.items };
// Use empty an empty HTML document.
parser.parse("<html><head><meta charset=\"utf-8\"></head><body></body></htm>");
self.documentIsComplete(); self.documentIsComplete();
}, },
.pre => { .pre => {
@@ -787,20 +801,19 @@ fn pageDoneCallback(ctx: *anyopaque) !void {
// We assume we have received an OK status (checked in Client.headerCallback) // We assume we have received an OK status (checked in Client.headerCallback)
// so we load a blank document to navigate away from any prior page. // so we load a blank document to navigate away from any prior page.
self._parse_state = .{ .complete = {} }; self._parse_state = .{ .complete = {} };
// Use empty an empty HTML document.
parser.parse("<html><head><meta charset=\"utf-8\"></head><body></body></htm>");
self.documentIsComplete(); self.documentIsComplete();
}, },
.err => |err| { .err => |err| {
// Generate a pseudo HTML page indicating the failure. // Generate a pseudo HTML page indicating the failure.
const parse_arena = try self.getArena(.{ .debug = "Page.parse" }); const html = try std.mem.concat(parse_arena, u8, &.{
defer self.releaseArena(parse_arena);
const html = std.mem.concat(parse_arena, u8, &.{
"<html><head><meta charset=\"utf-8\"></head><body><h1>Navigation failed</h1><p>Reason: ", "<html><head><meta charset=\"utf-8\"></head><body><h1>Navigation failed</h1><p>Reason: ",
@errorName(err), @errorName(err),
"</p></body></htm>", "</p></body></htm>",
}) catch "<html><head><meta charset=\"utf-8\"></head><body><h1>Navigation failed</h1></body></htm>"; });
var parser = Parser.init(parse_arena, self.document.asNode(), self);
parser.parse(html); parser.parse(html);
self.documentIsComplete(); self.documentIsComplete();
}, },
@@ -880,7 +893,7 @@ fn _wait(self: *Page, wait_ms: u32) !Session.WaitResult {
while (true) { while (true) {
switch (self._parse_state) { switch (self._parse_state) {
.pre, .raw, .text => { .pre, .raw, .text, .image => {
// The main page hasn't started/finished navigating. // The main page hasn't started/finished navigating.
// There's no JS to run, and no reason to run the scheduler. // There's no JS to run, and no reason to run the scheduler.
if (http_client.active == 0 and exit_when_done) { if (http_client.active == 0 and exit_when_done) {
@@ -2848,6 +2861,7 @@ const ParseState = union(enum) {
err: anyerror, err: anyerror,
html: std.ArrayList(u8), html: std.ArrayList(u8),
text: std.ArrayList(u8), text: std.ArrayList(u8),
image: std.ArrayList(u8),
raw: std.ArrayList(u8), raw: std.ArrayList(u8),
raw_done: []const u8, raw_done: []const u8,
}; };