Skip to content

http.Client hangs on HTTPS request larger than the write buffer size #25294

@benburkert

Description

@benburkert

Zig Version

0.15.1

Steps to Reproduce and Observed Behavior

The http.Client will hang on a HTTPS POST when the size of the request body exceeds the write buffer size:

const std = @import("std");

pub fn main() !void {
    var http_client: std.http.Client = .{ .allocator = std.heap.smp_allocator };
    std.debug.assert(http_client.write_buffer_size == 1024);

    {
        var req = try http_client.request(.POST, try std.Uri.parse("https://www.google.com/"), .{});
        defer req.deinit();

        var buf: [1024]u8 = undefined;

        std.debug.assert(buf.len <= http_client.write_buffer_size);

        try req.sendBodyComplete(&buf);
    }

    {
        var req = try http_client.request(.POST, try std.Uri.parse("https://www.google.com/"), .{});
        defer req.deinit();

        var buf: [1025]u8 = undefined;

        std.debug.assert(buf.len > http_client.write_buffer_size);

        try req.sendBodyComplete(&buf); // this one hangs
    }
}

I found that it is spinning on this line in defaultFlush, calling tls.Client.drain. In drain, it does not consume any input from data if the first buffer is too small. Since this drain doesn't buffer data, I don't believe it's compatible with std.Io.defaultFlush, which is used implicitly by the http.BodyWriter.

Expected Behavior

The example program should not hang.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugObserved behavior contradicts documented or intended behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions