web: fix compiler errors

This commit is contained in:
2026-03-12 03:07:05 +01:00
parent fe4a585b6b
commit 712e214f61
8 changed files with 48 additions and 36 deletions

View File

@@ -139,7 +139,7 @@ pub const FileDescriptor = enum(i32) {
} }
pub fn setsockopt(self: FileDescriptor, level: i32, optname: u32, opt: []const u8) !void { pub fn setsockopt(self: FileDescriptor, level: i32, optname: u32, opt: []const u8) !void {
const rc = linux.setsockopt(@intFromEnum(self), level, optname, opt.ptr, opt.len); const rc = linux.setsockopt(@intFromEnum(self), level, optname, opt.ptr, @intCast(opt.len));
return switch (errno(rc)) { return switch (errno(rc)) {
.SUCCESS => {}, .SUCCESS => {},
else => error.SystemError, else => error.SystemError,

View File

@@ -27,7 +27,7 @@ pub fn init(connection: *Connection, header_write_buffer: []u8, body_write_buffe
return .{ return .{
.connection = connection, .connection = connection,
.header_writer = .fixed(header_write_buffer), .header_writer = .fixed(header_write_buffer),
.writer = .fixed(body_write_buffer), .body_writer = .fixed(body_write_buffer),
.state = .init, .state = .init,
}; };
} }

View File

@@ -103,7 +103,7 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Server {
// 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_huge_pages) * huge_page_size;
const all_read_buffers_size = worker_count * single_read_buffer_size; const all_read_buffers_size = worker_count * single_read_buffer_size;
const double_single_read_buffer_size = 2 * single_read_buffer_size; const double_single_read_buffer_size = 2 * single_read_buffer_size;
@@ -165,7 +165,7 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Server {
// Allocate body write buffer // Allocate body write buffer
const single_body_write_buffer_size = @as(usize, options.write_buffer_pages) * huge_page_size; const single_body_write_buffer_size = @as(usize, options.body_write_buffer_huge_pages) * huge_page_size;
const all_body_write_buffers_size = worker_count * single_body_write_buffer_size; const all_body_write_buffers_size = worker_count * single_body_write_buffer_size;
const body_write_buffer_ptr = try errOrPtr(linux.mmap( const body_write_buffer_ptr = try errOrPtr(linux.mmap(

View File

@@ -41,8 +41,8 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Worker {
try header_hash_map.ensureTotalCapacity(allocator, options.max_header_fields); try header_hash_map.ensureTotalCapacity(allocator, options.max_header_fields);
errdefer header_hash_map.deinit(allocator); errdefer header_hash_map.deinit(allocator);
const header_list_buffer = try allocator.alloc(Request.HeaderList, options.max_header_fields); const header_value_buffer = try allocator.alloc(Request.HeaderValue, options.max_header_fields);
errdefer allocator.free(header_list_buffer); errdefer allocator.free(header_value_buffer);
return .{ return .{
.worker_id = options.worker_id, .worker_id = options.worker_id,
@@ -56,7 +56,7 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !Worker {
.body_write_buffer = options.body_write_buffer, .body_write_buffer = options.body_write_buffer,
.header_hash_map = header_hash_map, .header_hash_map = header_hash_map,
.header_value_buffer = header_list_buffer, .header_value_buffer = header_value_buffer,
}; };
} }
@@ -126,7 +126,7 @@ fn handleRequest(
.headers = &self.header_hash_map, .headers = &self.header_hash_map,
.body = undefined, .body = undefined,
}; };
var response: Response = .init(connection, self.write_buffer); var response: Response = .init(connection, self.header_write_buffer, self.body_write_buffer);
var parser: http.Parser = .init(); var parser: http.Parser = .init();
var next_header_index: usize = 0; var next_header_index: usize = 0;
@@ -152,15 +152,9 @@ fn handleRequest(
const res = parser.consume(chunk) catch |err| { const res = parser.consume(chunk) catch |err| {
switch (err) { switch (err) {
error.MethodNotSupported => { error.MethodNotSupported => try closeWith(&response, http.status.method_not_allowed),
try response.sendClose(.{ .status_text = http.status.method_not_allowed }); error.HttpVersionNotSupported => try closeWith(&response, http.status.http_version_not_supported),
}, error.SyntaxError => try closeWith(&response, http.status.bad_request),
error.HttpVersionNotSupported => {
try response.sendClose(.{ .status_text = http.status.http_version_not_supported });
},
error.SyntaxError => {
try response.sendClose(.{ .status_text = http.status.bad_request });
},
} }
return false; return false;
}; };
@@ -169,9 +163,9 @@ fn handleRequest(
if (self.read_tail - self.read_head >= self.read_buffer_size and !done) { if (self.read_tail - self.read_head >= self.read_buffer_size and !done) {
if (parser.state == .body) { if (parser.state == .body) {
try response.sendClose(.{ .status_text = http.status.content_too_large }); try closeWith(&response, http.status.content_too_large);
} else { } else {
try response.sendClose(.{ .status_text = http.status.request_header_fields_too_large }); try closeWith(&response, http.status.request_header_fields_too_large);
} }
return false; return false;
} }
@@ -180,14 +174,19 @@ fn handleRequest(
switch (result) { switch (result) {
.method => |method| request.method = method, .method => |method| request.method = method,
.pathname => |pathname| request.pathname = pathname, .pathname => |pathname| request.pathname = pathname,
.header => |header| { .header => |header| blk: {
if (ignore) { if (ignore) {
break; break :blk;
} }
if (next_header_index >= self.header_value_buffer.len or self.header_hash_map.available == 0) { if (next_header_index >= self.header_value_buffer.len or self.header_hash_map.available == 0) {
try response.send(.{ .status_text = http.status.request_header_fields_too_large }); // TODO Here, we could ignore, but make sure this does
ignore = true; // not clash with the other "request too long" checks
// (i.e. be careful not to double respond).
_ = &ignore;
try closeWith(&response, http.status.request_header_fields_too_large);
return false;
} else { } else {
const entry = self.header_hash_map.getOrPutAssumeCapacity(header.name); const entry = self.header_hash_map.getOrPutAssumeCapacity(header.name);
const header_value = &self.header_value_buffer[next_header_index]; const header_value = &self.header_value_buffer[next_header_index];
@@ -267,3 +266,15 @@ fn handleRequest(
leftover_bytes = bytes_read - res.consumed; leftover_bytes = bytes_read - res.consumed;
} }
} }
fn closeWith(response: *Response, status_line: []const u8) !void {
// This function is meant to be called before a request handler gets to do
// anything.
std.debug.assert(response.header_writer.end == 0);
std.debug.assert(response.body_writer.end == 0);
std.debug.assert(response.state == .init);
try response.header_writer.writeAll(status_line);
try response.header_writer.writeAll("Connection: close\r\n");
try response.header_writer.writeAll("\r\n");
}

View File

@@ -12,7 +12,7 @@ pub const FieldName = extern struct {
const tag_short_bias: u8 = 0x02; const tag_short_bias: u8 = 0x02;
pub fn init(name: []const u8) FieldName { pub fn init(name: []const u8) FieldName {
var data: [16]u8 = @splat(0); var data: [16]u8 align(8) = @splat(0);
if (KnownFieldName.isKnownFieldName(name)) |known| { if (KnownFieldName.isKnownFieldName(name)) |known| {
data[0] = tag_known; data[0] = tag_known;
@as(*KnownFieldName, @ptrCast(data[8..16])).* = known; @as(*KnownFieldName, @ptrCast(data[8..16])).* = known;
@@ -29,7 +29,7 @@ pub const FieldName = extern struct {
} }
pub fn initKnown(known: KnownFieldName) FieldName { pub fn initKnown(known: KnownFieldName) FieldName {
var data: [16]u8 = @splat(0); var data: [16]u8 align(8) = @splat(0);
data[0] = tag_known; data[0] = tag_known;
@as(*KnownFieldName, @ptrCast(data[8..16])).* = known; @as(*KnownFieldName, @ptrCast(data[8..16])).* = known;
@@ -39,7 +39,8 @@ pub const FieldName = extern struct {
fn getKnown(self: FieldName) KnownFieldName { fn getKnown(self: FieldName) KnownFieldName {
std.debug.assert(self.data[0] == tag_known); std.debug.assert(self.data[0] == tag_known);
return @bitCast(self.data[8..16].*); const intval: u64 = @bitCast(self.data[8..16].*);
return @enumFromInt(intval);
} }
fn getLong(self: FieldName) []const u8 { fn getLong(self: FieldName) []const u8 {
@@ -57,7 +58,7 @@ pub const FieldName = extern struct {
return str; return str;
} }
pub fn hash(self: FieldName) u32 { pub fn hash(self: FieldName) u64 {
return switch (self.data[0]) { return switch (self.data[0]) {
tag_known => Wyhash.hash(0, self.data[8..16]), tag_known => Wyhash.hash(0, self.data[8..16]),
tag_long => Wyhash.hash(1, self.getLong()), tag_long => Wyhash.hash(1, self.getLong()),
@@ -79,11 +80,11 @@ pub const FieldName = extern struct {
} }
pub const HashMapContext = struct { pub const HashMapContext = struct {
pub fn hash(_: HashMapContext, key: FieldName) u32 { pub fn hash(_: HashMapContext, key: FieldName) u64 {
return key.hash(); return key.hash();
} }
pub fn eql(_: HashMapContext, a: FieldName, b: FieldName, _: usize) bool { pub fn eql(_: HashMapContext, a: FieldName, b: FieldName) bool {
return FieldName.eql(a, b); return FieldName.eql(a, b);
} }
}; };

View File

@@ -19,5 +19,5 @@ pub fn isNamed(self: Header, name: FieldName) bool {
} }
pub fn isNamedKnown(self: Header, known: KnownFieldName) bool { pub fn isNamedKnown(self: Header, known: KnownFieldName) bool {
return FieldName.eql(self.name, .initKnonw(known)); return FieldName.eql(self.name, .initKnown(known));
} }

View File

@@ -240,11 +240,11 @@ fn consumeChar(self: *Parser, char_ptr: *const u8) Error!?Result {
'O' => self.state = .method_o, 'O' => self.state = .method_o,
'P' => self.state = .method_p, 'P' => self.state = .method_p,
'T' => self.state = .method_t, 'T' => self.state = .method_t,
else => error.MethodNotSupported, else => return error.MethodNotSupported,
}, },
.method_c => switch (char) { .method_c => switch (char) {
'O' => self.state = .method_co, 'O' => self.state = .method_co,
else => error.MethodNotSupported, else => return error.MethodNotSupported,
}, },
.method_d => switch (char) { .method_d => switch (char) {
'E' => self.state = .method_de, 'E' => self.state = .method_de,
@@ -514,7 +514,7 @@ fn consumeChar(self: *Parser, char_ptr: *const u8) Error!?Result {
self.state = .done; self.state = .done;
return .initBody(new_body); return .initBody(new_body);
} else { } else {
self.state = new_body; self.state = .initBody(new_body);
} }
}, },
.done => unreachable, .done => unreachable,

View File

@@ -19,7 +19,7 @@ fn interruptionHandler(signal: i32) callconv(.c) void {
const Handler = struct { const Handler = struct {
fn handle(_: *anyopaque, request: *web.Request, response: *web.Response) !void { fn handle(_: *anyopaque, request: *web.Request, response: *web.Response) !void {
if (!std.mem.eql(request.pathname, "/")) { if (!std.mem.eql(u8, request.pathname, "/")) {
try response.body_writer.writeAll("Not Found\n"); try response.body_writer.writeAll("Not Found\n");
try response.header_writer.writeAll(web.http.status.not_found); try response.header_writer.writeAll(web.http.status.not_found);
@@ -31,7 +31,7 @@ const Handler = struct {
return; return;
} }
if (!std.mem.eql(request.method, "GET")) { if (request.method != .GET) {
try response.body_writer.writeAll("Method Not Allowed\n"); try response.body_writer.writeAll("Method Not Allowed\n");
try response.header_writer.writeAll(web.http.status.method_not_allowed); try response.header_writer.writeAll(web.http.status.method_not_allowed);
@@ -47,7 +47,7 @@ const Handler = struct {
try response.header_writer.writeAll(web.http.status.ok); try response.header_writer.writeAll(web.http.status.ok);
try response.header_writer.writeAll("Content-Type: application/json\r\n"); try response.header_writer.writeAll("Content-Type: application/json\r\n");
try response.header_writer.writeAll("Content-Length: {d}\r\n", .{response.body_writer.end}); try response.header_writer.print("Content-Length: {d}\r\n", .{response.body_writer.end});
try response.header_writer.writeAll("\r\n"); try response.header_writer.writeAll("\r\n");
response.sendHeadersAndBody(); response.sendHeadersAndBody();