diff --git a/src/browser/Page.zig b/src/browser/Page.zig index b5bc29af..253642fd 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -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 { diff --git a/src/browser/ScriptManager.zig b/src/browser/ScriptManager.zig index aa0b7dc6..b2b64b86 100644 --- a/src/browser/ScriptManager.zig +++ b/src/browser/ScriptManager.zig @@ -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(); diff --git a/src/browser/webapi/net/Fetch.zig b/src/browser/webapi/net/Fetch.zig index b5e3b384..98aaf1a4 100644 --- a/src/browser/webapi/net/Fetch.zig +++ b/src/browser/webapi/net/Fetch.zig @@ -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 { diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index a2dec743..c61a2760 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -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 { diff --git a/src/http/Client.zig b/src/http/Client.zig index c76a355e..a0f5ee81 100644 --- a/src/http/Client.zig +++ b/src/http/Client.zig @@ -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);