diff --git a/src/handler.zig b/src/handler.zig index 77b9f1e..05b5b0c 100644 --- a/src/handler.zig +++ b/src/handler.zig @@ -15,6 +15,10 @@ const Self = @This(); pub fn task(io: std.Io, stream: std.Io.net.Stream) error{Canceled}!void { defer stream.close(io); + var arena: std.heap.ArenaAllocator = .init(maivi.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + var recv_buffer: [0x1000]u8 = undefined; var send_buffer: [0x1000]u8 = undefined; @@ -26,15 +30,22 @@ pub fn task(io: std.Io, stream: std.Io.net.Stream) error{Canceled}!void { var request = server.receiveHead() catch return; const ret = blk: { - const path = helpers.sanitize(maivi.allocator, request.head.target) catch |err| switch (err) { - error.TrailingSlash => return helpers.redirect(&request, request.head.target[0 .. request.head.target.len - 1], .temporary_redirect) catch |e| break :blk e, + const path = helpers.sanitize(allocator, request.head.target) catch |err| switch (err) { + error.TrailingSlash => return { + _ = helpers.redirect( + allocator, + &request, + request.head.target[0 .. request.head.target.len - 1], + .temporary_redirect, + ) catch |e| break :blk e; + }, else => break :blk err, }; - defer maivi.allocator.free(path); dispatch(.{ .request = &request, .handle = stream.socket.handle, .path = path, + .arena = allocator, }) catch |err| break :blk err; }; ret catch |e| { @@ -47,6 +58,7 @@ pub const Connection = struct { request: *Request, handle: std.Io.net.Socket.Handle, path: []const u8, + arena: std.mem.Allocator, }; pub fn dispatch(conn: Connection) !void { diff --git a/src/helpers.zig b/src/helpers.zig index 46489e4..d2d59cc 100644 --- a/src/helpers.zig +++ b/src/helpers.zig @@ -89,17 +89,19 @@ pub fn sendfile(conn: Handler.Connection, dir: std.Io.Dir, path: []const u8) !vo b.state = .end; } -pub fn redirect(request: *Request, uri: []const u8, code: ?Status) !void { - const headers = try std.mem.concat(maivi.allocator, http.Header, &.{ +/// NOTE: returns allocated memory that can optionally be freed by the caller +pub fn redirect(arena: std.mem.Allocator, request: *Request, uri: []const u8, code: ?Status) ![]http.Header { + const headers = try std.mem.concat(arena, http.Header, &.{ &.{SERVER_HEADER}, &.{.{ .name = "location", .value = uri }}, }); - defer maivi.allocator.free(headers); try request.respond(uri, .{ .status = code orelse Status.found, .extra_headers = headers, }); + + return headers; } pub fn statusFromErr(err: anyerror) ?Status { diff --git a/src/root.zig b/src/root.zig index 40aa881..9d72f30 100644 --- a/src/root.zig +++ b/src/root.zig @@ -152,7 +152,7 @@ pub fn handle(conn: handler.Connection) !void { }); } - try path.action(request); + try path.action(conn); // TODO: pre-register all static & build paths // if (dev) @@ -211,7 +211,9 @@ pub fn handletxt(conn: handler.Connection) !void { .msg("redirecting to message path") .str("path", MESSAGE_PATH) .log(); - return helpers.redirect(request, MESSAGE_PATH, null); + return { + _ = try helpers.redirect(conn.arena, request, MESSAGE_PATH, null); + }; } const mdpath = try std.mem.concat(allocator, u8, &.{ request.head.target[0 .. request.head.target.len - 1], ".md" }); @@ -255,8 +257,10 @@ pub fn add_redirects() !void { } } -fn handleredirect(request: *Request) !void { +fn handleredirect(conn: handler.Connection) !void { + const request = conn.request; + const redirect_url = redirects.get(request.head.target) orelse return error.FileNotFound; - try helpers.redirect(request, redirect_url, null); + _ = try helpers.redirect(conn.arena, request, redirect_url, null); } diff --git a/src/router.zig b/src/router.zig index 276b88e..a25afb1 100644 --- a/src/router.zig +++ b/src/router.zig @@ -8,6 +8,7 @@ const zlua = @import("zlua"); const Lua = zlua.Lua; const fragment = @import("fragment.zig"); +const handler = @import("handler.zig"); const helpers = @import("helpers.zig"); const maivi = @import("root.zig"); @@ -21,7 +22,7 @@ pub const Path = struct { return .{ .action = action, .config = cfg orelse .{} }; } - pub const Action = *const fn (request: *Request) anyerror!void; + pub const Action = *const fn (conn: handler.Connection) anyerror!void; pub const Config = struct { allowed_methods: []const http.Method = &.{.GET}, }; @@ -104,7 +105,9 @@ fn lua_add(l: *Lua) !i32 { // TODO: // - set content // - caching? -pub fn handle_lua(request: *Request) !void { +pub fn handle_lua(conn: handler.Connection) !void { + const request = conn.request; + const content_type = helpers.content_type_for_file(request.head.target) orelse .html; var wbuf: [0x4000]u8 = undefined;