Merge pull request #1398 from lightpanda-io/handle_non_200_scripts

Handle scripts that don't return a 200 status code
This commit is contained in:
Karl Seguin
2026-01-24 07:39:19 +08:00
committed by GitHub
5 changed files with 45 additions and 20 deletions

View File

@@ -590,7 +590,7 @@ fn _documentIsComplete(self: *Page) !void {
);
}
fn pageHeaderDoneCallback(transfer: *Http.Transfer) !void {
fn pageHeaderDoneCallback(transfer: *Http.Transfer) !bool {
var self: *Page = @ptrCast(@alignCast(transfer.ctx));
// would be different than self.url in the case of a redirect
@@ -607,6 +607,8 @@ fn pageHeaderDoneCallback(transfer: *Http.Transfer) !void {
.content_type = header.contentType(),
});
}
return true;
}
fn pageDataCallback(transfer: *Http.Transfer, data: []const u8) !void {

View File

@@ -663,7 +663,7 @@ pub const Script = struct {
log.debug(.http, "script fetch start", .{ .req = transfer });
}
fn headerCallback(transfer: *Http.Transfer) !void {
fn headerCallback(transfer: *Http.Transfer) !bool {
const self: *Script = @ptrCast(@alignCast(transfer.ctx));
const header = &transfer.response_header.?;
self.status = header.status;
@@ -673,7 +673,7 @@ pub const Script = struct {
.status = header.status,
.content_type = header.contentType(),
});
return;
return false;
}
if (comptime IS_DEBUG) {
@@ -694,6 +694,7 @@ pub const Script = struct {
try buffer.ensureTotalCapacity(self.manager.allocator, cl);
}
self.source = .{ .remote = buffer };
return true;
}
fn dataCallback(transfer: *Http.Transfer, data: []const u8) !void {
@@ -733,7 +734,7 @@ pub const Script = struct {
log.warn(.http, "script fetch error", .{
.err = err,
.req = self.url,
.mode = self.mode,
.mode = std.meta.activeTag(self.mode),
.kind = self.kind,
.status = self.status,
});
@@ -753,9 +754,13 @@ pub const Script = struct {
return;
}
if (self.mode == .import) {
const entry = self.manager.imported_modules.getPtr(self.url).?;
entry.state = .err;
switch (self.mode) {
.import_async => |ia| ia.callback(ia.data, error.FailedToLoad),
.import => {
const entry = manager.imported_modules.getPtr(self.url).?;
entry.state = .err;
},
else => {},
}
self.deinit(true);
manager.evaluate();

View File

@@ -89,7 +89,7 @@ pub fn deinit(self: *Fetch) void {
}
}
fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void {
fn httpHeaderDoneCallback(transfer: *Http.Transfer) !bool {
const self: *Fetch = @ptrCast(@alignCast(transfer.ctx));
if (transfer.getContentLength()) |cl| {
@@ -133,6 +133,8 @@ fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void {
while (it.next()) |hdr| {
try res._headers.append(hdr.name, hdr.value, self._page);
}
return true;
}
fn httpDataCallback(transfer: *Http.Transfer, data: []const u8) !void {

View File

@@ -290,7 +290,7 @@ fn httpHeaderCallback(transfer: *Http.Transfer, header: Http.Header) !void {
try self._response_headers.append(self._arena, joined);
}
fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void {
fn httpHeaderDoneCallback(transfer: *Http.Transfer) !bool {
const self: *XMLHttpRequest = @ptrCast(@alignCast(transfer.ctx));
const header = &transfer.response_header.?;
@@ -305,7 +305,8 @@ fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void {
if (header.contentType()) |ct| {
self._response_mime = Mime.parse(ct) catch |e| {
return self.handleError(e);
log.info(.http, "invalid content type", .{.content_Type = ct, .err = e, .url = self._url,});
return false;
};
}
@@ -332,6 +333,8 @@ fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void {
try self.stateChanged(.headers_received, local, page);
try self._proto.dispatch(.load_start, .{ .loaded = 0, .total = self._response_len orelse 0 }, local, page);
try self.stateChanged(.loading, local, page);
return true;
}
fn httpDataCallback(transfer: *Http.Transfer, data: []const u8) !void {

View File

@@ -594,15 +594,19 @@ fn processMessages(self: *Client) !bool {
defer transfer.deinit();
if (errorCheck(msg.data.result)) {
if (errorCheck(msg.data.result)) blk: {
// In case of request w/o data, we need to call the header done
// callback now.
if (!transfer._header_done_called) {
transfer.headerDoneCallback(easy) catch |err| {
const proceed = transfer.headerDoneCallback(easy) catch |err| {
log.err(.http, "header_done_callback", .{ .err = err });
self.requestFailed(transfer, err);
continue;
};
if (!proceed) {
self.requestFailed(transfer, error.Abort);
break :blk;
}
}
transfer.req.done_callback(transfer.ctx) catch |err| {
// transfer isn't valid at this point, don't use it.
@@ -771,7 +775,7 @@ pub const Request = struct {
ctx: *anyopaque = undefined,
start_callback: ?*const fn (transfer: *Transfer) anyerror!void = null,
header_callback: *const fn (transfer: *Transfer) anyerror!void,
header_callback: *const fn (transfer: *Transfer) anyerror!bool,
data_callback: *const fn (transfer: *Transfer, data: []const u8) anyerror!void,
done_callback: *const fn (ctx: *anyopaque) anyerror!void,
error_callback: *const fn (ctx: *anyopaque, err: anyerror) void,
@@ -1042,7 +1046,7 @@ pub const Transfer = struct {
// headerDoneCallback is called once the headers have been read.
// It can be called either on dataCallback or once the request for those
// w/o body.
fn headerDoneCallback(transfer: *Transfer, easy: *c.CURL) !void {
fn headerDoneCallback(transfer: *Transfer, easy: *c.CURL) !bool {
if (comptime IS_DEBUG) {
std.debug.assert(transfer._header_done_called == false);
}
@@ -1070,7 +1074,7 @@ pub const Transfer = struct {
if (i >= ct.?.amount) break;
}
transfer.req.header_callback(transfer) catch |err| {
const proceed = transfer.req.header_callback(transfer) catch |err| {
log.err(.http, "header_callback", .{ .err = err, .req = transfer });
return err;
};
@@ -1080,6 +1084,8 @@ pub const Transfer = struct {
.transfer = transfer,
});
}
return proceed;
}
// headerCallback is called by curl on each request's header line read.
@@ -1193,7 +1199,7 @@ pub const Transfer = struct {
return buf_len;
}
fn dataCallback(buffer: [*]const u8, chunk_count: usize, chunk_len: usize, data: *anyopaque) callconv(.c) usize {
fn dataCallback(buffer: [*]const u8, chunk_count: usize, chunk_len: usize, data: *anyopaque) callconv(.c) isize {
// libcurl should only ever emit 1 chunk at a time
if (comptime IS_DEBUG) {
std.debug.assert(chunk_count == 1);
@@ -1206,14 +1212,18 @@ pub const Transfer = struct {
};
if (transfer._redirecting or transfer._auth_challenge != null) {
return chunk_len;
return @intCast(chunk_len);
}
if (!transfer._header_done_called) {
transfer.headerDoneCallback(easy) catch |err| {
const proceed = transfer.headerDoneCallback(easy) catch |err| {
log.err(.http, "header_done_callback", .{ .err = err, .req = transfer });
return c.CURL_WRITEFUNC_ERROR;
};
if (!proceed) {
// signal abort to libcurl
return -1;
}
}
transfer.bytes_received += chunk_len;
@@ -1230,7 +1240,7 @@ pub const Transfer = struct {
});
}
return chunk_len;
return @intCast(chunk_len);
}
pub fn responseHeaderIterator(self: *Transfer) HeaderIterator {
@@ -1288,7 +1298,10 @@ pub const Transfer = struct {
}
}
try req.header_callback(transfer);
if (try req.header_callback(transfer) == false) {
transfer.abort(error.Abort);
return;
}
if (body) |b| {
try req.data_callback(transfer, b);