Make request generic based on reader

This commit is contained in:
jaina heartles 2022-11-05 03:09:59 -07:00
parent b46e82746c
commit 438c72b7e9
5 changed files with 31 additions and 55 deletions

View file

@ -10,24 +10,15 @@ pub const socket = @import("./socket.zig");
pub const Method = std.http.Method; pub const Method = std.http.Method;
pub const Status = std.http.Status; 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 serveConn = server.serveConn;
pub const Response = server.Response; pub const Response = server.Response;
pub const Handler = server.Handler; pub const Handler = server.Handler;
pub const Fields = @import("./headers.zig").Fields; pub const Fields = @import("./headers.zig").Fields;
pub const Headers = std.HashMap([]const u8, []const u8, struct { pub const Protocol = enum {
pub fn eql(_: @This(), a: []const u8, b: []const u8) bool { http_1_0,
return ciutf8.eql(a, b); http_1_1,
} http_1_x,
};
pub fn hash(_: @This(), str: []const u8) u64 {
return ciutf8.hash(str);
}
}, std.hash_map.default_max_load_percentage);
test {
_ = server;
_ = request;
}

View file

@ -3,14 +3,9 @@ const http = @import("./lib.zig");
const parser = @import("./request/parser.zig"); const parser = @import("./request/parser.zig");
pub const Request = struct { pub fn Request(comptime _: type) type {
pub const Protocol = enum { return struct {
http_1_0, protocol: http.Protocol,
http_1_1,
http_1_x,
};
protocol: Protocol,
method: http.Method, method: http.Method,
uri: []const u8, uri: []const u8,
@ -18,15 +13,14 @@ pub const Request = struct {
body: ?[]const u8 = null, body: ?[]const u8 = null,
pub fn parse(alloc: std.mem.Allocator, reader: anytype) !Request { pub fn parseFree(self: *@This(), allocator: std.mem.Allocator) void {
return parser.parse(alloc, reader); allocator.free(self.uri);
} self.headers.deinit();
if (self.body) |body| allocator.free(body);
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);
} }

View file

@ -21,7 +21,7 @@ const Encoding = enum {
chunked, 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 method = try parseMethod(reader);
const uri = reader.readUntilDelimiterAlloc(alloc, ' ', max_path_len) catch |err| switch (err) { const uri = reader.readUntilDelimiterAlloc(alloc, ' ', max_path_len) catch |err| switch (err) {
error.StreamTooLong => return error.RequestUriTooLong, error.StreamTooLong => return error.RequestUriTooLong,
@ -47,7 +47,7 @@ pub fn parse(alloc: std.mem.Allocator, reader: anytype) !Request {
null; null;
errdefer if (body) |b| alloc.free(b); errdefer if (body) |b| alloc.free(b);
return Request{ return Request(@TypeOf(reader)){
.protocol = proto, .protocol = proto,
.method = method, .method = method,
@ -73,7 +73,7 @@ fn parseMethod(reader: anytype) !Method {
return error.MethodNotImplemented; return error.MethodNotImplemented;
} }
fn parseProto(reader: anytype) !Request.Protocol { fn parseProto(reader: anytype) !http.Protocol {
var buf: [8]u8 = undefined; var buf: [8]u8 = undefined;
const proto = reader.readUntilDelimiter(&buf, '/') catch |err| switch (err) { const proto = reader.readUntilDelimiter(&buf, '/') catch |err| switch (err) {
error.StreamTooLong => return error.UnknownProtocol, error.StreamTooLong => return error.UnknownProtocol,
@ -159,9 +159,3 @@ fn parseEncoding(encoding: ?[]const u8) !Encoding {
if (std.mem.eql(u8, encoding.?, "chunked")) return .chunked; if (std.mem.eql(u8, encoding.?, "chunked")) return .chunked;
return error.UnsupportedMediaType; 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);
}

View file

@ -5,7 +5,7 @@ const t = std.testing;
const test_case = struct { const test_case = struct {
fn parse(text: []const u8, expected: 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, method: http.Method = .GET,
headers: []const std.meta.Tuple(&.{ []const u8, []const u8 }) = &.{}, headers: []const std.meta.Tuple(&.{ []const u8, []const u8 }) = &.{},
uri: []const u8 = "", uri: []const u8 = "",

View file

@ -3,6 +3,7 @@ const util = @import("util");
const http = @import("./lib.zig"); const http = @import("./lib.zig");
const response = @import("./server/response.zig"); const response = @import("./server/response.zig");
const request = @import("./request.zig");
pub const Response = struct { pub const Response = struct {
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
@ -26,10 +27,6 @@ pub const Response = struct {
const Request = http.Request; const Request = http.Request;
const request_buf_size = 1 << 16; 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 { pub fn serveConn(conn: std.net.StreamServer.Connection, ctx: anytype, handler: anytype, alloc: std.mem.Allocator) !void {
// TODO: Timeouts // TODO: Timeouts
while (true) { 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); var arena = std.heap.ArenaAllocator.init(alloc);
defer arena.deinit(); 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 {}; return handleError(conn.stream.writer(), err) catch {};
}; };
std.log.debug("done parsing", .{}); std.log.debug("done parsing", .{});