http: refacto http header parsing

This commit is contained in:
Pierre Tachoire
2025-08-21 14:01:33 +02:00
parent 159bd06a56
commit 5e78a26e3d

View File

@@ -309,6 +309,9 @@ fn makeRequest(self: *Client, handle: *Handle, transfer: *Transfer) !void {
transfer._handle = handle;
errdefer transfer.deinit();
// Store the proxy's information in transfer to ease headers parsing.
transfer._use_proxy = conn.opts.use_proxy;
try conn.setURL(req.url);
try conn.setMethod(req.method);
if (req.body) |b| {
@@ -574,6 +577,13 @@ pub const Transfer = struct {
_redirecting: bool = false,
// use_proxy is set when the transfer has been associated to a given
// connection in makeRequest().
_use_proxy: bool = undefined,
// stateful variables used to parse responses headers.
_resp_header_status: enum { empty, first, next, end } = .empty,
fn deinit(self: *Transfer) void {
self.req.headers.deinit();
if (self._handle) |handle| {
@@ -684,20 +694,23 @@ pub const Transfer = struct {
const header = buffer[0 .. buf_len - 2];
if (transfer.response_header == null) {
if (transfer._redirecting and buf_len == 2) {
// parse and set cookies for the redirection.
redirectionCookies(transfer, easy) catch |err| {
log.debug(.http, "redirection cookies", .{ .err = err });
return 0;
// transition the status dependending the previous one.
transfer._resp_header_status = switch (transfer._resp_header_status) {
.empty => .first,
.first => .next,
.next => .next,
.end => .first,
};
return buf_len;
}
if (buf_len < 13 or std.mem.startsWith(u8, header, "HTTP/") == false) {
if (transfer._redirecting) {
return buf_len;
}
// mark the end of parsing headers
if (buf_len == 2) transfer._resp_header_status = .end;
log.debug(.http, "header parsing", .{ .status = transfer._resp_header_status });
switch (transfer._resp_header_status) {
.empty => unreachable,
.first => {
if (buf_len < 13) {
log.debug(.http, "invalid response line", .{ .line = header });
return 0;
}
@@ -729,12 +742,19 @@ pub const Transfer = struct {
.url = url,
.status = status,
};
transfer.bytes_received = buf_len;
},
.next => {},
.end => {
// If we are in a redirection, take care of cookies only.
if (transfer._redirecting) {
// parse and set cookies for the redirection.
redirectionCookies(transfer, easy) catch |err| {
log.debug(.http, "redirection cookies", .{ .err = err });
return 0;
};
return buf_len;
}
transfer.bytes_received += buf_len;
if (buf_len == 2) {
if (getResponseHeader(easy, "content-type", 0)) |ct| {
var hdr = &transfer.response_header.?;
const value = ct.value;
@@ -765,7 +785,10 @@ pub const Transfer = struct {
.transfer = transfer,
});
}
},
}
transfer.bytes_received += buf_len;
return buf_len;
}