const std = @import("std"); // extremely basic http file server pub fn main() !void { var allocator = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = allocator.deinit(); const alloc = allocator.allocator(); var svr = std.http.Server.init(alloc, .{.reuse_address = true}); defer svr.deinit(); const addr = try std.net.Address.resolveIp("127.0.0.1", 8080); try svr.listen(addr); while (true) { var res = try svr.accept(.{.allocator = alloc }); defer res.deinit(); try res.wait(); const target = res.request.target; const path = try std.fs.path.join(alloc, &[_][]const u8{".", target}); defer alloc.free(path); if (std.fs.cwd().openFile(path, .{})) |file| { const md = try file.metadata(); if (md.kind() == .directory) { const index_path = try std.fs.path.join(alloc, &[_][]const u8{path, "index.html"}); defer alloc.free(index_path); if (std.fs.cwd().openFile(index_path, .{})) |index_file| { const index_md = try index_file.metadata(); try serve_file(&res, index_file, index_md); } else |_| { try serve_error(&res, .not_found); } } else { try serve_file(&res, file, md); } } else |err| { switch (err) { error.FileNotFound => try serve_error(&res, .not_found), else => try serve_error(&res, .bad_request), } } try res.finish(); } } fn serve_file(res: *std.http.Server.Response, file: std.fs.File, md: std.fs.File.Metadata) !void { res.transfer_encoding = .{ .content_length = md.size() }; try res.do(); var buf = [_]u8{0} ** 1024; while (true) { const read = try file.read(&buf); if (read == 0) break; _ = try res.write(buf[0..read]); } } fn serve_error(res: *std.http.Server.Response, status: std.http.Status) !void { res.status = status; const msg = \\ error! ; res.transfer_encoding = . { .content_length = msg.len }; try res.do(); _ = try res.write(msg); }