Unable to make https POST request

Hello,

I’m not able to make an HTTPS POST request with Zig 0.15.1 using the following code.
When I run this code, I get the error: HttpConnectionClosing.

I found this issue: std.http.Client blocks forever with larger payloads on HTTPS requests · Issue #25015 · ziglang/zig · GitHub
However, that report is about large payloads, while I’m experiencing the same issue even with small payloads (using the same code).

Do you have any idea what might be causing this?

const std = @import("std");

const Client = std.http.Client;

pub fn main() !void {
    const alloc = std.heap.page_allocator;

    var allocating = std.Io.Writer.Allocating.init(alloc);
    defer allocating.deinit();

    const opts: Client.FetchOptions = .{
        .method = .POST,
        .location = .{ .url = "https://httpbin.org/post" },
        .payload = "Hello World",
        .response_writer = &allocating.writer,
    };

    var client: Client = .{ .allocator = alloc };
    defer client.deinit();

    _ = try client.fetch(opts);

    std.debug.print("{s}\n", .{allocating.written()});
}

I ran into this too. It seemed to occur with anything over ~800 bytes. I couldn’t solve it, my assistant couldn’t solve it. Then I saw that same issue in the ziglang repo and threw my hands up.

I ended up vendoring in libcurl/mbedtls stripped down to the essentials and have had good success doing that. I would much prefer to use zig stdlib though. I’m also using zig 0.15.1.

Cheers

2 Likes

Has anyone figured this out? Ever since I updated to 0.15.2 I cannot make requests. I keep getting this error with any request POST GET DELETE ETC. This is insane. What broke?

General protection exception (no address available)
/home/mfduar8766/.config/Code/User/globalStorage/ziglang.vscode-zig/zig/x86_64-linux-0.15.2/lib/std/http/Client.zig:1586:38: 0x11eb168 in connect (std.zig)
    if (std.ascii.eqlIgnoreCase(proxy.host, host) and
                                     ^
/home/mfduar8766/.config/Code/User/globalStorage/ziglang.vscode-zig/zig/x86_64-linux-0.15.2/lib/std/http/Client.zig:1699:36: 0x11c8c4b in request (std.zig)
        break :c try client.connect(host_name, uriPort(uri, protocol), protocol);
                                   ^
/home/mfduar8766/Desktop/browserAutomation-Zig/lib/http/http.zig:40:42: 0x1199c7d in makeRequest (main.zig)
        var req = try self.client.request(method, uriStr, http.Client.RequestOptions{
                                         ^
/home/mfduar8766/Desktop/browserAutomation-Zig/lib/fileManger/fileMnager.zig:257:41: 0x11a48cc in downloadChromeDriverVersionInformation (main.zig)
        const body = try req.makeRequest(
                                        ^
/home/mfduar8766/Desktop/browserAutomation-Zig/automation/src/driver/driver.zig:778:76: 0x11aae7f in checkOptions (main.zig)
                try self.fileManager.downloadChromeDriverVersionInformation(CHROME_DRIVER_DOWNLOAD_URL);
                                                                           ^
/home/mfduar8766/Desktop/browserAutomation-Zig/automation/src/driver/driver.zig:223:35: 0x11ab6da in init (main.zig)
        try driverPrt.checkOptions(options);
                                  ^
/home/mfduar8766/Desktop/browserAutomation-Zig/example/src/main.zig:20:33: 0x11c0e20 in main (main.zig)
    var driver = try Driver.init(allocator, true, Types.ChromeDriverConfigOptions{
                                ^
/home/mfduar8766/.config/Code/User/globalStorage/ziglang.vscode-zig/zig/x86_64-linux-0.15.2/lib/std/start.zig:627:37: 0x11c1889 in posixCallMainAndExit (std.zig)
            const result = root.main() catch |err| {
                                    ^
/home/mfduar8766/.config/Code/User/globalStorage/ziglang.vscode-zig/zig/x86_64-linux-0.15.2/lib/std/start.zig:232:5: 0x118d351 in _start (std.zig)
    asm volatile (switch (native_arch) {
    ^
???:?:?: 0x0 in ??? (???)
run
└─ run exe example failure
error: the following command terminated unexpectedly:
/home/mfduar8766/Desktop/browserAutomation-Zig/example/zig-out/bin/example

Build Summary: 4/6 steps succeeded; 1 failed
run transitive failure
└─ run exe example failure

Here is my code for reference. Even if I use fetch I still get same error.

  pub fn makeRequest(
        self: *Self,
        url: []const u8,
        method: std.http.Method,
        headers: std.http.Client.Request.Headers,
        body: ?[]u8,
    ) ![]const u8 {
        var requestBuf: [Utils.MAX_BUFF_SIZE]u8 = undefined;
        const requestMessage = try std.fmt.bufPrint(&requestBuf, "Http::makeRequest()::making {s} request to: {s}", .{ @tagName(method), url });
        try self.logger.info(@as([]const u8, requestMessage), null);
        const uriStr = try Uri.parse("https://jsonplaceholder.typicode.com/users");
        var req = try self.client.request(method, uriStr, http.Client.RequestOptions{
            .headers = headers,
        });
        defer req.deinit();

        _ = try req.sendBodiless();

        if (body) |b| {
            _ = try req.sendBodyComplete(b);
        }

        var redirectBuf: [Utils.MAX_BUFF_SIZE]u8 = undefined;
        var response = try req.receiveHead(&redirectBuf);
        if (response.head.status.class() != .success) {
            var buf: [32]u8 = undefined;
            const statusCode = try std.fmt.bufPrint(&buf, ":{s}", .{@tagName(response.head.status.class())});
            try self.logger.err("Http::makeRequest()::statusCode:", statusCode);
            return http.Client.RequestError.NetworkUnreachable;
        }
        var responseBuf: [Utils.MAX_BUFF_SIZE]u8 = undefined;
        const responseBody = try response.reader(&responseBuf).readAlloc(self.allocator, Utils.MAX_BUFF_SIZE);
        defer self.allocator.free(responseBody);
        std.debug.print("RESPONSE: {s}\n", .{responseBody});
        return try self.allocator.dupe(u8, responseBody);
    }

zig detects that the connection requires a proxy, because one of the following environment variables is set:

  • https_proxy
  • HTTPS_PROXY
  • all_proxy
  • ALL_PROXY

But when it tries to use the configured value, the program crashes.
Is it empty?

On my code I just created a http.Client{ .allocator = allocator }; Even if I set .http_proxy = null. It still doesn’t work. Looking at the http code it’s self the proxy vars are null already.