fix HTTP server to handle a chunked transfer coding request

This commit is contained in:
Ryo Ota
2023-04-24 02:07:52 +09:00
committed by Andrew Kelley
parent 1d1255b433
commit bba90b8863
2 changed files with 77 additions and 2 deletions

View File

@@ -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();
}

View File

@@ -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;