web: fix compile errors and critical runtime errors
This commit is contained in:
@@ -14,6 +14,22 @@ pub fn build(b: *std.Build) void {
|
|||||||
.root_module = module,
|
.root_module = module,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const exe_module = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.imports = &.{
|
||||||
|
.{ .name = "web", .module = module },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "web",
|
||||||
|
.root_module = exe_module,
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
const run_tests = b.addRunArtifact(tests);
|
const run_tests = b.addRunArtifact(tests);
|
||||||
|
|
||||||
const test_step = b.step("test", "Run tests");
|
const test_step = b.step("test", "Run tests");
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub const FileDescriptor = enum(i32) {
|
|||||||
stderr = 2,
|
stderr = 2,
|
||||||
_,
|
_,
|
||||||
|
|
||||||
pub fn memfd_create(name: [*:0]const u8, flags: u32) FileDescriptor {
|
pub fn memfd_create(name: [*:0]const u8, flags: u32) !FileDescriptor {
|
||||||
const rc = linux.memfd_create(name, flags);
|
const rc = linux.memfd_create(name, flags);
|
||||||
return switch (errno(rc)) {
|
return switch (errno(rc)) {
|
||||||
.SUCCESS => @enumFromInt(@as(i32, @intCast(rc))),
|
.SUCCESS => @enumFromInt(@as(i32, @intCast(rc))),
|
||||||
@@ -17,7 +17,7 @@ pub const FileDescriptor = enum(i32) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn socket(domain: u32, socket_type: u32, protocol: u32) FileDescriptor {
|
pub fn socket(domain: u32, socket_type: u32, protocol: u32) !FileDescriptor {
|
||||||
const rc = linux.socket(domain, socket_type, protocol);
|
const rc = linux.socket(domain, socket_type, protocol);
|
||||||
return switch (errno(rc)) {
|
return switch (errno(rc)) {
|
||||||
.SUCCESS => @enumFromInt(@as(i32, @intCast(rc))),
|
.SUCCESS => @enumFromInt(@as(i32, @intCast(rc))),
|
||||||
@@ -30,7 +30,7 @@ pub const FileDescriptor = enum(i32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept(self: FileDescriptor, noalias addr: ?*linux.sockaddr, noalias len: ?*linux.socklen_t) !FileDescriptor {
|
pub fn accept(self: FileDescriptor, noalias addr: ?*linux.sockaddr, noalias len: ?*linux.socklen_t) !FileDescriptor {
|
||||||
const rc = linux.accept(@intFromEnum(self), &addr, &len);
|
const rc = linux.accept(@intFromEnum(self), addr, len);
|
||||||
return switch (errno(rc)) {
|
return switch (errno(rc)) {
|
||||||
.SUCCESS => @enumFromInt(@as(i32, @intCast(rc))),
|
.SUCCESS => @enumFromInt(@as(i32, @intCast(rc))),
|
||||||
.CONNABORTED => return error.ConnectionAborted,
|
.CONNABORTED => return error.ConnectionAborted,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const errno = linux.E.init;
|
|||||||
fd: FileDescriptor,
|
fd: FileDescriptor,
|
||||||
address: std.net.Address,
|
address: std.net.Address,
|
||||||
workers: []Worker,
|
workers: []Worker,
|
||||||
|
threads: []std.Thread,
|
||||||
request_router: RequestRouter,
|
request_router: RequestRouter,
|
||||||
|
|
||||||
connection_queue: std.DoublyLinkedList,
|
connection_queue: std.DoublyLinkedList,
|
||||||
@@ -65,21 +66,22 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Server {
|
|||||||
|
|
||||||
var socklen = options.address.getOsSockLen();
|
var socklen = options.address.getOsSockLen();
|
||||||
try fd.bind(&options.address.any, socklen);
|
try fd.bind(&options.address.any, socklen);
|
||||||
try fd.listen(options.kernel_backlog);
|
try fd.listen(options.max_connections);
|
||||||
|
|
||||||
var listen_address = options.address;
|
var listen_address = options.address;
|
||||||
try fd.getsockname(fd, &listen_address, &socklen);
|
try fd.getsockname(&listen_address.any, &socklen);
|
||||||
|
|
||||||
// Allocate workers
|
// Allocate arrays
|
||||||
|
|
||||||
const workers = try allocator.alloc(Worker, worker_count);
|
const workers = try allocator.alloc(Worker, worker_count);
|
||||||
errdefer allocator.free(workers);
|
errdefer allocator.free(workers);
|
||||||
|
|
||||||
// Allocate connection pool
|
|
||||||
|
|
||||||
const connection_buffer = try allocator.alloc(Connection, options.max_connections);
|
const connection_buffer = try allocator.alloc(Connection, options.max_connections);
|
||||||
errdefer allocator.free(connection_buffer);
|
errdefer allocator.free(connection_buffer);
|
||||||
|
|
||||||
|
const threads = try allocator.alloc(std.Thread, worker_count);
|
||||||
|
errdefer allocator.free(threads);
|
||||||
|
|
||||||
// Allocate and remap read buffers
|
// Allocate and remap read buffers
|
||||||
|
|
||||||
const single_read_buffer_size = @as(usize, options.read_buffer_pages) * huge_page_size;
|
const single_read_buffer_size = @as(usize, options.read_buffer_pages) * huge_page_size;
|
||||||
@@ -91,7 +93,7 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Server {
|
|||||||
const read_buffer_fd: FileDescriptor = try .memfd_create("read_buffer", 0);
|
const read_buffer_fd: FileDescriptor = try .memfd_create("read_buffer", 0);
|
||||||
defer read_buffer_fd.close();
|
defer read_buffer_fd.close();
|
||||||
|
|
||||||
try read_buffer_fd.ftruncate(all_read_buffers_size);
|
try read_buffer_fd.ftruncate(@intCast(all_read_buffers_size));
|
||||||
|
|
||||||
const read_buffer_ptr = try errOrPtr(linux.mmap(
|
const read_buffer_ptr = try errOrPtr(linux.mmap(
|
||||||
null,
|
null,
|
||||||
@@ -114,7 +116,7 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Server {
|
|||||||
linux.PROT.READ | linux.PROT.WRITE,
|
linux.PROT.READ | linux.PROT.WRITE,
|
||||||
linux.MAP{ .TYPE = .SHARED, .FIXED = true },
|
linux.MAP{ .TYPE = .SHARED, .FIXED = true },
|
||||||
@intFromEnum(read_buffer_fd),
|
@intFromEnum(read_buffer_fd),
|
||||||
offset,
|
@intCast(offset),
|
||||||
));
|
));
|
||||||
|
|
||||||
try err(linux.mmap(
|
try err(linux.mmap(
|
||||||
@@ -123,7 +125,7 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Server {
|
|||||||
linux.PROT.READ | linux.PROT.WRITE,
|
linux.PROT.READ | linux.PROT.WRITE,
|
||||||
linux.MAP{ .TYPE = .SHARED, .FIXED = true },
|
linux.MAP{ .TYPE = .SHARED, .FIXED = true },
|
||||||
@intFromEnum(read_buffer_fd),
|
@intFromEnum(read_buffer_fd),
|
||||||
offset,
|
@intCast(offset),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,13 +164,14 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Server {
|
|||||||
|
|
||||||
var connection_pool: std.DoublyLinkedList = .{};
|
var connection_pool: std.DoublyLinkedList = .{};
|
||||||
for (connection_buffer) |*c| {
|
for (connection_buffer) |*c| {
|
||||||
connection_pool.prepend(c.node);
|
connection_pool.prepend(&c.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.fd = fd,
|
.fd = fd,
|
||||||
.address = listen_address,
|
.address = listen_address,
|
||||||
.workers = workers,
|
.workers = workers,
|
||||||
|
.threads = threads,
|
||||||
.request_router = options.request_router,
|
.request_router = options.request_router,
|
||||||
|
|
||||||
.connection_queue = .{},
|
.connection_queue = .{},
|
||||||
@@ -184,7 +187,9 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Server {
|
|||||||
pub fn deinit(self: *Server, allocator: std.mem.Allocator) void {
|
pub fn deinit(self: *Server, allocator: std.mem.Allocator) void {
|
||||||
// TODO Deinitialize workers
|
// TODO Deinitialize workers
|
||||||
self.fd.close();
|
self.fd.close();
|
||||||
|
allocator.free(self.threads);
|
||||||
allocator.free(self.connection_buffer);
|
allocator.free(self.connection_buffer);
|
||||||
|
allocator.free(self.workers);
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,13 +203,13 @@ pub fn listen(self: *Server, running: *const std.atomic.Value(bool)) !void {
|
|||||||
defer {
|
defer {
|
||||||
worker_running.store(false, .release);
|
worker_running.store(false, .release);
|
||||||
self.cond_connection_queued.broadcast();
|
self.cond_connection_queued.broadcast();
|
||||||
for (self.workers[0..spawned]) |*worker| {
|
for (self.threads[0..spawned]) |*thread| {
|
||||||
worker.thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.workers) |*worker| {
|
for (self.workers, 0..) |*worker, i| {
|
||||||
worker.thread = try std.Thread.spawn(.{}, Worker.worker, .{ worker, self, &worker_running });
|
self.threads[i] = try std.Thread.spawn(.{}, Worker.worker, .{ worker, self, &worker_running });
|
||||||
spawned += 1;
|
spawned += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +245,7 @@ pub fn listen(self: *Server, running: *const std.atomic.Value(bool)) !void {
|
|||||||
|
|
||||||
fn err(rc: usize) !void {
|
fn err(rc: usize) !void {
|
||||||
const e = errno(rc);
|
const e = errno(rc);
|
||||||
return if (e != .SUCCESS) error.SystemError else rc;
|
return if (e != .SUCCESS) error.SystemError else {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn errOrPtr(rc: usize) ![*]u8 {
|
fn errOrPtr(rc: usize) ![*]u8 {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ read_buffer_size: usize,
|
|||||||
read_head: usize,
|
read_head: usize,
|
||||||
read_tail: usize,
|
read_tail: usize,
|
||||||
|
|
||||||
write_buffer: []const u8,
|
write_buffer: []u8,
|
||||||
|
|
||||||
pub fn worker(
|
pub fn worker(
|
||||||
self: *Worker,
|
self: *Worker,
|
||||||
@@ -31,11 +31,11 @@ pub fn worker(
|
|||||||
server.mutex.unlock();
|
server.mutex.unlock();
|
||||||
defer {
|
defer {
|
||||||
server.mutex.lock();
|
server.mutex.lock();
|
||||||
server.connection_pool.append(self.connection.node);
|
server.connection_pool.append(&connection.node);
|
||||||
server.cond_connection_freed.signal();
|
server.cond_connection_freed.signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.handleConnection(server, server.request_router, connection, running) catch |err| {
|
self.handleConnection(server.request_router, connection, running) catch |err| {
|
||||||
std.log.err("Error while handling connection: {}", .{err});
|
std.log.err("Error while handling connection: {}", .{err});
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -53,8 +53,9 @@ fn handleConnection(
|
|||||||
defer connection.deinit();
|
defer connection.deinit();
|
||||||
|
|
||||||
while (running.load(.acquire)) {
|
while (running.load(.acquire)) {
|
||||||
const res = self.handleRequest(request_router, running) catch |err| {
|
const res = self.handleRequest(request_router, connection) catch |err| {
|
||||||
std.log.err("Error while handling request: {}", .{err});
|
std.log.err("Error while handling request: {}", .{err});
|
||||||
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!res) break;
|
if (!res) break;
|
||||||
@@ -68,6 +69,11 @@ fn handleRequest(
|
|||||||
) !bool {
|
) !bool {
|
||||||
var response: Response = .init(connection, self.write_buffer);
|
var response: Response = .init(connection, self.write_buffer);
|
||||||
var parser: http.Parser = .init(request_router, &response);
|
var parser: http.Parser = .init(request_router, &response);
|
||||||
|
defer {
|
||||||
|
if (parser.request_handler) |rh| {
|
||||||
|
rh.rawFinalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var leftover_bytes = self.read_tail - self.read_head;
|
var leftover_bytes = self.read_tail - self.read_head;
|
||||||
const max_read_tail = self.read_head + self.read_buffer_size;
|
const max_read_tail = self.read_head + self.read_buffer_size;
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ pub const Name = union(enum) {
|
|||||||
|
|
||||||
/// Maps **lowercased** header names to enum values.
|
/// Maps **lowercased** header names to enum values.
|
||||||
pub const map: std.StaticStringMap(Known) = blk: {
|
pub const map: std.StaticStringMap(Known) = blk: {
|
||||||
|
@setEvalBranchQuota(20000);
|
||||||
const fields = @typeInfo(Known).@"enum".fields;
|
const fields = @typeInfo(Known).@"enum".fields;
|
||||||
|
|
||||||
var kvs_list: [fields.len]struct { []const u8, Known } = undefined;
|
var kvs_list: [fields.len]struct { []const u8, Known } = undefined;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const vec_len = @typeInfo(Vec).vector.len;
|
|||||||
const Pattern = struct {
|
const Pattern = struct {
|
||||||
value: Vec,
|
value: Vec,
|
||||||
mask: Vec,
|
mask: Vec,
|
||||||
len: u6,
|
len: u32,
|
||||||
|
|
||||||
pub fn init(comptime prefix: []const u8) Pattern {
|
pub fn init(comptime prefix: []const u8) Pattern {
|
||||||
if (prefix.len > vec_len) {
|
if (prefix.len > vec_len) {
|
||||||
@@ -40,6 +40,12 @@ const Pattern = struct {
|
|||||||
mask[i] = 0x00;
|
mask[i] = 0x00;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.value = value,
|
||||||
|
.mask = mask,
|
||||||
|
.len = prefix.len,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn check(self: Pattern, vec: Vec) bool {
|
inline fn check(self: Pattern, vec: Vec) bool {
|
||||||
@@ -199,21 +205,22 @@ pub fn consume(self: *Parser, chars: []const u8) Error!ConsumeResult {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
if (chars.len - i >= vec_len) {
|
// TODO Fix
|
||||||
const vec_res = try self.consumeVec(chars[i..][0..vec_len]);
|
// if (chars.len - i >= vec_len) {
|
||||||
i += vec_res.consumed;
|
// const vec_res = try self.consumeVec(chars[i..][0..vec_len]);
|
||||||
|
// i += vec_res.consumed;
|
||||||
|
|
||||||
if (vec_res.done) {
|
// if (vec_res.done) {
|
||||||
return .{
|
// return .{
|
||||||
.consumed = i,
|
// .consumed = i,
|
||||||
.done = true,
|
// .done = true,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (vec_res.consumed > 0) {
|
// if (vec_res.consumed > 0) {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
const char_res = try self.consumeChar(&chars[i]);
|
const char_res = try self.consumeChar(&chars[i]);
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -231,7 +238,8 @@ pub fn consume(self: *Parser, chars: []const u8) Error!ConsumeResult {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn consumeVec(self: *Parser, vec: *const [vec_len]u8) Error!ConsumeResult {
|
pub fn consumeVec(self: *Parser, vec_ptr: *const [vec_len]u8) Error!ConsumeResult {
|
||||||
|
const vec: Vec = vec_ptr.*;
|
||||||
switch (self.state) {
|
switch (self.state) {
|
||||||
.init => {
|
.init => {
|
||||||
inline for (@typeInfo(patterns.methods).@"struct".decls) |decl| {
|
inline for (@typeInfo(patterns.methods).@"struct".decls) |decl| {
|
||||||
@@ -257,6 +265,10 @@ pub fn consumeVec(self: *Parser, vec: *const [vec_len]u8) Error!ConsumeResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.state = .pathname(s.method, s.pathname.ptr[0 .. s.pathname.len + vec_len]);
|
self.state = .pathname(s.method, s.pathname.ptr[0 .. s.pathname.len + vec_len]);
|
||||||
|
return .{
|
||||||
|
.consumed = vec_len,
|
||||||
|
.done = false,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
.pathname_complete => {
|
.pathname_complete => {
|
||||||
if (patterns.@"version_http/1.1".check(vec)) {
|
if (patterns.@"version_http/1.1".check(vec)) {
|
||||||
@@ -279,6 +291,10 @@ pub fn consumeVec(self: *Parser, vec: *const [vec_len]u8) Error!ConsumeResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.state = .headerValue(s.name, s.value.ptr[0 .. s.value.len + vec_len]);
|
self.state = .headerValue(s.name, s.value.ptr[0 .. s.value.len + vec_len]);
|
||||||
|
return .{
|
||||||
|
.consumed = vec_len,
|
||||||
|
.done = false,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
// Delegate to `consumeChar`.
|
// Delegate to `consumeChar`.
|
||||||
@@ -444,7 +460,7 @@ pub fn consumeChar(self: *Parser, c_ptr: *const u8) Error!ConsumeCharResult {
|
|||||||
self.content_length = std.fmt.parseInt(usize, header.value, 10) catch return error.InvalidContentLength;
|
self.content_length = std.fmt.parseInt(usize, header.value, 10) catch return error.InvalidContentLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.request_handler.rawHeader(header) catch |err| {
|
self.request_handler.?.rawHeader(self.response, header) catch |err| {
|
||||||
self.last_handler_error = err;
|
self.last_handler_error = err;
|
||||||
return error.HandlerError;
|
return error.HandlerError;
|
||||||
};
|
};
|
||||||
@@ -458,7 +474,10 @@ pub fn consumeChar(self: *Parser, c_ptr: *const u8) Error!ConsumeCharResult {
|
|||||||
.headers_end => switch (c) {
|
.headers_end => switch (c) {
|
||||||
'\n' => {
|
'\n' => {
|
||||||
if (self.content_length == 0) {
|
if (self.content_length == 0) {
|
||||||
self.handler.rawBody(self.request, &.{});
|
self.request_handler.?.rawBody(self.response, &.{}) catch |err| {
|
||||||
|
self.last_handler_error = err;
|
||||||
|
return error.HandlerError;
|
||||||
|
};
|
||||||
return .done;
|
return .done;
|
||||||
}
|
}
|
||||||
self.state = .{ .body = @as([*]const u8, @ptrCast(c_ptr))[1..1] };
|
self.state = .{ .body = @as([*]const u8, @ptrCast(c_ptr))[1..1] };
|
||||||
@@ -469,7 +488,10 @@ pub fn consumeChar(self: *Parser, c_ptr: *const u8) Error!ConsumeCharResult {
|
|||||||
const new_body = body.ptr[0 .. body.len + 1];
|
const new_body = body.ptr[0 .. body.len + 1];
|
||||||
self.state = .{ .body = new_body };
|
self.state = .{ .body = new_body };
|
||||||
if (new_body.len >= self.content_length) {
|
if (new_body.len >= self.content_length) {
|
||||||
self.handler.rawBody(self.request, new_body);
|
self.request_handler.?.rawBody(self.response, new_body) catch |err| {
|
||||||
|
self.last_handler_error = err;
|
||||||
|
return error.HandlerError;
|
||||||
|
};
|
||||||
return .done;
|
return .done;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,17 +1,9 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const http = @import("http.zig");
|
const web = @import("web");
|
||||||
|
|
||||||
const Connection = @import("Connection.zig");
|
|
||||||
const Response = @import("Response.zig");
|
|
||||||
const RequestHandler = @import("RequestHandler.zig");
|
|
||||||
const RequestRouter = @import("RequestRouter.zig");
|
|
||||||
const Route = @import("Route.zig");
|
|
||||||
const Server = @import("Server.zig");
|
|
||||||
const UUID = @import("UUID.zig");
|
|
||||||
const Worker = @import("Worker.zig");
|
|
||||||
|
|
||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const errno = linux.E.init;
|
const errno = linux.E.init;
|
||||||
|
const UUID = web.UUID;
|
||||||
|
|
||||||
var running: std.atomic.Value(bool) = .init(true);
|
var running: std.atomic.Value(bool) = .init(true);
|
||||||
|
|
||||||
@@ -33,7 +25,7 @@ const Router = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interface(self: *Router) RequestRouter {
|
fn interface(self: *Router) web.RequestRouter {
|
||||||
return .{
|
return .{
|
||||||
.ptr = self,
|
.ptr = self,
|
||||||
.vtable = &.{
|
.vtable = &.{
|
||||||
@@ -42,11 +34,11 @@ const Router = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn onRoute(ctx: *anyopaque, route: Route) !RequestHandler {
|
fn onRoute(ctx: *anyopaque, route: web.Route) !web.RequestHandler {
|
||||||
const self: *Router = @ptrCast(@alignCast(ctx));
|
const self: *Router = @ptrCast(@alignCast(ctx));
|
||||||
|
|
||||||
const handler = try self.allocator.create(Handler);
|
const handler = try self.allocator.create(Handler);
|
||||||
handler.* = .init(self.allocator, route);
|
handler.* = try .init(self.allocator, route);
|
||||||
return handler.interface();
|
return handler.interface();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -54,7 +46,7 @@ const Router = struct {
|
|||||||
const Handler = struct {
|
const Handler = struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
route: Route,
|
route: web.Route,
|
||||||
uuid: UUID,
|
uuid: UUID,
|
||||||
timer: std.time.Timer,
|
timer: std.time.Timer,
|
||||||
|
|
||||||
@@ -63,17 +55,17 @@ const Handler = struct {
|
|||||||
accept_language: ?[]const u8 = null,
|
accept_language: ?[]const u8 = null,
|
||||||
user_agent: ?[]const u8 = null,
|
user_agent: ?[]const u8 = null,
|
||||||
|
|
||||||
fn init(allocator: std.mem.Allocator, route: Route) Handler {
|
fn init(allocator: std.mem.Allocator, route: web.Route) !Handler {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
|
|
||||||
.route = route,
|
.route = route,
|
||||||
.uuid = UUID.v7(),
|
.uuid = UUID.v7(),
|
||||||
.timer = .start(),
|
.timer = try .start(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interface(self: *Handler) RequestHandler {
|
fn interface(self: *Handler) web.RequestHandler {
|
||||||
return .{
|
return .{
|
||||||
.ptr = self,
|
.ptr = self,
|
||||||
.vtable = &.{
|
.vtable = &.{
|
||||||
@@ -84,7 +76,7 @@ const Handler = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn onHeader(ctx: *anyopaque, response: *Response, header: http.Header) void {
|
fn onHeader(ctx: *anyopaque, response: *web.Response, header: web.http.Header) !void {
|
||||||
const self: *Handler = @ptrCast(@alignCast(ctx));
|
const self: *Handler = @ptrCast(@alignCast(ctx));
|
||||||
|
|
||||||
switch (header.name) {
|
switch (header.name) {
|
||||||
@@ -101,6 +93,7 @@ const Handler = struct {
|
|||||||
.@"User-Agent" => {
|
.@"User-Agent" => {
|
||||||
self.user_agent = header.value;
|
self.user_agent = header.value;
|
||||||
},
|
},
|
||||||
|
else => {},
|
||||||
},
|
},
|
||||||
.other => {},
|
.other => {},
|
||||||
}
|
}
|
||||||
@@ -108,12 +101,12 @@ const Handler = struct {
|
|||||||
_ = response;
|
_ = response;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn onBody(ctx: *anyopaque, response: *Response, body: []const u8) !void {
|
fn onBody(ctx: *anyopaque, response: *web.Response, body: []const u8) !void {
|
||||||
const self: *Handler = @ptrCast(@alignCast(ctx));
|
const self: *Handler = @ptrCast(@alignCast(ctx));
|
||||||
|
|
||||||
try response.sendResponse(.{
|
try response.sendResponse(.{
|
||||||
.media_type = "application/json",
|
.media_type = "application/json",
|
||||||
.response_body = "{\"ok\":true}",
|
.response_body = "{\"ok\":true}\r\n",
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = self;
|
_ = self;
|
||||||
@@ -126,7 +119,7 @@ const Handler = struct {
|
|||||||
const time_ns = self.timer.read();
|
const time_ns = self.timer.read();
|
||||||
const time_us_ceil = (time_ns + std.time.ns_per_us - 1) / std.time.ns_per_us;
|
const time_us_ceil = (time_ns + std.time.ns_per_us - 1) / std.time.ns_per_us;
|
||||||
|
|
||||||
std.log.info("{s} {s} (<={} [µs])", .{ @tagName(self.route.method), self.route.pathname, time_us_ceil });
|
std.log.info("{s} {s} ({} µs)", .{ @tagName(self.route.method), self.route.pathname, time_us_ceil });
|
||||||
|
|
||||||
self.allocator.destroy(self);
|
self.allocator.destroy(self);
|
||||||
}
|
}
|
||||||
@@ -141,8 +134,9 @@ pub fn main() !void {
|
|||||||
|
|
||||||
var router: Router = .init(allocator);
|
var router: Router = .init(allocator);
|
||||||
|
|
||||||
var server = try Server.init(allocator, .{
|
var server = try web.Server.init(allocator, .{
|
||||||
.request_router = router.interface(),
|
.request_router = router.interface(),
|
||||||
|
.address = .initIp4(.{ 127, 0, 0, 1 }, 8000),
|
||||||
});
|
});
|
||||||
defer server.deinit(allocator);
|
defer server.deinit(allocator);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user