http: ajust header callback according to review

This commit is contained in:
Pierre Tachoire
2025-08-22 10:15:54 +02:00
parent fcd49c000f
commit 25ad420f85

View File

@@ -582,9 +582,6 @@ pub const Transfer = struct {
// 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| {
@@ -695,21 +692,20 @@ pub const Transfer = struct {
const header = buffer[0 .. buf_len - 2];
// transition the status dependending the previous one.
transfer._resp_header_status = switch (transfer._resp_header_status) {
.empty => .first,
.first => .next,
.next => .next,
.end => .first,
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;
};
return buf_len;
}
// mark the end of parsing headers
if (buf_len == 2) transfer._resp_header_status = .end;
switch (transfer._resp_header_status) {
.empty => unreachable,
.first => {
if (buf_len < 13) {
if (buf_len < 13 or std.mem.startsWith(u8, header, "HTTP/") == false) {
if (transfer._redirecting) {
return buf_len;
}
log.debug(.http, "invalid response line", .{ .line = header });
return 0;
}
@@ -725,58 +721,65 @@ pub const Transfer = struct {
return 0;
};
var url: [*c]u8 = undefined;
errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_EFFECTIVE_URL, &url)) catch |err| {
log.err(.http, "failed to get URL", .{ .err = err });
return 0;
};
// When using proxy, curl call the header function for all HTTP
// requests, including the CONNECT one used tunneling requests.
if (transfer._use_proxy and transfer.proxy_response_header == null) {
transfer.proxy_response_header = .{
.url = "",
.status = status,
};
// We want to ignore the successful proxy's CONNECT request.
// But there is no proper way to detect if the current
// request is a proxy CONNECT one.
// We know curl uses a CONNECT when it establishes a TLS
// conn.
if (status == 200 and std.mem.startsWith(u8, std.mem.span(url), "https")) {
return buf_len;
}
}
if (status >= 300 and status <= 399) {
transfer._redirecting = true;
return buf_len;
}
transfer._redirecting = false;
var url: [*c]u8 = undefined;
errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_EFFECTIVE_URL, &url)) catch |err| {
log.err(.http, "failed to get URL", .{ .err = err });
return 0;
};
transfer.response_header = .{
.url = url,
.status = status,
};
},
.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;
};
transfer.bytes_received = buf_len;
return buf_len;
}
if (transfer._use_proxy and transfer.response_header == null) {
// we are in a successful CONNECT proxy request, ignore it.
transfer.bytes_received += buf_len;
if (buf_len != 2) {
return buf_len;
}
// Starting here, we get the last header line.
// We're connecting to a proxy. Consider the first request to the
// proxy's result.
if (transfer._use_proxy and transfer.proxy_response_header == null) {
// We have to cases:
// 1. for http://, we have one request. So both
// proxy_response_header and response_header will have the same
// value.
//
// 2. for https://, we two successive requests, a CONNECT to the
// proxy and a final request. So proxy_response_header and
// response_header may have different values.
transfer.proxy_response_header = transfer.response_header;
// Detect if the request is a CONNECT to the proxy. There might be
// a better way to detect this, but I didn't find a better one.
// When we don't force curl to always use tunneling, it uses
// CONNECT tunnel only for https requests.
const is_connect = std.mem.startsWith(u8, std.mem.span(transfer.proxy_response_header.?.url), "https");
// If the CONNECT is successful, curl will create a following
// request to the final target, so we reset
// transfer.response_header to get the "real" data.
if (is_connect and transfer.proxy_response_header.?.status == 200) {
transfer.response_header = null;
return buf_len;
}
// If the CONNECT fails, use the request result as it would be our
// final request.
}
if (getResponseHeader(easy, "content-type", 0)) |ct| {
var hdr = &transfer.response_header.?;
const value = ct.value;
@@ -807,10 +810,6 @@ pub const Transfer = struct {
.transfer = transfer,
});
}
},
}
transfer.bytes_received += buf_len;
return buf_len;
}