I got a State
with an asset variable asset
which holds an open handler to a generic asset directory, whose path is passed as CLI argument:
$ zig build run -- path/to/asset
The goal is to serve all files inside the asset directory.
My solution is the following:
pub fn main() !void {
var args = std.process.args();
const cmd = args.next() orelse unreachable;
const path = args.next() orelse std.debug.panic("too few arguments\nusage: {s} GALLERY_PATH", .{cmd});
if (args.next() != null) {
std.debug.panic("too many arguments\nusage: {s} GALLERY_PATH", .{cmd});
}
var state = State.init(path);
defer state.deinit();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
var server = try httpz.Server(*State).init(allocator, .{ .port = 3000 }, &state);
defer {
server.stop();
server.deinit();
}
}
const State = struct {
asset: *std.fs.Dir,
const Self = @This();
fn init(asset_path: []const u8) Self {
if (std.fs.path.isAbsolute(asset_path)) {
var dir = std.fs.openDirAbsolute(asset_path, .{}) catch |err| std.debug.panic("failed to open absolute gallery path {s}: {any}", .{ asset_path, err });
return .{ .asset = &dir };
} else {
var dir = std.fs.cwd().openDir(asset_path, .{}) catch |err| std.debug.panic("failed to open relative gallery path {s}: {any}", .{ asset_path, err });
return .{ .asset = &dir };
}
}
fn deinit(self: Self) void {
self.asset.close();
}
};
var router = try server.router(.{});
router.get("/static/asset/:name", serve_gallery, .{});
std.log.info("listening on http://127.0.0.1:3000", .{});
try server.listen();
}
fn serve_gallery(state: *State, req: *httpz.Request, res: *httpz.Response) !void {
// Get name of file to serve
const name = req.param("name") orelse {
res.content_type = .TEXT;
res.status = 400;
res.body = "request misses file name";
return;
};
res.content_type = httpz.ContentType.forExtension(std.fs.path.extension(name));
res.body = state.asset.readFileAlloc(res.arena, name, std.math.maxInt(usize)) catch |err| switch (err) {
error.FileNotFound => {
res.content_type = .TEXT;
res.status = 404;
res.body = "file not found";
return;
},
else => {
std.log.err("failed to open requested file {s}: {any}", .{ name, err });
res.content_type = .TEXT;
res.status = 500;
res.body = "failed to open requested file";
return;
},
};
}
But request /static/asset/foo
it just throws an failed to open requested file foo: error.NotDir
.
Keep in mind:
path/to/asset
exists.- I tried deleting and recreating multiple times the directory and its files.
name
param is correct.- CLI argument is correct.
- The same setup, with the same version of zig (
0.15.0-dev.864+75d0ec9c0
) and the same version of httpz (httpz-0.0.0-PNVzrE-8BgCUEVpFtYaUOFrWMqXHBu95eyIYRkXbyriy
), pointing to the same asset directory works on another project.
Any suggestions?