Commit bba90b8863
Changed files (2)
lib
std
lib/std/http/protocol.zig
@@ -556,8 +556,12 @@ pub const HeadersParser = struct {
switch (r.state) {
.invalid => return error.HttpChunkInvalid,
.chunk_data => if (r.next_chunk_length == 0) {
- // The trailer section is formatted identically to the header section.
- r.state = .seen_rn;
+ if (std.mem.eql(u8, bconn.peek(), "\r\n")) {
+ r.state = .finished;
+ } else {
+ // The trailer section is formatted identically to the header section.
+ r.state = .seen_rn;
+ }
r.done = true;
return out_index;
lib/std/http/Server.zig
@@ -661,3 +661,74 @@ pub fn accept(server: *Server, options: HeaderStrategy) AcceptError!*Response {
return res;
}
+
+test "HTTP server handles a chunked transfer coding request" {
+ const builtin = @import("builtin");
+
+ // This test requires spawning threads.
+ if (builtin.single_threaded) {
+ return error.SkipZigTest;
+ }
+
+ const native_endian = comptime builtin.cpu.arch.endian();
+ if (builtin.zig_backend == .stage2_llvm and native_endian == .Big) {
+ // https://github.com/ziglang/zig/issues/13782
+ return error.SkipZigTest;
+ }
+
+ if (builtin.os.tag == .wasi) return error.SkipZigTest;
+
+ const allocator = std.testing.allocator;
+ const expect = std.testing.expect;
+
+ const max_header_size = 8192;
+ var server = std.http.Server.init(allocator, .{ .reuse_address = true });
+ defer server.deinit();
+
+ const address = try std.net.Address.parseIp("127.0.0.1", 0);
+ try server.listen(address);
+ const server_port = server.socket.listen_address.in.getPort();
+
+ const server_thread = try std.Thread.spawn(.{}, (struct {
+ fn apply(s: *std.http.Server) !void {
+ const res = try s.accept(.{ .dynamic = max_header_size });
+ defer res.deinit();
+ defer res.reset();
+ try res.wait();
+
+ try expect(res.request.transfer_encoding.? == .chunked);
+
+ const server_body: []const u8 = "message from server!\n";
+ res.transfer_encoding = .{ .content_length = server_body.len };
+ try res.headers.append("content-type", "text/plain");
+ try res.headers.append("connection", "close");
+ try res.do();
+
+ var buf: [128]u8 = undefined;
+ const n = try res.readAll(&buf);
+ try expect(std.mem.eql(u8, buf[0..n], "ABCD"));
+ _ = try res.writer().writeAll(server_body);
+ try res.finish();
+ }
+ }).apply, .{&server});
+
+ const request_bytes =
+ "POST / HTTP/1.1\r\n" ++
+ "Content-Type: text/plain\r\n" ++
+ "Transfer-Encoding: chunked\r\n" ++
+ "\r\n" ++
+ "1\r\n" ++
+ "A\r\n" ++
+ "1\r\n" ++
+ "B\r\n" ++
+ "2\r\n" ++
+ "CD\r\n" ++
+ "0\r\n" ++
+ "\r\n";
+
+ const stream = try std.net.tcpConnectToHost(allocator, "127.0.0.1", server_port);
+ defer stream.close();
+ _ = try stream.writeAll(request_bytes[0..]);
+
+ server_thread.join();
+}