From 2dd4a19e2ee85a239edc87ace60194d35e53ea5f Mon Sep 17 00:00:00 2001 From: Bob Farrell Date: Mon, 5 May 2025 10:31:02 +0100 Subject: [PATCH] Public routing path Set `public_routing_path` config option to specify a request path prefix for public requests. --- demo/src/main.zig | 4 ++++ src/jetzig/config.zig | 4 ++++ src/jetzig/http/Server.zig | 11 +++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/demo/src/main.zig b/demo/src/main.zig index b306e70..454a95a 100644 --- a/demo/src/main.zig +++ b/demo/src/main.zig @@ -66,6 +66,10 @@ pub const jetzig_options = struct { // Path relative to cwd() to serve public content from. Symlinks are not followed. pub const public_content_path = "public"; + /// Request path to map to public directory, e.g. if `public_routing_path` is `"/foo"` then a + /// request to `/foo/bar.png` will serve static content found in `public/bar.png` + pub const public_routing_path = "/"; + // HTTP buffer. Must be large enough to store all headers. This should typically not be modified. pub const http_buffer_size: usize = std.math.pow(usize, 2, 16); diff --git a/src/jetzig/config.zig b/src/jetzig/config.zig index da82dbc..9ac1d95 100644 --- a/src/jetzig/config.zig +++ b/src/jetzig/config.zig @@ -84,6 +84,10 @@ pub const max_connections: u16 = 512; /// Path relative to cwd() to serve public content from. Symlinks are not followed. pub const public_content_path = "public"; +/// Request path to map to public directory, e.g. if `public_routing_path` is `"/foo"` then a +/// request to `/foo/bar.png` will serve static content found in `public/bar.png` +pub const public_routing_path = "/"; + /// Middleware chain. Add any custom middleware here, or use middleware provided in /// `jetzig.middleware` (e.g. `jetzig.middleware.HtmxMiddleware`). pub const middleware = &.{}; diff --git a/src/jetzig/http/Server.zig b/src/jetzig/http/Server.zig index 7c1e073..9aaed47 100644 --- a/src/jetzig/http/Server.zig +++ b/src/jetzig/http/Server.zig @@ -754,9 +754,16 @@ fn matchStaticResource(self: *Server, request: *jetzig.http.Request) !?StaticRes } fn matchPublicContent(self: *Server, request: *jetzig.http.Request) !?StaticResource { - if (request.path.file_path.len <= 1) return null; + const public_routing_path = comptime jetzig.config.get([]const u8, "public_routing_path"); + if (!std.mem.startsWith(u8, request.path.file_path, public_routing_path)) return null; if (request.method != .GET) return null; + const match_path = if (comptime std.mem.endsWith(u8, public_routing_path, "/")) + request.path.file_path[public_routing_path.len..] + else if (request.path.file_path.len <= public_routing_path.len + 1) { + return null; + } else request.path.file_path[public_routing_path.len + 1 ..]; + var iterable_dir = std.fs.cwd().openDir( jetzig.config.get([]const u8, "public_content_path"), .{ .iterate = true, .no_follow = true }, @@ -777,7 +784,7 @@ fn matchPublicContent(self: *Server, request: *jetzig.http.Request) !?StaticReso _ = std.mem.replace(u8, file.path, std.fs.path.sep_str_windows, std.fs.path.sep_str_posix, &path_buffer); break :blk path_buffer[0..file.path.len]; } else file.path; - if (std.mem.eql(u8, file_path, request.path.file_path[1..])) { + if (std.mem.eql(u8, file_path, match_path)) { const content = try iterable_dir.readFileAlloc( request.allocator, file_path,