From 438c72b7e9e4bf04340ef443756bcb8d2c842c63 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Sat, 5 Nov 2022 03:09:59 -0700 Subject: [PATCH] Make request generic based on reader --- src/http/lib.zig | 21 +++++---------- src/http/request.zig | 44 ++++++++++++++------------------ src/http/request/parser.zig | 12 +++------ src/http/request/test_parser.zig | 2 +- src/http/server.zig | 7 ++--- 5 files changed, 31 insertions(+), 55 deletions(-) diff --git a/src/http/lib.zig b/src/http/lib.zig index e234e27..ce97ad1 100644 --- a/src/http/lib.zig +++ b/src/http/lib.zig @@ -10,24 +10,15 @@ pub const socket = @import("./socket.zig"); pub const Method = std.http.Method; pub const Status = std.http.Status; -pub const Request = request.Request; +pub const Request = request.Request(std.net.Stream.Reader); pub const serveConn = server.serveConn; pub const Response = server.Response; pub const Handler = server.Handler; pub const Fields = @import("./headers.zig").Fields; -pub const Headers = std.HashMap([]const u8, []const u8, struct { - pub fn eql(_: @This(), a: []const u8, b: []const u8) bool { - return ciutf8.eql(a, b); - } - - pub fn hash(_: @This(), str: []const u8) u64 { - return ciutf8.hash(str); - } -}, std.hash_map.default_max_load_percentage); - -test { - _ = server; - _ = request; -} +pub const Protocol = enum { + http_1_0, + http_1_1, + http_1_x, +}; diff --git a/src/http/request.zig b/src/http/request.zig index cc16b8b..f3166a8 100644 --- a/src/http/request.zig +++ b/src/http/request.zig @@ -3,30 +3,24 @@ const http = @import("./lib.zig"); const parser = @import("./request/parser.zig"); -pub const Request = struct { - pub const Protocol = enum { - http_1_0, - http_1_1, - http_1_x, +pub fn Request(comptime _: type) type { + return struct { + protocol: http.Protocol, + + method: http.Method, + uri: []const u8, + headers: http.Fields, + + body: ?[]const u8 = null, + + pub fn parseFree(self: *@This(), allocator: std.mem.Allocator) void { + allocator.free(self.uri); + self.headers.deinit(); + if (self.body) |body| allocator.free(body); + } }; - - protocol: Protocol, - - method: http.Method, - uri: []const u8, - headers: http.Fields, - - body: ?[]const u8 = null, - - pub fn parse(alloc: std.mem.Allocator, reader: anytype) !Request { - return parser.parse(alloc, reader); - } - - pub fn parseFree(self: *Request, alloc: std.mem.Allocator) void { - parser.parseFree(alloc, self); - } -}; - -test { - _ = parser; +} + +pub fn parse(alloc: std.mem.Allocator, reader: anytype) !Request(@TypeOf(reader)) { + return parser.parse(alloc, reader); } diff --git a/src/http/request/parser.zig b/src/http/request/parser.zig index 4cbe320..6bdf514 100644 --- a/src/http/request/parser.zig +++ b/src/http/request/parser.zig @@ -21,7 +21,7 @@ const Encoding = enum { chunked, }; -pub fn parse(alloc: std.mem.Allocator, reader: anytype) !Request { +pub fn parse(alloc: std.mem.Allocator, reader: anytype) !Request(@TypeOf(reader)) { const method = try parseMethod(reader); const uri = reader.readUntilDelimiterAlloc(alloc, ' ', max_path_len) catch |err| switch (err) { error.StreamTooLong => return error.RequestUriTooLong, @@ -47,7 +47,7 @@ pub fn parse(alloc: std.mem.Allocator, reader: anytype) !Request { null; errdefer if (body) |b| alloc.free(b); - return Request{ + return Request(@TypeOf(reader)){ .protocol = proto, .method = method, @@ -73,7 +73,7 @@ fn parseMethod(reader: anytype) !Method { return error.MethodNotImplemented; } -fn parseProto(reader: anytype) !Request.Protocol { +fn parseProto(reader: anytype) !http.Protocol { var buf: [8]u8 = undefined; const proto = reader.readUntilDelimiter(&buf, '/') catch |err| switch (err) { error.StreamTooLong => return error.UnknownProtocol, @@ -159,9 +159,3 @@ fn parseEncoding(encoding: ?[]const u8) !Encoding { if (std.mem.eql(u8, encoding.?, "chunked")) return .chunked; return error.UnsupportedMediaType; } - -pub fn parseFree(allocator: std.mem.Allocator, request: *Request) void { - allocator.free(request.uri); - request.headers.deinit(); - if (request.body) |body| allocator.free(body); -} diff --git a/src/http/request/test_parser.zig b/src/http/request/test_parser.zig index 1eef214..55a66d6 100644 --- a/src/http/request/test_parser.zig +++ b/src/http/request/test_parser.zig @@ -5,7 +5,7 @@ const t = std.testing; const test_case = struct { fn parse(text: []const u8, expected: struct { - protocol: http.Request.Protocol = .http_1_1, + protocol: http.Protocol = .http_1_1, method: http.Method = .GET, headers: []const std.meta.Tuple(&.{ []const u8, []const u8 }) = &.{}, uri: []const u8 = "", diff --git a/src/http/server.zig b/src/http/server.zig index 91bde68..91b5747 100644 --- a/src/http/server.zig +++ b/src/http/server.zig @@ -3,6 +3,7 @@ const util = @import("util"); const http = @import("./lib.zig"); const response = @import("./server/response.zig"); +const request = @import("./request.zig"); pub const Response = struct { alloc: std.mem.Allocator, @@ -26,10 +27,6 @@ pub const Response = struct { const Request = http.Request; const request_buf_size = 1 << 16; -pub fn Handler(comptime Ctx: type) type { - return fn (Ctx, Request, *Response) void; -} - pub fn serveConn(conn: std.net.StreamServer.Connection, ctx: anytype, handler: anytype, alloc: std.mem.Allocator) !void { // TODO: Timeouts while (true) { @@ -37,7 +34,7 @@ pub fn serveConn(conn: std.net.StreamServer.Connection, ctx: anytype, handler: a var arena = std.heap.ArenaAllocator.init(alloc); defer arena.deinit(); - const req = Request.parse(arena.allocator(), conn.stream.reader()) catch |err| { + const req = request.parse(arena.allocator(), conn.stream.reader()) catch |err| { return handleError(conn.stream.writer(), err) catch {}; }; std.log.debug("done parsing", .{});