Move all curl_easy ops to Connection

This commit is contained in:
Nikolay Govorov
2026-02-24 03:45:43 +00:00
parent 5fea1df42b
commit 29982e2caf
4 changed files with 611 additions and 576 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,7 @@ const lp = @import("lightpanda");
const log = @import("../log.zig"); const log = @import("../log.zig");
const builtin = @import("builtin"); const builtin = @import("builtin");
const Http = @import("Http.zig"); const Net = @import("../Net.zig");
const Config = @import("../Config.zig"); const Config = @import("../Config.zig");
const URL = @import("../browser/URL.zig"); const URL = @import("../browser/URL.zig");
const Notification = @import("../Notification.zig"); const Notification = @import("../Notification.zig");
@@ -30,18 +30,20 @@ const CookieJar = @import("../browser/webapi/storage/Cookie.zig").Jar;
const Robots = @import("../browser/Robots.zig"); const Robots = @import("../browser/Robots.zig");
const RobotStore = Robots.RobotStore; const RobotStore = Robots.RobotStore;
const c = Http.c; const c = Net.c;
const posix = std.posix; const posix = std.posix;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator; const ArenaAllocator = std.heap.ArenaAllocator;
const errorCheck = Http.errorCheck;
const errorMCheck = Http.errorMCheck;
const IS_DEBUG = builtin.mode == .Debug; const IS_DEBUG = builtin.mode == .Debug;
const Method = Http.Method; const errorCheck = Net.errorCheck;
const errorMCheck = Net.errorMCheck;
const Method = Net.Method;
const ResponseHead = Net.ResponseHead;
const HeaderIterator = Net.HeaderIterator;
// This is loosely tied to a browser Page. Loading all the <scripts>, doing // This is loosely tied to a browser Page. Loading all the <scripts>, doing
// XHR requests, and loading imports all happens through here. Sine the app // XHR requests, and loading imports all happens through here. Sine the app
@@ -186,14 +188,14 @@ pub fn deinit(self: *Client) void {
self.allocator.destroy(self); self.allocator.destroy(self);
} }
pub fn newHeaders(self: *const Client) !Http.Headers { pub fn newHeaders(self: *const Client) !Net.Headers {
return Http.Headers.init(self.config.http_headers.user_agent_header); return Net.Headers.init(self.config.http_headers.user_agent_header);
} }
pub fn abort(self: *Client) void { pub fn abort(self: *Client) void {
while (self.handles.in_use.first) |node| { while (self.handles.in_use.first) |node| {
const handle: *Handle = @fieldParentPtr("node", node); const handle: *Handle = @fieldParentPtr("node", node);
var transfer = Transfer.fromEasy(handle.conn.easy) catch |err| { var transfer = Transfer.fromConnection(&handle.conn) catch |err| {
log.err(.http, "get private info", .{ .err = err, .source = "abort" }); log.err(.http, "get private info", .{ .err = err, .source = "abort" });
continue; continue;
}; };
@@ -354,7 +356,7 @@ fn fetchRobotsThenProcessRequest(self: *Client, robots_url: [:0]const u8, req: R
try entry.value_ptr.append(self.allocator, req); try entry.value_ptr.append(self.allocator, req);
} }
fn robotsHeaderCallback(transfer: *Http.Transfer) !bool { fn robotsHeaderCallback(transfer: *Transfer) !bool {
const ctx: *RobotsRequestContext = @ptrCast(@alignCast(transfer.ctx)); const ctx: *RobotsRequestContext = @ptrCast(@alignCast(transfer.ctx));
if (transfer.response_header) |hdr| { if (transfer.response_header) |hdr| {
@@ -369,7 +371,7 @@ fn robotsHeaderCallback(transfer: *Http.Transfer) !bool {
return true; return true;
} }
fn robotsDataCallback(transfer: *Http.Transfer, data: []const u8) !void { fn robotsDataCallback(transfer: *Transfer, data: []const u8) !void {
const ctx: *RobotsRequestContext = @ptrCast(@alignCast(transfer.ctx)); const ctx: *RobotsRequestContext = @ptrCast(@alignCast(transfer.ctx));
try ctx.buffer.appendSlice(ctx.client.allocator, data); try ctx.buffer.appendSlice(ctx.client.allocator, data);
} }
@@ -548,7 +550,7 @@ pub fn abortTransfer(self: *Client, transfer: *Transfer) void {
} }
// For an intercepted request // For an intercepted request
pub fn fulfillTransfer(self: *Client, transfer: *Transfer, status: u16, headers: []const Http.Header, body: ?[]const u8) !void { pub fn fulfillTransfer(self: *Client, transfer: *Transfer, status: u16, headers: []const Net.Header, body: ?[]const u8) !void {
if (comptime IS_DEBUG) { if (comptime IS_DEBUG) {
std.debug.assert(transfer._intercept_state != .not_intercepted); std.debug.assert(transfer._intercept_state != .not_intercepted);
log.debug(.http, "filfull transfer", .{ .intercepted = self.intercepted }); log.debug(.http, "filfull transfer", .{ .intercepted = self.intercepted });
@@ -627,7 +629,7 @@ pub fn changeProxy(self: *Client, proxy: [:0]const u8) !void {
try self.ensureNoActiveConnection(); try self.ensureNoActiveConnection();
for (self.handles.handles) |*h| { for (self.handles.handles) |*h| {
try errorCheck(c.curl_easy_setopt(h.conn.easy, c.CURLOPT_PROXY, proxy.ptr)); try h.conn.setProxy(proxy.ptr);
} }
self.use_proxy = true; self.use_proxy = true;
} }
@@ -639,7 +641,7 @@ pub fn restoreOriginalProxy(self: *Client) !void {
const proxy = if (self.http_proxy) |p| p.ptr else null; const proxy = if (self.http_proxy) |p| p.ptr else null;
for (self.handles.handles) |*h| { for (self.handles.handles) |*h| {
try errorCheck(c.curl_easy_setopt(h.conn.easy, c.CURLOPT_PROXY, proxy)); try h.conn.setProxy(proxy);
} }
self.use_proxy = proxy != null; self.use_proxy = proxy != null;
} }
@@ -650,15 +652,7 @@ pub fn enableTlsVerify(self: *const Client) !void {
// the command during navigate and Curl seems to accept it... // the command during navigate and Curl seems to accept it...
for (self.handles.handles) |*h| { for (self.handles.handles) |*h| {
const easy = h.conn.easy; try h.conn.setTlsVerify(true, self.use_proxy);
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYHOST, @as(c_long, 2)));
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYPEER, @as(c_long, 1)));
if (self.use_proxy) {
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXY_SSL_VERIFYHOST, @as(c_long, 2)));
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXY_SSL_VERIFYPEER, @as(c_long, 1)));
}
} }
} }
@@ -668,21 +662,12 @@ pub fn disableTlsVerify(self: *const Client) !void {
// the command during navigate and Curl seems to accept it... // the command during navigate and Curl seems to accept it...
for (self.handles.handles) |*h| { for (self.handles.handles) |*h| {
const easy = h.conn.easy; try h.conn.setTlsVerify(false, self.use_proxy);
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYHOST, @as(c_long, 0)));
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYPEER, @as(c_long, 0)));
if (self.use_proxy) {
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXY_SSL_VERIFYHOST, @as(c_long, 0)));
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXY_SSL_VERIFYPEER, @as(c_long, 0)));
}
} }
} }
fn makeRequest(self: *Client, handle: *Handle, transfer: *Transfer) anyerror!void { fn makeRequest(self: *Client, handle: *Handle, transfer: *Transfer) anyerror!void {
const conn = handle.conn; const conn = &handle.conn;
const easy = conn.easy;
const req = &transfer.req; const req = &transfer.req;
{ {
@@ -694,23 +679,23 @@ fn makeRequest(self: *Client, handle: *Handle, transfer: *Transfer) anyerror!voi
if (req.body) |b| { if (req.body) |b| {
try conn.setBody(b); try conn.setBody(b);
} else { } else {
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HTTPGET, @as(c_long, 1))); try conn.setGetMode();
} }
var header_list = req.headers; var header_list = req.headers;
try conn.secretHeaders(&header_list); // Add headers that must be hidden from intercepts try conn.secretHeaders(&header_list, &self.config.http_headers); // Add headers that must be hidden from intercepts
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HTTPHEADER, header_list.headers)); try conn.setHeaders(&header_list);
// Add cookies. // Add cookies.
if (header_list.cookies) |cookies| { if (header_list.cookies) |cookies| {
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIE, cookies)); try conn.setCookies(cookies);
} }
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PRIVATE, transfer)); try conn.setPrivate(transfer);
// add credentials // add credentials
if (req.credentials) |creds| { if (req.credentials) |creds| {
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXYUSERPWD, creds.ptr)); try conn.setProxyCredentials(creds);
} }
} }
@@ -719,11 +704,11 @@ fn makeRequest(self: *Client, handle: *Handle, transfer: *Transfer) anyerror!voi
// fails BEFORE `curl_multi_add_handle` suceeds, the we still need to do // fails BEFORE `curl_multi_add_handle` suceeds, the we still need to do
// cleanup. But if things fail after `curl_multi_add_handle`, we expect // cleanup. But if things fail after `curl_multi_add_handle`, we expect
// perfom to pickup the failure and cleanup. // perfom to pickup the failure and cleanup.
try errorMCheck(c.curl_multi_add_handle(self.multi, easy)); try errorMCheck(c.curl_multi_add_handle(self.multi, conn.easy));
if (req.start_callback) |cb| { if (req.start_callback) |cb| {
cb(transfer) catch |err| { cb(transfer) catch |err| {
try errorMCheck(c.curl_multi_remove_handle(self.multi, easy)); try errorMCheck(c.curl_multi_remove_handle(self.multi, conn.easy));
transfer.deinit(); transfer.deinit();
return err; return err;
}; };
@@ -786,7 +771,8 @@ fn processMessages(self: *Client) !bool {
} }
const easy = msg.easy_handle.?; const easy = msg.easy_handle.?;
const transfer = try Transfer.fromEasy(easy); const conn: Net.Connection = .{ .easy = easy };
const transfer = try Transfer.fromConnection(&conn);
// In case of auth challenge // In case of auth challenge
// TODO give a way to configure the number of auth retries. // TODO give a way to configure the number of auth retries.
@@ -840,7 +826,7 @@ fn processMessages(self: *Client) !bool {
// 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) {
const proceed = transfer.headerDoneCallback(easy) catch |err| { const proceed = transfer.headerDoneCallback(&conn) catch |err| {
log.err(.http, "header_done_callback", .{ .err = err }); log.err(.http, "header_done_callback", .{ .err = err });
requestFailed(transfer, err, true); requestFailed(transfer, err, true);
continue; continue;
@@ -951,7 +937,7 @@ const Handles = struct {
// wraps a c.CURL (an easy handle) // wraps a c.CURL (an easy handle)
pub const Handle = struct { pub const Handle = struct {
client: *Client, client: *Client,
conn: Http.Connection, conn: Net.Connection,
node: Handles.HandleList.Node, node: Handles.HandleList.Node,
fn init( fn init(
@@ -959,16 +945,11 @@ pub const Handle = struct {
ca_blob: ?c.curl_blob, ca_blob: ?c.curl_blob,
config: *const Config, config: *const Config,
) !Handle { ) !Handle {
const conn = try Http.Connection.init(ca_blob, config); var conn = try Net.Connection.init(ca_blob, config);
errdefer conn.deinit(); errdefer conn.deinit();
const easy = conn.easy;
// callbacks // callbacks
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HEADERDATA, easy)); try conn.setCallbacks(Transfer.headerCallback, Transfer.dataCallback);
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HEADERFUNCTION, Transfer.headerCallback));
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_WRITEDATA, easy));
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_WRITEFUNCTION, Transfer.dataCallback));
return .{ return .{
.node = .{}, .node = .{},
@@ -988,7 +969,7 @@ pub const RequestCookie = struct {
is_navigation: bool, is_navigation: bool,
origin: [:0]const u8, origin: [:0]const u8,
pub fn headersForRequest(self: *const RequestCookie, temp: Allocator, url: [:0]const u8, headers: *Http.Headers) !void { pub fn headersForRequest(self: *const RequestCookie, temp: Allocator, url: [:0]const u8, headers: *Net.Headers) !void {
var arr: std.ArrayList(u8) = .{}; var arr: std.ArrayList(u8) = .{};
try self.jar.forRequest(url, arr.writer(temp), .{ try self.jar.forRequest(url, arr.writer(temp), .{
.is_http = self.is_http, .is_http = self.is_http,
@@ -1007,7 +988,7 @@ pub const Request = struct {
page_id: u32, page_id: u32,
method: Method, method: Method,
url: [:0]const u8, url: [:0]const u8,
headers: Http.Headers, headers: Net.Headers,
body: ?[]const u8 = null, body: ?[]const u8 = null,
cookie_jar: ?*CookieJar, cookie_jar: ?*CookieJar,
resource_type: ResourceType, resource_type: ResourceType,
@@ -1053,7 +1034,7 @@ pub const Request = struct {
}; };
}; };
pub const AuthChallenge = @import("../Net.zig").AuthChallenge; const AuthChallenge = Net.AuthChallenge;
pub const Transfer = struct { pub const Transfer = struct {
arena: ArenaAllocator, arena: ArenaAllocator,
@@ -1071,7 +1052,7 @@ pub const Transfer = struct {
max_response_size: ?usize = null, max_response_size: ?usize = null,
// We'll store the response header here // We'll store the response header here
response_header: ?ResponseHeader = null, response_header: ?ResponseHead = null,
// track if the header callbacks done have been called. // track if the header callbacks done have been called.
_header_done_called: bool = false, _header_done_called: bool = false,
@@ -1128,34 +1109,28 @@ pub const Transfer = struct {
self.client.transfer_pool.destroy(self); self.client.transfer_pool.destroy(self);
} }
fn buildResponseHeader(self: *Transfer, easy: *c.CURL) !void { fn buildResponseHeader(self: *Transfer, conn: *const Net.Connection) !void {
if (comptime IS_DEBUG) { if (comptime IS_DEBUG) {
std.debug.assert(self.response_header == null); std.debug.assert(self.response_header == null);
} }
var url: [*c]u8 = undefined; const url = try conn.getEffectiveUrl();
try errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_EFFECTIVE_URL, &url));
var status: c_long = undefined; const status: u16 = if (self._auth_challenge != null)
if (self._auth_challenge) |_| { 407
status = 407; else
} else { try conn.getResponseCode();
try errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_RESPONSE_CODE, &status));
}
var redirect_count: c_long = undefined;
try errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_REDIRECT_COUNT, &redirect_count));
self.response_header = .{ self.response_header = .{
.url = url, .url = url,
.status = @intCast(status), .status = status,
.redirect_count = @intCast(redirect_count), .redirect_count = try conn.getRedirectCount(),
}; };
if (getResponseHeader(easy, "content-type", 0)) |ct| { if (conn.getResponseHeader("content-type", 0)) |ct| {
var hdr = &self.response_header.?; var hdr = &self.response_header.?;
const value = ct.value; const value = ct.value;
const len = @min(value.len, ResponseHeader.MAX_CONTENT_TYPE_LEN); const len = @min(value.len, ResponseHead.MAX_CONTENT_TYPE_LEN);
hdr._content_type_len = len; hdr._content_type_len = len;
@memcpy(hdr._content_type[0..len], value[0..len]); @memcpy(hdr._content_type[0..len], value[0..len]);
} }
@@ -1182,7 +1157,7 @@ pub const Transfer = struct {
self.req.credentials = userpwd; self.req.credentials = userpwd;
} }
pub fn replaceRequestHeaders(self: *Transfer, allocator: Allocator, headers: []const Http.Header) !void { pub fn replaceRequestHeaders(self: *Transfer, allocator: Allocator, headers: []const Net.Header) !void {
self.req.headers.deinit(); self.req.headers.deinit();
var buf: std.ArrayList(u8) = .empty; var buf: std.ArrayList(u8) = .empty;
@@ -1261,7 +1236,7 @@ pub const Transfer = struct {
// redirectionCookies manages cookies during redirections handled by Curl. // redirectionCookies manages cookies during redirections handled by Curl.
// It sets the cookies from the current response to the cookie jar. // It sets the cookies from the current response to the cookie jar.
// It also immediately sets cookies for the following request. // It also immediately sets cookies for the following request.
fn redirectionCookies(transfer: *Transfer, easy: *c.CURL) !void { fn redirectionCookies(transfer: *Transfer, conn: *const Net.Connection) !void {
const req = &transfer.req; const req = &transfer.req;
const arena = transfer.arena.allocator(); const arena = transfer.arena.allocator();
@@ -1269,7 +1244,7 @@ pub const Transfer = struct {
if (req.cookie_jar) |jar| { if (req.cookie_jar) |jar| {
var i: usize = 0; var i: usize = 0;
while (true) { while (true) {
const ct = getResponseHeader(easy, "set-cookie", i); const ct = conn.getResponseHeader("set-cookie", i);
if (ct == null) break; if (ct == null) break;
try jar.populateFromResponse(transfer.url, ct.?.value); try jar.populateFromResponse(transfer.url, ct.?.value);
i += 1; i += 1;
@@ -1278,12 +1253,11 @@ pub const Transfer = struct {
} }
// set cookies for the following redirection's request. // set cookies for the following redirection's request.
const location = getResponseHeader(easy, "location", 0) orelse { const location = conn.getResponseHeader("location", 0) orelse {
return error.LocationNotFound; return error.LocationNotFound;
}; };
var base_url: [*c]u8 = undefined; const base_url = try conn.getEffectiveUrl();
try errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_EFFECTIVE_URL, &base_url));
const url = try URL.resolve(arena, std.mem.span(base_url), location.value, .{}); const url = try URL.resolve(arena, std.mem.span(base_url), location.value, .{});
transfer.url = url; transfer.url = url;
@@ -1297,23 +1271,23 @@ pub const Transfer = struct {
.is_navigation = req.resource_type == .document, .is_navigation = req.resource_type == .document,
}); });
try cookies.append(arena, 0); //null terminate try cookies.append(arena, 0); //null terminate
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIE, @as([*c]const u8, @ptrCast(cookies.items.ptr)))); try conn.setCookies(@ptrCast(cookies.items.ptr));
} }
} }
// 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) !bool { fn headerDoneCallback(transfer: *Transfer, conn: *const Net.Connection) !bool {
lp.assert(transfer._header_done_called == false, "Transfer.headerDoneCallback", .{}); lp.assert(transfer._header_done_called == false, "Transfer.headerDoneCallback", .{});
defer transfer._header_done_called = true; defer transfer._header_done_called = true;
try transfer.buildResponseHeader(easy); try transfer.buildResponseHeader(conn);
if (getResponseHeader(easy, "content-type", 0)) |ct| { if (conn.getResponseHeader("content-type", 0)) |ct| {
var hdr = &transfer.response_header.?; var hdr = &transfer.response_header.?;
const value = ct.value; const value = ct.value;
const len = @min(value.len, ResponseHeader.MAX_CONTENT_TYPE_LEN); const len = @min(value.len, ResponseHead.MAX_CONTENT_TYPE_LEN);
hdr._content_type_len = len; hdr._content_type_len = len;
@memcpy(hdr._content_type[0..len], value[0..len]); @memcpy(hdr._content_type[0..len], value[0..len]);
} }
@@ -1321,7 +1295,7 @@ pub const Transfer = struct {
if (transfer.req.cookie_jar) |jar| { if (transfer.req.cookie_jar) |jar| {
var i: usize = 0; var i: usize = 0;
while (true) { while (true) {
const ct = getResponseHeader(easy, "set-cookie", i); const ct = conn.getResponseHeader("set-cookie", i);
if (ct == null) break; if (ct == null) break;
jar.populateFromResponse(transfer.url, ct.?.value) catch |err| { jar.populateFromResponse(transfer.url, ct.?.value) catch |err| {
log.err(.http, "set cookie", .{ .err = err, .req = transfer }); log.err(.http, "set cookie", .{ .err = err, .req = transfer });
@@ -1359,8 +1333,8 @@ pub const Transfer = struct {
std.debug.assert(header_count == 1); std.debug.assert(header_count == 1);
} }
const easy: *c.CURL = @ptrCast(@alignCast(data)); const conn: Net.Connection = .{ .easy = @ptrCast(@alignCast(data)) };
var transfer = fromEasy(easy) catch |err| { var transfer = fromConnection(&conn) catch |err| {
log.err(.http, "get private info", .{ .err = err, .source = "header callback" }); log.err(.http, "get private info", .{ .err = err, .source = "header callback" });
return 0; return 0;
}; };
@@ -1463,7 +1437,7 @@ pub const Transfer = struct {
if (transfer._redirecting) { if (transfer._redirecting) {
// parse and set cookies for the redirection. // parse and set cookies for the redirection.
redirectionCookies(transfer, easy) catch |err| { redirectionCookies(transfer, &conn) catch |err| {
if (comptime IS_DEBUG) { if (comptime IS_DEBUG) {
log.debug(.http, "redirection cookies", .{ .err = err }); log.debug(.http, "redirection cookies", .{ .err = err });
} }
@@ -1481,8 +1455,8 @@ pub const Transfer = struct {
std.debug.assert(chunk_count == 1); std.debug.assert(chunk_count == 1);
} }
const easy: *c.CURL = @ptrCast(@alignCast(data)); const conn: Net.Connection = .{ .easy = @ptrCast(@alignCast(data)) };
var transfer = fromEasy(easy) catch |err| { var transfer = fromConnection(&conn) catch |err| {
log.err(.http, "get private info", .{ .err = err, .source = "body callback" }); log.err(.http, "get private info", .{ .err = err, .source = "body callback" });
return c.CURL_WRITEFUNC_ERROR; return c.CURL_WRITEFUNC_ERROR;
}; };
@@ -1492,7 +1466,7 @@ pub const Transfer = struct {
} }
if (!transfer._header_done_called) { if (!transfer._header_done_called) {
const proceed = transfer.headerDoneCallback(easy) catch |err| { const proceed = transfer.headerDoneCallback(&conn) 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;
}; };
@@ -1532,7 +1506,7 @@ pub const Transfer = struct {
if (self._handle) |handle| { if (self._handle) |handle| {
// If we have a handle, than this is a real curl request and we // If we have a handle, than this is a real curl request and we
// iterate through the header that curl maintains. // iterate through the header that curl maintains.
return .{ .curl = .{ .easy = handle.conn.easy } }; return .{ .curl = .{ .conn = &handle.conn } };
} }
// If there's no handle, it either means this is being called before // If there's no handle, it either means this is being called before
// the request is even being made (which would be a bug in the code) // the request is even being made (which would be a bug in the code)
@@ -1541,14 +1515,18 @@ pub const Transfer = struct {
return .{ .list = .{ .list = self.response_header.?._injected_headers } }; return .{ .list = .{ .list = self.response_header.?._injected_headers } };
} }
// pub because Page.printWaitAnalysis uses it pub fn fromConnection(conn: *const Net.Connection) !*Transfer {
pub fn fromEasy(easy: *c.CURL) !*Transfer { const private = try conn.getPrivate();
var private: *anyopaque = undefined;
try errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_PRIVATE, &private));
return @ptrCast(@alignCast(private)); return @ptrCast(@alignCast(private));
} }
pub fn fulfill(transfer: *Transfer, status: u16, headers: []const Http.Header, body: ?[]const u8) !void { // pub because Page.printWaitAnalysis uses it
pub fn fromEasy(easy: *c.CURL) !*Transfer {
const conn: Net.Connection = .{ .easy = easy };
return fromConnection(&conn);
}
pub fn fulfill(transfer: *Transfer, status: u16, headers: []const Net.Header, body: ?[]const u8) !void {
if (transfer._handle != null) { if (transfer._handle != null) {
// should never happen, should have been intercepted/paused, and then // should never happen, should have been intercepted/paused, and then
// either continued, aborted or fulfilled once. // either continued, aborted or fulfilled once.
@@ -1562,7 +1540,7 @@ pub const Transfer = struct {
}; };
} }
fn _fulfill(transfer: *Transfer, status: u16, headers: []const Http.Header, body: ?[]const u8) !void { fn _fulfill(transfer: *Transfer, status: u16, headers: []const Net.Header, body: ?[]const u8) !void {
const req = &transfer.req; const req = &transfer.req;
if (req.start_callback) |cb| { if (req.start_callback) |cb| {
try cb(transfer); try cb(transfer);
@@ -1576,7 +1554,7 @@ pub const Transfer = struct {
}; };
for (headers) |hdr| { for (headers) |hdr| {
if (std.ascii.eqlIgnoreCase(hdr.name, "content-type")) { if (std.ascii.eqlIgnoreCase(hdr.name, "content-type")) {
const len = @min(hdr.value.len, ResponseHeader.MAX_CONTENT_TYPE_LEN); const len = @min(hdr.value.len, ResponseHead.MAX_CONTENT_TYPE_LEN);
@memcpy(transfer.response_header.?._content_type[0..len], hdr.value[0..len]); @memcpy(transfer.response_header.?._content_type[0..len], hdr.value[0..len]);
transfer.response_header.?._content_type_len = len; transfer.response_header.?._content_type_len = len;
break; break;
@@ -1607,7 +1585,7 @@ pub const Transfer = struct {
if (self._handle) |handle| { if (self._handle) |handle| {
// If we have a handle, than this is a normal request. We can get the // If we have a handle, than this is a normal request. We can get the
// header value from the easy handle. // header value from the easy handle.
const cl = getResponseHeader(handle.conn.easy, "content-length", 0) orelse return null; const cl = handle.conn.getResponseHeader("content-length", 0) orelse return null;
return cl.value; return cl.value;
} }
@@ -1625,11 +1603,3 @@ pub const Transfer = struct {
return null; return null;
} }
}; };
pub const ResponseHeader = @import("../Net.zig").ResponseHeader;
const HeaderIterator = Net.HeaderIterator;
const Net = @import("../Net.zig");
const CurlHeaderValue = Net.CurlHeaderValue;
const getResponseHeader = Net.getResponseHeader;

View File

@@ -19,9 +19,9 @@
const std = @import("std"); const std = @import("std");
const Net = @import("../Net.zig"); const Net = @import("../Net.zig");
pub const c = Net.c; const c = Net.c;
pub const ENABLE_DEBUG = Net.ENABLE_DEBUG; const ENABLE_DEBUG = Net.ENABLE_DEBUG;
pub const Client = @import("Client.zig"); pub const Client = @import("Client.zig");
pub const Transfer = Client.Transfer; pub const Transfer = Client.Transfer;
@@ -29,11 +29,6 @@ pub const Method = Net.Method;
pub const Header = Net.Header; pub const Header = Net.Header;
pub const Headers = Net.Headers; pub const Headers = Net.Headers;
pub const Connection = Net.Connection;
pub const errorCheck = Net.errorCheck;
pub const errorMCheck = Net.errorMCheck;
const Config = @import("../Config.zig"); const Config = @import("../Config.zig");
const RobotStore = @import("../browser/Robots.zig").RobotStore; const RobotStore = @import("../browser/Robots.zig").RobotStore;
@@ -91,6 +86,6 @@ pub fn createClient(self: *Http, allocator: Allocator) !*Client {
return Client.init(allocator, self.ca_blob, self.robot_store, self.config); return Client.init(allocator, self.ca_blob, self.robot_store, self.config);
} }
pub fn newConnection(self: *Http) !Connection { pub fn newConnection(self: *Http) !Net.Connection {
return Connection.init(self.ca_blob, self.config); return Net.Connection.init(self.ca_blob, self.config);
} }

View File

@@ -21,6 +21,7 @@ pub const LightPanda = struct {
mutex: std.Thread.Mutex, mutex: std.Thread.Mutex,
cond: Thread.Condition, cond: Thread.Condition,
connection: Http.Connection, connection: Http.Connection,
config: *const Config,
pending: std.DoublyLinkedList, pending: std.DoublyLinkedList,
mem_pool: std.heap.MemoryPool(LightPandaEvent), mem_pool: std.heap.MemoryPool(LightPandaEvent),
@@ -40,6 +41,7 @@ pub const LightPanda = struct {
.running = true, .running = true,
.allocator = allocator, .allocator = allocator,
.connection = connection, .connection = connection,
.config = app.config,
.mem_pool = std.heap.MemoryPool(LightPandaEvent).init(allocator), .mem_pool = std.heap.MemoryPool(LightPandaEvent).init(allocator),
}; };
} }
@@ -109,7 +111,7 @@ pub const LightPanda = struct {
} }
try self.connection.setBody(aw.written()); try self.connection.setBody(aw.written());
const status = try self.connection.request(); const status = try self.connection.request(&self.config.http_headers);
if (status != 200) { if (status != 200) {
log.warn(.telemetry, "server error", .{ .status = status }); log.warn(.telemetry, "server error", .{ .status = status });