const std = @import("std");
-var fixed_allocator: std.heap.FixedBufferAllocator = undefined;
-var allocator: std.mem.Allocator = undefined;
+const markdownToHtml = @import("md_to_html.zig").markdownToHtml;
fn parentDirPath(path: []const u8) ?[]const u8 {
for (0..path.len) |idx| {
}
}
-fn handleClient(connection: std.net.Server.Connection) !void {
+fn handleClient(parent_allocator: std.mem.Allocator, connection: std.net.Server.Connection) !void {
+ const alloc_buffer = try parent_allocator.alloc(u8, 65_536);
+ defer parent_allocator.free(alloc_buffer);
+
+ var fixed_allocator = std.heap.FixedBufferAllocator.init(alloc_buffer);
+ const allocator = fixed_allocator.allocator();
+
var read_buffer: [4_096]u8 = undefined;
+ var send_buffer = std.ArrayList(u8).init(allocator);
+ var layout_buffer = std.ArrayList(u8).init(allocator);
+ var temp_buffer = std.ArrayList(u8).init(allocator);
+
+ defer send_buffer.deinit();
+ defer layout_buffer.deinit();
+ defer temp_buffer.deinit();
+
var server = std.http.Server.init(connection, &read_buffer);
const cwd = std.fs.cwd();
while (true) {
defer fixed_allocator.reset();
- var send_buffer = std.ArrayList(u8).init(allocator);
- defer send_buffer.deinit();
+ defer send_buffer.clearAndFree();
+ defer layout_buffer.clearAndFree();
+ defer temp_buffer.clearAndFree();
var request = try server.receiveHead();
const file_reader = file.reader();
try file_reader.readAllArrayList(&send_buffer, std.math.maxInt(usize));
- } else {
+ } else blk: {
+ { // Layout file.
+ var layout_file = public_dir.openFile("layout.html", .{}) catch {
+ std.log.err("Could not open layout file.", .{});
+ break :blk;
+ };
+
+ defer layout_file.close();
+
+ const layout_file_reader = layout_file.reader();
+ try layout_file_reader.readAllArrayList(&layout_buffer, std.math.maxInt(usize));
+ }
+
var maybe_index_file: ?std.fs.File = null;
index_file: {
- blk: {
- var route_dir = public_dir.openDir(route, .{}) catch break :blk;
- defer route_dir.close();
-
- maybe_index_file = route_dir.openFile("index.html", .{}) catch break :blk;
+ route_dir: {
+ var is_public: bool = undefined;
+ var route_dir: std.fs.Dir = undefined;
+
+ if (route.len == 0) {
+ route_dir = public_dir;
+ is_public = true;
+ } else {
+ route_dir = public_dir.openDir(route, .{}) catch break :route_dir;
+ is_public = false;
+ }
+
+ defer {
+ if (!is_public) {
+ route_dir.close();
+ }
+ }
+
+ maybe_index_file = route_dir.openFile("index.html", .{}) catch break :route_dir;
break :index_file;
}
try path_ext.appendSlice(route);
try path_ext.appendSlice(".html");
- if (public_dir.openFile(route, .{})) |index_file| {
+ if (public_dir.openFile(path_ext.items, .{})) |index_file| {
maybe_index_file = index_file;
} else |_| {
//
defer index_file.close();
const index_file_reader = index_file.reader();
- try index_file_reader.readAllArrayList(&send_buffer, std.math.maxInt(usize));
+ try index_file_reader.readAllArrayList(&temp_buffer, std.math.maxInt(usize));
+ } else {
+ var path_ext = std.ArrayList(u8).init(allocator);
+ defer path_ext.deinit();
+
+ try path_ext.appendSlice(route);
+ try path_ext.appendSlice(".md");
+
+ var md_file = public_dir.openFile(path_ext.items, .{}) catch break :blk;
+ defer md_file.close();
+
+ const md_file_reader = md_file.reader();
+
+ const temp_buffer_writer = temp_buffer.writer();
+
+ try markdownToHtml(temp_buffer_writer.any(), md_file_reader.any());
}
+
+ try send_buffer.resize(layout_buffer.items.len + temp_buffer.items.len - 3);
+ _ = std.mem.replace(u8, layout_buffer.items, "{s}", temp_buffer.items, send_buffer.items);
}
try request.respond(send_buffer.items, .{});
}
}
-fn handleClientThread(connection: std.net.Server.Connection) void {
- handleClient(connection) catch {};
+fn handleClientThread(parent_allocator: std.mem.Allocator, connection: std.net.Server.Connection) void {
+ handleClient(parent_allocator, connection) catch |err| {
+ switch (err) {
+ error.HttpConnectionClosing => std.log.info("Client {} disconnected.", .{connection.address}),
+ else => std.log.err("Client {} errored with code {}", .{ connection.address, err }),
+ }
+ };
}
pub fn main() !void {
- var buffer: [65_536]u8 = undefined;
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
+ defer _ = gpa.deinit();
- fixed_allocator = std.heap.FixedBufferAllocator.init(&buffer);
- allocator = fixed_allocator.allocator();
+ const gpa_allocator = gpa.allocator();
const server_addr = try std.net.Address.parseIp("0.0.0.0", 3000);
std.log.info("Connection from {}.", .{connection.address});
- const thread = try std.Thread.spawn(.{}, handleClientThread, .{connection});
+ const thread = try std.Thread.spawn(.{}, handleClientThread, .{ gpa_allocator, connection });
thread.detach();
}
}