2022-06-23 07:25:50 +00:00
|
|
|
const std = @import("std");
|
|
|
|
const util = @import("util");
|
|
|
|
const http = @import("./lib.zig");
|
|
|
|
|
2022-07-09 22:43:35 +00:00
|
|
|
const connection = @import("./server/connection.zig");
|
|
|
|
const response = @import("./server/response.zig");
|
|
|
|
|
|
|
|
pub const Connection = connection.Connection;
|
|
|
|
pub const Response = response.ResponseStream(Connection.Writer);
|
2022-06-23 07:25:50 +00:00
|
|
|
|
2022-07-09 22:43:35 +00:00
|
|
|
const ConnectionServer = connection.Server;
|
|
|
|
const Request = http.Request;
|
2022-06-23 07:25:50 +00:00
|
|
|
const request_buf_size = 1 << 16;
|
|
|
|
|
2022-07-09 21:18:43 +00:00
|
|
|
pub const Context = struct {
|
|
|
|
alloc: std.mem.Allocator,
|
|
|
|
request: Request,
|
|
|
|
connection: Connection,
|
2022-06-23 07:25:50 +00:00
|
|
|
|
2022-07-09 22:43:35 +00:00
|
|
|
pub fn openResponse(self: *Context, headers: *const http.Headers, status: http.Status) !Response {
|
|
|
|
return try response.open(self.alloc, self.connection.stream.writer(), headers, status);
|
2022-07-09 21:18:43 +00:00
|
|
|
}
|
|
|
|
|
2022-07-09 22:14:49 +00:00
|
|
|
pub fn close(self: *Context) void {
|
2022-07-09 21:18:43 +00:00
|
|
|
// todo: deallocate request
|
2022-07-09 22:14:49 +00:00
|
|
|
self.connection.close();
|
2022-07-09 21:18:43 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-07-09 22:43:35 +00:00
|
|
|
pub const Server = struct {
|
|
|
|
conn_server: ConnectionServer,
|
|
|
|
pub fn listen(addr: std.net.Address) !Server {
|
|
|
|
return Server{
|
|
|
|
.conn_server = try ConnectionServer.listen(addr),
|
2022-07-09 21:18:43 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-07-09 22:43:35 +00:00
|
|
|
pub fn accept(self: *Server, alloc: std.mem.Allocator) !Context {
|
2022-07-09 21:18:43 +00:00
|
|
|
while (true) {
|
|
|
|
const conn = try self.conn_server.accept();
|
|
|
|
errdefer conn.close();
|
|
|
|
|
|
|
|
const req = http.Request.parse(alloc, conn.stream.reader()) catch |err| {
|
2022-07-09 22:17:44 +00:00
|
|
|
handleError(conn.stream.writer(), err) catch unreachable;
|
2022-07-09 21:18:43 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
2022-07-09 22:18:48 +00:00
|
|
|
return Context{ .connection = conn, .request = req, .alloc = alloc };
|
2022-07-09 21:18:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-09 22:43:35 +00:00
|
|
|
pub fn shutdown(self: *Server) void {
|
2022-07-09 21:18:43 +00:00
|
|
|
self.conn_server.shutdown();
|
|
|
|
}
|
|
|
|
};
|
2022-06-23 07:25:50 +00:00
|
|
|
|
2022-07-09 22:17:44 +00:00
|
|
|
// TODO: We should get more specific about what type of errors can happen
|
2022-06-26 06:35:31 +00:00
|
|
|
fn handleError(writer: anytype, err: anyerror) !void {
|
|
|
|
const status: http.Status = switch (err) {
|
|
|
|
error.BadRequest => .bad_request,
|
|
|
|
error.UnsupportedMediaType => .unsupported_media_type,
|
|
|
|
error.HttpVersionNotSupported => .http_version_not_supported,
|
|
|
|
|
2022-07-09 22:17:44 +00:00
|
|
|
else => return err,
|
2022-06-26 06:35:31 +00:00
|
|
|
};
|
|
|
|
|
2022-07-28 03:13:25 +00:00
|
|
|
try writer.print("HTTP/1.1 {} {?s}\r\n\r\n", .{ @enumToInt(status), status.phrase() });
|
2022-06-26 06:35:31 +00:00
|
|
|
}
|