diff options
Diffstat (limited to 'src/main.zig')
-rw-r--r-- | src/main.zig | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/src/main.zig b/src/main.zig index 1e62272..f074fde 100644 --- a/src/main.zig +++ b/src/main.zig @@ -43,10 +43,16 @@ const buffer_limit = 1 << 21; /// file.stat() will return a StatError /// file.readAll() will return a ReadError fn readFiles(target: []const u8, buffer: []u8) !usize { + // fba_buffer is the maximum malloc size for this functiono, as it's using + // a Fixed Buffer Allocator. It needs to be able to contain file_path, + // which is max_path_bytes in size, twice over, because it may also get + // allocPrint'ed to if the provided target is a directory. var fba_buffer: [max_path_bytes * 2]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&fba_buffer); const allocator = fba.allocator(); + // `target` is relative to the root of the http server; for now, it's + // going to assume the root (/) is the current working directory. var file_path = try allocator.alloc(u8, max_path_bytes); defer allocator.free(file_path); var cwd_buffer = [_]u8{0} ** max_path_bytes; @@ -59,6 +65,9 @@ fn readFiles(target: []const u8, buffer: []u8) !usize { defer file.close(); var stat = try file.stat(); switch (stat.kind) { + // If the path is a directory, it needs to get the file at + // directory/index.html. This isn't technically the standard + // (probably), but it's the assumption I will make for now. .directory => { if (std.mem.endsWith(u8, target, "/")) { file_path = try std.fmt.allocPrint(allocator, "{s}index.html", .{target}); @@ -67,9 +76,13 @@ fn readFiles(target: []const u8, buffer: []u8) !usize { } return readFiles(file_path, buffer); }, + // If it's a file then write all of the contents (up to buffer_limit + // bytes) into the provided arg buffer, and return the number of bytes + // written. .file => { return try file.readAll(buffer); }, + // Otherwise, it's an error I'm not going to handle. else => { return 0; }, @@ -103,26 +116,38 @@ fn handleRequest(response: *std.http.Server.Response) !void { try response.headers.append("connection", "keep-alive"); } + // First try to read the file into the read buffer; also handle and return + // certain easy error codes here const size = readFiles(response.request.target, &read) catch |err| { switch (err) { + // Return an error 403 if the file is denied because of permissions error.AccessDenied => { response.status = .forbidden; }, + // Return an error 404 if the file is not found error.FileNotFound => { response.status = .not_found; }, + // Return an error 414 if the URI is too long to be read error.OutOfMemory => { response.status = .uri_too_long; }, + // Otherwise, some other error happened that I don't know. This + // will eventually return an error 500 else => { return err; }, } + // For all of the above error cases, it's not actually returning any + // data, so .content_length is 0 response.transfer_encoding = .{ .content_length = 0 }; try response.do(); return; }; if (size >= buffer_limit) { + // If the amount read into read is as big as the buffer_limit, that + // means there was more text than could be processed and so this will + // return an error 413 response.status = .payload_too_large; response.transfer_encoding = .{ .content_length = 0 }; try response.do(); @@ -130,12 +155,13 @@ fn handleRequest(response: *std.http.Server.Response) !void { } else if (size > 0) { // Get the file extension, and set the content-type header if it exists // (using mime.zig) - // To do this, we iterate through response.request.target in reverse + // To do this, iterate through response.request.target in reverse // looking for a '/' or a '.' // a '/' indicates a directory, so there is no extension // a '.' indicates a file extension var i: usize = response.request.target.len; var mime_type: ?mime.Type = undefined; + // TODO properly handle files with no extension if (std.mem.endsWith(u8, response.request.target, "/")) { log.warn("Dir requested, returning index.html!", .{}); try response.headers.append("content-type", "text/html"); @@ -168,6 +194,7 @@ fn handleRequest(response: *std.http.Server.Response) !void { if (mime_type) |mime_val| { try response.headers.append("content-type", @tagName(mime_val)); } else { + // Should maybe return error 415? try response.headers.append("content-type", "text/plain"); } } |