Commit 5f219a2d11
Changed files (2)
lib
std
http
test
standalone
lib/std/http/Server.zig
@@ -352,7 +352,7 @@ pub const Response = struct {
transfer_encoding: ResponseTransfer = .none,
- server: *Server,
+ allocator: Allocator,
address: net.Address,
connection: BufferedConnection,
@@ -376,7 +376,7 @@ pub const Response = struct {
res.request.headers.deinit();
if (res.request.parser.header_bytes_owned) {
- res.request.parser.header_bytes.deinit(res.server.allocator);
+ res.request.parser.header_bytes.deinit(res.allocator);
}
}
@@ -545,13 +545,13 @@ pub const Response = struct {
while (true) {
try res.connection.fill();
- const nchecked = try res.request.parser.checkCompleteHead(res.server.allocator, res.connection.peek());
+ const nchecked = try res.request.parser.checkCompleteHead(res.allocator, res.connection.peek());
res.connection.clear(@intCast(u16, nchecked));
if (res.request.parser.state.isContent()) break;
}
- res.request.headers = .{ .allocator = res.server.allocator, .owned = true };
+ res.request.headers = .{ .allocator = res.allocator, .owned = true };
try res.request.parse(res.request.parser.header_bytes.items);
if (res.request.transfer_encoding) |te| {
@@ -573,13 +573,13 @@ pub const Response = struct {
if (res.request.transfer_compression) |tc| switch (tc) {
.compress => return error.CompressionNotSupported,
.deflate => res.request.compression = .{
- .deflate = std.compress.zlib.zlibStream(res.server.allocator, res.transferReader()) catch return error.CompressionInitializationFailed,
+ .deflate = std.compress.zlib.zlibStream(res.allocator, res.transferReader()) catch return error.CompressionInitializationFailed,
},
.gzip => res.request.compression = .{
- .gzip = std.compress.gzip.decompress(res.server.allocator, res.transferReader()) catch return error.CompressionInitializationFailed,
+ .gzip = std.compress.gzip.decompress(res.allocator, res.transferReader()) catch return error.CompressionInitializationFailed,
},
.zstd => res.request.compression = .{
- .zstd = std.compress.zstd.decompressStream(res.server.allocator, res.transferReader()),
+ .zstd = std.compress.zstd.decompressStream(res.allocator, res.transferReader()),
},
};
}
@@ -612,12 +612,12 @@ pub const Response = struct {
while (!res.request.parser.state.isContent()) { // read trailing headers
try res.connection.fill();
- const nchecked = try res.request.parser.checkCompleteHead(res.server.allocator, res.connection.peek());
+ const nchecked = try res.request.parser.checkCompleteHead(res.allocator, res.connection.peek());
res.connection.clear(@intCast(u16, nchecked));
}
if (has_trail) {
- res.request.headers = http.Headers{ .allocator = res.server.allocator, .owned = false };
+ res.request.headers = http.Headers{ .allocator = res.allocator, .owned = false };
// The response headers before the trailers are already guaranteed to be valid, so they will always be parsed again and cannot return an error.
// This will *only* fail for a malformed trailer.
@@ -731,24 +731,29 @@ pub const HeaderStrategy = union(enum) {
static: []u8,
};
+pub const AcceptOptions = struct {
+ allocator: Allocator,
+ header_strategy: HeaderStrategy = .{ .dynamic = 8192 },
+};
+
/// Accept a new connection.
-pub fn accept(server: *Server, options: HeaderStrategy) AcceptError!Response {
+pub fn accept(server: *Server, options: AcceptOptions) AcceptError!Response {
const in = try server.socket.accept();
return Response{
- .server = server,
+ .allocator = options.allocator,
.address = in.address,
.connection = .{ .conn = .{
.stream = in.stream,
.protocol = .plain,
} },
- .headers = .{ .allocator = server.allocator },
+ .headers = .{ .allocator = options.allocator },
.request = .{
.version = undefined,
.method = undefined,
.target = undefined,
- .headers = .{ .allocator = server.allocator, .owned = false },
- .parser = switch (options) {
+ .headers = .{ .allocator = options.allocator, .owned = false },
+ .parser = switch (options.header_strategy) {
.dynamic => |max| proto.HeadersParser.initDynamic(max),
.static => |buf| proto.HeadersParser.initStatic(buf),
},
test/standalone/http.zig
@@ -15,6 +15,8 @@ var gpa_client = std.heap.GeneralPurposeAllocator(.{}){};
const salloc = gpa_server.allocator();
const calloc = gpa_client.allocator();
+var server: Server = undefined;
+
fn handleRequest(res: *Server.Response) !void {
const log = std.log.scoped(.server);
@@ -89,7 +91,7 @@ fn handleRequest(res: *Server.Response) !void {
} else if (mem.eql(u8, res.request.target, "/redirect/3")) {
res.transfer_encoding = .chunked;
- const location = try std.fmt.allocPrint(salloc, "http://127.0.0.1:{d}/redirect/2", .{res.server.socket.listen_address.getPort()});
+ const location = try std.fmt.allocPrint(salloc, "http://127.0.0.1:{d}/redirect/2", .{server.socket.listen_address.getPort()});
defer salloc.free(location);
res.status = .found;
@@ -119,7 +121,10 @@ var handle_new_requests = true;
fn runServer(srv: *Server) !void {
outer: while (handle_new_requests) {
- var res = try srv.accept(.{ .dynamic = max_header_size });
+ var res = try srv.accept(.{
+ .allocator = salloc,
+ .header_strategy = .{ .dynamic = max_header_size },
+ });
defer res.deinit();
while (res.reset() != .closing) {
@@ -162,7 +167,7 @@ pub fn main() !void {
defer _ = gpa_client.deinit();
- var server = Server.init(salloc, .{ .reuse_address = true });
+ server = Server.init(salloc, .{ .reuse_address = true });
const addr = std.net.Address.parseIp("127.0.0.1", 0) catch unreachable;
try server.listen(addr);