summaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig94
1 files changed, 53 insertions, 41 deletions
diff --git a/src/main.zig b/src/main.zig
index 9b85d30..b3c1b55 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -42,21 +42,26 @@ const getcwd = std.os.getcwd;
/// The maximum file size is 1 << 21, aka (1 * 2^20), which is 2 MB.
const server_addr = "127.0.0.1";
const server_port = 8080;
-const MAX_PATH_BYTES = fs.MAX_PATH_BYTES;
-const BUFFER_LIMIT = 1 << 21;
+const max_path_bytes = fs.MAX_PATH_BYTES;
+const buffer_limit = 1 << 21;
-/// read_files() reads the file to a provided buffer, and returns the number of
+/// readFiles() reads the file to a provided buffer, and returns the number of
/// bytes read.
-/// read_files() can fail from fmt.allocPrint(), fs.cwd().openFile(),
+/// readFiles() can fail from fmt.allocPrint(), fs.cwd().openFile(),
/// file.stat(), and file.readAll()
/// fmt.allocPrint() will return an AllocPrintError
/// fs.cwd().openFile() will return a File.OpenError
/// file.stat() will return a StatError
/// file.readAll() will return a ReadError
-fn read_files(target: []const u8, buffer: []u8, allocator: mem.Allocator) !usize {
- var file_path = try allocator.alloc(u8, MAX_PATH_BYTES);
+fn readFiles(target: []const u8, buffer: []u8) !usize {
+ const whole_buffer = max_path_bytes * 2;
+ var fba_buffer: [whole_buffer]u8 = undefined;
+ var fba = std.heap.FixedBufferAllocator.init(&fba_buffer);
+ const allocator = fba.allocator();
+
+ var file_path = try allocator.alloc(u8, max_path_bytes);
defer allocator.free(file_path);
- var cwd_buffer = [_]u8{0} ** MAX_PATH_BYTES;
+ var cwd_buffer = [_]u8{0} ** max_path_bytes;
const cwd = try getcwd(&cwd_buffer);
file_path = try fmt.allocPrint(allocator, "{s}{s}", .{ cwd, target });
log.info("Loading file {s}...", .{file_path});
@@ -71,7 +76,7 @@ fn read_files(target: []const u8, buffer: []u8, allocator: mem.Allocator) !usize
} else {
file_path = try fmt.allocPrint(allocator, "{s}/index.html", .{target});
}
- return read_files(file_path, buffer, allocator);
+ return readFiles(file_path, buffer);
},
.file => {
return try file.readAll(buffer);
@@ -82,34 +87,34 @@ fn read_files(target: []const u8, buffer: []u8, allocator: mem.Allocator) !usize
}
}
-/// handle_request() handles the requests from the server and, if necessary,
-/// calls read_files to read requested files.
-/// handle_request() can fail from response.headers.append(), response.do(),
-/// response.writeAll(), response.finish(), and read_files()
+/// handleRequest() handles the requests from the server and, if necessary,
+/// calls readFiles to read requested files.
+/// handleRequest() can fail from response.headers.append(), response.do(),
+/// response.writeAll(), response.finish(), and readFiles()
/// response.headers.append() does not define what error types it will return
/// response.do() does not define what error types it will return
/// response.writeAll() will return a WriteError
/// response.finish() will return a FinishError
-/// read_files() does not define what error types it will return
-/// handle_request handles the following status codes:
+/// readFiles() does not define what error types it will return
+/// handleRequest handles the following status codes:
/// - 200 OK
/// - 403 Forbidden
/// - 404 Not Found
/// - 413 Payload Too Large
/// - 414 URI Too Long
-fn handle_request(response: *http.Server.Response, allocator: mem.Allocator) !void {
+fn handleRequest(response: *http.Server.Response) !void {
// Log the request details
log.info("{s} {s} {s}", .{ @tagName(response.request.method), @tagName(response.request.version), response.request.target });
- // Create a []u8 to read up to BUFFER_LIMIT characters
- var read = [_]u8{0} ** BUFFER_LIMIT;
+ // Create a []u8 to read up to buffer_limit characters
+ var read = [_]u8{0} ** buffer_limit;
// Set "connection" header to "keep-alive" if present in request headers
if (response.request.headers.contains("connection")) {
try response.headers.append("connection", "keep-alive");
}
- const size = read_files(response.request.target, &read, allocator) catch |err| {
+ const size = readFiles(response.request.target, &read) catch |err| {
switch (err) {
error.AccessDenied => {
response.status = .forbidden;
@@ -128,7 +133,7 @@ fn handle_request(response: *http.Server.Response, allocator: mem.Allocator) !vo
try response.do();
return;
};
- if (size >= BUFFER_LIMIT) {
+ if (size >= buffer_limit) {
response.status = .payload_too_large;
response.transfer_encoding = .{ .content_length = 0 };
try response.do();
@@ -201,15 +206,19 @@ fn handle_request(response: *http.Server.Response, allocator: mem.Allocator) !vo
}
}
-/// run_server() accepts inputs from the server, and passes the requests on to
-/// handle_request().
-/// run_server() can fail from server.accept(), response.wait(), and
-/// handle_request().
+/// runServer() accepts inputs from the server, and passes the requests on to
+/// handleRequest().
+/// runServer() can fail from server.accept(), response.wait(), and
+/// handleRequest().
/// server.accept() will return an AcceptError
/// resonse.wait() will return a WaitError
-/// run_server() handles the following error codes:
+/// runServer() handles the following error codes:
/// - 500 (Internal Server Error)
-fn run_server(server: *http.Server, allocator: mem.Allocator) !void {
+fn runServer(server: *http.Server) !void {
+ var fba_buffer: [buffer_limit]u8 = undefined;
+ var fba = std.heap.FixedBufferAllocator.init(&fba_buffer);
+ const allocator = fba.allocator();
+
outer: while (true) {
// Accept incoming connection
var response = try server.accept(.{
@@ -226,7 +235,7 @@ fn run_server(server: *http.Server, allocator: mem.Allocator) !void {
};
// Process the request
- handle_request(&response, allocator) catch |err| {
+ handleRequest(&response) catch |err| {
response.status = .internal_server_error;
response.transfer_encoding = .{ .content_length = 0 };
try response.do();
@@ -236,38 +245,41 @@ fn run_server(server: *http.Server, allocator: mem.Allocator) !void {
}
}
-pub fn print_info() void {
- log.info("zhttpd version 0.1.0, Copyright (C) 2024 ZachIR", .{});
- log.info("zhttpd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions; see the included LICENSE for more details", .{});
+pub fn printInfo(stderr: fs.File.Writer) !void {
+ try stderr.print("zhttpd version 0.1.0, Copyright (C) 2024 ZachIR\n", .{});
+ try stderr.print("zhttpd comes with ABSOLUTELY NO WARRANTY. This is ", .{});
+ try stderr.print("free software, and you are welcome to ", .{});
+ try stderr.print("redistribute it under certain conditions; see the ", .{});
+ try stderr.print("included LICENSE for more details.\n", .{});
}
-/// main() initializes the server, parses the IP and port, and beings
-/// run_server.
-/// main() can fail exit from server.listen() and run_server(), which do not
+/// main() initializes the server, parses the IP and port, and begins
+/// runServer().
+/// main() can fail exit from server.listen() and runServer(), which do not
/// specify the error types they can return.
-/// main() also defines the allocator used by everything else, the
-/// heap.GeneralPurposeAllocator.
pub fn main() !void {
- // Define allocator
- var gpa = heap.GeneralPurposeAllocator(.{}){};
- defer debug.assert(gpa.deinit() == .ok);
- const allocator = gpa.allocator();
+ var fba_buffer: [@sizeOf(http.Server)]u8 = undefined;
+ var fba = heap.FixedBufferAllocator.init(&fba_buffer);
+ const allocator = fba.allocator();
+
+ //const stdout = std.io.getStdOut().writer();
+ const stderr = std.io.getStdErr().writer();
- print_info();
+ try printInfo(stderr);
// Initialize the server
var server = http.Server.init(allocator, .{ .reuse_address = true });
defer server.deinit();
// Log the server address and port
- log.info("Server is running at {s}:{d}", .{ server_addr, server_port });
+ try stderr.print("Server is running at {s}:{d}\n", .{ server_addr, server_port });
// Parse the server address
const address = Address.parseIp(server_addr, server_port) catch unreachable;
try server.listen(address);
// Run the server
- run_server(&server, allocator) catch |err| {
+ runServer(&server) catch |err| {
// Handle server errors
log.err("server error: {}\n", .{err});
if (@errorReturnTrace()) |trace| {