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)); var self: *Page = @ptrCast(@alignCast(transfer.ctx));
// would be different than self.url in the case of a redirect // 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(), .content_type = header.contentType(),
}); });
} }
return true;
} }
fn pageDataCallback(transfer: *Http.Transfer, data: []const u8) !void { 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 }); 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 self: *Script = @ptrCast(@alignCast(transfer.ctx));
const header = &transfer.response_header.?; const header = &transfer.response_header.?;
self.status = header.status; self.status = header.status;
@@ -673,7 +673,7 @@ pub const Script = struct {
.status = header.status, .status = header.status,
.content_type = header.contentType(), .content_type = header.contentType(),
}); });
return; return false;
} }
if (comptime IS_DEBUG) { if (comptime IS_DEBUG) {
@@ -694,6 +694,7 @@ pub const Script = struct {
try buffer.ensureTotalCapacity(self.manager.allocator, cl); try buffer.ensureTotalCapacity(self.manager.allocator, cl);
} }
self.source = .{ .remote = buffer }; self.source = .{ .remote = buffer };
return true;
} }
fn dataCallback(transfer: *Http.Transfer, data: []const u8) !void { fn dataCallback(transfer: *Http.Transfer, data: []const u8) !void {
@@ -733,7 +734,7 @@ pub const Script = struct {
log.warn(.http, "script fetch error", .{ log.warn(.http, "script fetch error", .{
.err = err, .err = err,
.req = self.url, .req = self.url,
.mode = self.mode, .mode = std.meta.activeTag(self.mode),
.kind = self.kind, .kind = self.kind,
.status = self.status, .status = self.status,
}); });
@@ -753,9 +754,13 @@ pub const Script = struct {
return; return;
} }
if (self.mode == .import) { switch (self.mode) {
const entry = self.manager.imported_modules.getPtr(self.url).?; .import_async => |ia| ia.callback(ia.data, error.FailedToLoad),
.import => {
const entry = manager.imported_modules.getPtr(self.url).?;
entry.state = .err; entry.state = .err;
},
else => {},
} }
self.deinit(true); self.deinit(true);
manager.evaluate(); 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)); const self: *Fetch = @ptrCast(@alignCast(transfer.ctx));
if (transfer.getContentLength()) |cl| { if (transfer.getContentLength()) |cl| {
@@ -133,6 +133,8 @@ fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void {
while (it.next()) |hdr| { while (it.next()) |hdr| {
try res._headers.append(hdr.name, hdr.value, self._page); try res._headers.append(hdr.name, hdr.value, self._page);
} }
return true;
} }
fn httpDataCallback(transfer: *Http.Transfer, data: []const u8) !void { 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); 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 self: *XMLHttpRequest = @ptrCast(@alignCast(transfer.ctx));
const header = &transfer.response_header.?; const header = &transfer.response_header.?;
@@ -305,7 +305,8 @@ fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void {
if (header.contentType()) |ct| { if (header.contentType()) |ct| {
self._response_mime = Mime.parse(ct) catch |e| { 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.stateChanged(.headers_received, local, page);
try self._proto.dispatch(.load_start, .{ .loaded = 0, .total = self._response_len orelse 0 }, local, page); try self._proto.dispatch(.load_start, .{ .loaded = 0, .total = self._response_len orelse 0 }, local, page);
try self.stateChanged(.loading, local, page); try self.stateChanged(.loading, local, page);
return true;
} }
fn httpDataCallback(transfer: *Http.Transfer, data: []const u8) !void { fn httpDataCallback(transfer: *Http.Transfer, data: []const u8) !void {

View File

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