diff --git a/src/http/middleware.zig b/src/http/middleware.zig index 7f4e5f6..32cceca 100644 --- a/src/http/middleware.zig +++ b/src/http/middleware.zig @@ -3,19 +3,41 @@ const root = @import("root"); const builtin = @import("builtin"); const http = @import("./lib.zig"); const util = @import("util"); -//const query_utils = @import("./query.zig"); -//const json_utils = @import("./json.zig"); -const json_utils = util; -const query_utils = util; +const query_utils = @import("./query.zig"); +const json_utils = @import("./json.zig"); +//const json_utils = util; +//const query_utils = util; + +fn printFields(comptime fields: []const std.builtin.Type.StructField) void { + comptime { + inline for (fields) |f| @compileLog(f.name.ptr); + } +} fn AddFields(comptime lhs: type, comptime rhs: type) type { + const fields = std.meta.fields(lhs) ++ std.meta.fields(rhs); + comptime if (false) { + @compileLog("New Type"); + @compileLog("lhs"); + printFields(std.meta.fields(lhs)); + @compileLog("rhs"); + printFields(std.meta.fields(rhs)); + @compileLog("all"); + printFields(fields); + }; const Ctx = @Type(.{ .Struct = .{ .layout = .Auto, - .fields = std.meta.fields(lhs) ++ std.meta.fields(rhs), + .fields = fields, .decls = &.{}, .is_tuple = false, } }); return Ctx; + // return struct { + // path: []const u8, + // fragment: []const u8, + // query_string: []const u8, + // api_source: *anyopaque, + // }; } fn addFields(lhs: anytype, rhs: anytype) AddFields(@TypeOf(lhs), @TypeOf(rhs)) { @@ -117,15 +139,18 @@ pub const default_error_handler = struct { fn handle(_: @This(), req: anytype, res: anytype, ctx: anytype, next: anytype) !void { _ = next; std.log.err("Error {} on uri {s}", .{ ctx.err, req.uri }); - if (!res.was_opened) { - if (res.open(.internal_server_error)) |stream| { - defer stream.close(); - stream.finish() catch {}; - } - } // Tell the server to close the connection after this request res.should_close = true; + + var buf: [1024]u8 = undefined; + var fba = std.heap.FixedBufferAllocator.init(&buf); + var headers = http.Fields.init(fba.allocator()); + if (!res.was_opened) { + var stream = res.open(.internal_server_error, &headers) catch return; + defer stream.close(); + stream.finish() catch {}; + } } }{}; @@ -155,9 +180,9 @@ pub const split_uri = struct { }{}; // routes a request to the correct handler based on declared HTTP method and path -pub fn Router(comptime Routes: []const type) type { +pub fn Router(comptime Routes: type) type { return struct { - routes: std.meta.Tuple(Routes), + routes: Routes, pub fn handle(self: @This(), req: anytype, res: anytype, ctx: anytype, next: void) !void { _ = next; @@ -176,13 +201,8 @@ pub fn Router(comptime Routes: []const type) type { } }; } -fn fieldTypes(comptime Tuple: type) []const type { - var types: [Tuple.len]type = undefined; - for (std.meta.fields(Tuple)) |f, i| types[i] = f.field_type; - return &types; -} -pub fn router(routes: anytype) Router(fieldTypes(@TypeOf(routes))) { - return Router(fieldTypes(@TypeOf(routes))){ .routes = routes }; +pub fn router(routes: anytype) Router(@TypeOf(routes)) { + return Router(@TypeOf(routes)){ .routes = routes }; } // helper function for doing route analysis @@ -212,7 +232,7 @@ pub const Route = struct { fn applies(self: @This(), req: anytype, ctx: anytype) bool { if (self.desc.method != req.method) return false; - const eff_path = if (@hasDecl(ctx, "path")) + const eff_path = if (@hasField(@TypeOf(ctx), "path")) ctx.path else std.mem.sliceTo(req.uri, '?'); @@ -303,7 +323,7 @@ pub fn ParsePathArgs(comptime route: []const u8, comptime Args: type) type { return next.handle( req, res, - addFields(ctx, .{ .args = parsePathArgs(route, Args, req.path) }), + addFields(ctx, .{ .args = try parsePathArgs(route, Args, ctx.path) }), {}, ); } @@ -356,12 +376,13 @@ pub fn ParseBody(comptime Body: type) type { var stream = req.body orelse return error.NoBody; const body = try parseBody(Body, base_content_type orelse .json, stream.reader(), ctx.allocator); - defer ctx.allocator.free(body); + defer util.deepFree(ctx.allocator, body); - return next.handler( + return next.handle( req, res, addFields(ctx, .{ .body = body }), + {}, ); } }; @@ -371,7 +392,7 @@ pub fn ParseQueryParams(comptime QueryParams: type) type { return struct { pub fn handle(_: @This(), req: anytype, res: anytype, ctx: anytype, next: anytype) !void { const query = try query_utils.parseQuery(ctx.allocator, QueryParams, ctx.query_string); - defer ctx.allocator.free(query); + defer util.deepFree(ctx.allocator, query); return next.handle( req,