diff --git a/src/http/conn.zig b/src/http/conn.zig index 15a332f..f7560b4 100644 --- a/src/http/conn.zig +++ b/src/http/conn.zig @@ -8,41 +8,44 @@ pub const Connection = struct { id: Id, address: std.net.Address, stream: std.net.Stream, + + fn new(id: Id, std_conn: std.net.Connection) Connection { + std.log.debug("new connection conn_id={}", .{id}); + return .{ + .id = id, + .address = std_conn.address, + .stream = std_conn.stream, + }; + } + + pub fn close(self: Connection) void { + std.log.debug("terminating connection conn_id={}", .{self.id}); + self.stream.close(); + } }; pub const ConnectionServer = struct { - pub const Handler = fn (Connection) callconv(.Async) void; - - alloc: std.mem.Allocator, next_conn_id: std.atomic.Atomic(Connection.Id) = std.atomic.Atomic(Connection.Id).init(1), - handler: Handler, + stream_server: std.net.StreamServer, - pub fn run(self: *ConnectionServer, addr: std.net.Address) noreturn { - var srv = std.net.StreamServer.init(.{ .reuse_address = true }); - defer srv.deinit(); + pub fn listen(addr: std.net.Address) !ConnectionServer { + var self = ConnectionServer{ + .stream_server = std.net.StreamServer.init(.{ .reuse_address = true }), + }; + errdefer self.stream_server.deinit(); - try srv.listen(addr); - - while (true) { - const conn = try srv.accept(); - self.handle(conn.stream, conn.address); - } - - unreachable; + try self.stream_server.listen(addr); + return self; } - fn handle(self: *ConnectionServer, stream: std.net.Stream, address: std.net.Address) void { - const conn = Connection{ - .id = self.next_conn_id.fetchAdd(1, .SeqCst), - .address = address, - .stream = stream, - }; + pub fn accept(self: *ConnectionServer) !Connection { + const conn = try self.stream_server.accept(); + const id = self.next_conn_id.fetchAdd(1, .SeqCst); - defer conn.stream.close(); - std.log.debug("new connection conn_id={}", .{conn.id}); + return Connection.new(id, conn); + } - async self.handler(conn); - - std.log.debug("terminating connection conn_id={}", .{conn.id}); + pub fn shutdown(self: *ConnectionServer) void { + self.stream_server.deinit(); } }; diff --git a/src/http/request/parser.zig b/src/http/request/parser.zig index 6e786f1..c08d66a 100644 --- a/src/http/request/parser.zig +++ b/src/http/request/parser.zig @@ -43,6 +43,7 @@ fn parseLine(alloc: std.mem.Allocator, request: *Request, reader: anytype) !void error.StreamTooLong => return error.RequestUriTooLong, else => return err, }; + errdefer alloc.free(request.path); try checkProto(reader); @@ -91,7 +92,14 @@ fn checkProto(reader: anytype) !void { fn parseHeaders(allocator: std.mem.Allocator, reader: anytype) !Headers { var map = Headers.init(allocator); errdefer map.deinit(); - // TODO: free map keys/values + // todo: + //errdefer { + //var iter = map.iterator(); + //while (iter.next()) |it| { + //allocator.free(it.key_ptr); + //allocator.free(it.value_ptr); + //} + //} var buf: [1024]u8 = undefined; diff --git a/src/http/server.zig b/src/http/server.zig index 842725f..63c8b9a 100644 --- a/src/http/server.zig +++ b/src/http/server.zig @@ -2,17 +2,53 @@ const std = @import("std"); const util = @import("util"); const http = @import("./lib.zig"); +const Request = http.Request; const Connection = http.Connection; const request_buf_size = 1 << 16; -fn handleConnection(conn: http.Connection) void { - var request_buf: [request_buf_size]u8 = undefined; - var fba = std.heap.FixedBufferAllocator.init(&request_buf); +pub const Context = struct { + alloc: std.mem.Allocator, + request: Request, + connection: Connection, - const request = http.Request.parse(fba.allocator(), conn.stream.reader()) catch |err| handleError(conn.stream.writer(), err); - _ = request; -} + const Writer = http.ResponseStream(Connection.Writer); + + pub fn openResponse(self: *Context, headers: *const http.Headers, status: http.Status) !Writer { + return try http.response_stream.open(self.alloc, self.connection.stream.writer(), headers, status); + } + + pub fn deinit(_: *Context) void { + // todo: deallocate request + } +}; + +const HttpServer = struct { + conn_server: http.ConnectionServer, + pub fn listen(addr: std.net.Address) !HttpServer { + return .{ + .conn_server = try http.ConnectionServer.listen(addr), + }; + } + + pub fn accept(self: *HttpServer, alloc: std.mem.Allocator) !Context { + while (true) { + const conn = try self.conn_server.accept(); + errdefer conn.close(); + + const req = http.Request.parse(alloc, conn.stream.reader()) catch |err| { + _ = handleError(conn.stream.writer(), err); + continue; + }; + + return .{ .connection = conn, .request = req, .alloc = alloc }; + } + } + + pub fn shutdown(self: *HttpServer) void { + self.conn_server.shutdown(); + } +}; fn handleError(writer: anytype, err: anyerror) !void { const status: http.Status = switch (err) {