Why was the decision made in std.http.Client.RequestOptions to use a .server_header_buffer? I feel like that really locks what the programmer can do. Looking at the open method, in std.http.Client, server_header_buffer is used for an arena. Ok that's fine, but then why not just allow the programmer to pass in an allocator of their choice? I am just so confused by this decision.
#std.http.Client.RequestOptions Decision
1 messages · Page 1 of 1 (latest)
because it means the http.Client performs no allocations in the hot path, the header buffer is preallocated
I get that you want to avoid allocations, but I still don't think it's a good idea to take away that choice from the programmer. What if the response if bigger than your buffer? So you just increase the size of your buffer, but now you made another request that doesn't need that much space. You can't win either way I feel like.
if the response is bigger than your buffer then you should have provided a bigger buffer, if you allow unbounded allocations then you open yourself up to malicious servers causing you to endlessly allocate
Like we were given a choice when it comes to reading the body, why not a choice for the headers?
most webservers can't even produce a response head more than 8-64kb
you aren't given a choice because you can place a reasonable upper bound on the size of the response head regardless of server
you can't place a reasonable upper bound on the size of the payload without knowing the form of the data
True, but also you have to make this decision arbitrarily tho for each request
Yeah but now I feel like you either don't have enough space or have too much
no you don't, allocate 8 or 16kb, use that as your header buffer; if the server sends you more than 16kb of response head then either the server is likely sending you way too much data
std.http.Client used to accept an allocator and resize during the middle of reading the response; the behavior was removed because it was unnecessary and generally just slower
I agree to what you are saying. However, imo, that should be the programmers choice tho
Makes sense, but I feel like that's on the programmer and not the std
I removed the ability to heap-allocate the buffer for headers. The buffer for HTTP headers is now always provided via a static buffer. As a consequence, OutOfMemory is no longer a member of the read() error set, and the API and implementation of Client and Server are simplified. error.HttpHeadersExceededSizeLimit is renamed to error.HttpHeadersOversize.
I agree with you that anything more than 16kb is way too much, my issue is that this should be on the programmer. Than again, what do I know if Father Andrew says so
Kinda related to this, but do you know why we can't send a body via request.send()? I had to copy and paste the method and add this feature myself
because it has to handle redirects
True, but like sending a body in an http request is pretty important imo
fetch exists to handle the normal use cases, if you want to use the lower-level Request/Response interface then each component does its own job and nothing else
fwiw, I dislike the general direction that std.http has gone because it's gotten less and less maintainable over time; but my time to rework it is limited
In Zig, what's the difference between fetch and request?
request doesn't exist
I should say the client.open then
Client.fetch is a tiny bit of code that takes in common options, does the request, and then returns the data back to you
Client.open is the lower level interface where you perform each step of the request yourself, which allows you to handle potential errors at each step
I am trying to write a wrapper around it for the same reason tbh. My goal is to make it kinda like the python requests library
fn create_profile(allocator: Allocator, id_number: i32, name: []const u8, age: i32) !void {
var headers = std.BufMap.init(allocator);
defer headers.deinit();
try headers.put("Content-Type", "application/json");
const request_body: []u8 = try std.fmt.allocPrint(allocator, "{{\"id_number\": {d}, \"name\": \"{s}\", \"age\": {d}}}", .{ id_number, name, age });
defer allocator.free(request_body);
var r: requests.Response = try requests.post(allocator, "http://127.0.0.1:55555/", &headers, request_body);
defer r.deinit();
print("\n{any} ({d})\n\n", .{ r.status_code, @intFromEnum(r.status_code) });
var response_headers = r.headers.iterator();
while (response_headers.next()) |header| {
print("{s}: {s}\n", .{ header.key_ptr.*, header.value_ptr.* });
}
print("\n{s}", .{r.body});
}