web: expand example executable
This commit is contained in:
@@ -28,6 +28,19 @@ pub const FileDescriptor = enum(i32) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn open(path: [*:0]const u8, flags: linux.O, perm: linux.mode_t) !FileDescriptor {
|
||||||
|
while (true) {
|
||||||
|
const rc = linux.open(path, flags, perm);
|
||||||
|
switch (errno(rc)) {
|
||||||
|
.SUCCESS => return @enumFromInt(@as(i32, @intCast(rc))),
|
||||||
|
.INTR => continue,
|
||||||
|
.NOENT => return error.FileNotFound,
|
||||||
|
.ACCESS => return error.AccessDenied,
|
||||||
|
else => return error.SystemError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn close(self: FileDescriptor) void {
|
pub fn close(self: FileDescriptor) void {
|
||||||
_ = linux.close(@intFromEnum(self));
|
_ = linux.close(@intFromEnum(self));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,10 @@
|
|||||||
//!
|
//!
|
||||||
//! The parser is not involved in any HTTP semantics, only its syntax. It is up
|
//! The parser is not involved in any HTTP semantics, only its syntax. It is up
|
||||||
//! to the user of this parser to respect all of the HTTP standards (if they
|
//! to the user of this parser to respect all of the HTTP standards (if they
|
||||||
//! even choose to). For example, none of the header field valuess are verified.
|
//! even choose to). For example, none of the header field values are verified,
|
||||||
//! The only exception is `Content-Length`. The parser must know the value to
|
//! except for `Content-Length`. The parser must know the value of
|
||||||
//! determine the length of the request body. If the value fails to parse as a
|
//! `Content-Length` to determine the length of the request body. If the value
|
||||||
//! decimal non-negative integer, a syntax error is returned. Note that
|
//! fails to parse as a decimal non-negative integer, a syntax error is
|
||||||
//! according to [RFC 9110, Section 8.6: HTTP Semantics](https://datatracker.ietf.org/doc/html/rfc9110#section-8.6),
|
//! according to [RFC 9110, Section 8.6: HTTP Semantics](https://datatracker.ietf.org/doc/html/rfc9110#section-8.6),
|
||||||
//! `Content-Length` header field value consisting of the same decimal value
|
//! `Content-Length` header field value consisting of the same decimal value
|
||||||
//! repeated as a comma-separated list (e.g. `Content-Length: 42, 42`) MAY be
|
//! repeated as a comma-separated list (e.g. `Content-Length: 42, 42`) MAY be
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ const web = @import("web");
|
|||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const errno = linux.E.init;
|
const errno = linux.E.init;
|
||||||
const ssl = web.openssl;
|
const ssl = web.openssl;
|
||||||
const UUID = web.UUID;
|
|
||||||
|
|
||||||
var running: std.atomic.Value(bool) = .init(true);
|
var running: std.atomic.Value(bool) = .init(true);
|
||||||
|
|
||||||
|
const body_write_buffer_huge_pages = 1;
|
||||||
|
|
||||||
fn interruptionHandler(sig: linux.SIG) callconv(.c) void {
|
fn interruptionHandler(sig: linux.SIG) callconv(.c) void {
|
||||||
var buf: [32]u8 = undefined;
|
var buf: [32]u8 = undefined;
|
||||||
|
|
||||||
@@ -27,14 +28,7 @@ fn interruptionHandler(sig: linux.SIG) callconv(.c) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Handler = struct {
|
const Handler = struct {
|
||||||
fn handle(_: *anyopaque, request: *web.Request, response: *web.Response) !void {
|
fn notFound(response: *web.Response) !void {
|
||||||
std.log.info("{f} | {s} {s}", .{
|
|
||||||
response.connection.address,
|
|
||||||
@tagName(request.method),
|
|
||||||
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);
|
||||||
@@ -43,10 +37,9 @@ const Handler = struct {
|
|||||||
try response.header_writer.writeAll("\r\n");
|
try response.header_writer.writeAll("\r\n");
|
||||||
|
|
||||||
response.sendHeadersAndBody();
|
response.sendHeadersAndBody();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.method != .GET) {
|
fn methodNotAllowed(response: *web.Response) !void {
|
||||||
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);
|
||||||
@@ -55,6 +48,18 @@ const Handler = struct {
|
|||||||
try response.header_writer.writeAll("\r\n");
|
try response.header_writer.writeAll("\r\n");
|
||||||
|
|
||||||
response.sendHeadersAndBody();
|
response.sendHeadersAndBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle(_: *anyopaque, request: *web.Request, response: *web.Response) !void {
|
||||||
|
std.log.info("{f} | {s} {s}", .{
|
||||||
|
response.connection.address,
|
||||||
|
@tagName(request.method),
|
||||||
|
request.pathname,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, request.pathname, "/")) {
|
||||||
|
if (request.method != .GET) {
|
||||||
|
try methodNotAllowed(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +71,36 @@ const Handler = struct {
|
|||||||
try response.header_writer.writeAll("\r\n");
|
try response.header_writer.writeAll("\r\n");
|
||||||
|
|
||||||
response.sendHeadersAndBody();
|
response.sendHeadersAndBody();
|
||||||
|
} else if (std.mem.startsWith(u8, request.pathname, "/zeroes/")) {
|
||||||
|
const bytes = std.fmt.parseUnsigned(usize, request.pathname[8..], 10) catch {
|
||||||
|
try notFound(response);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (bytes > body_write_buffer_huge_pages * 2 * 1024 * 1024) {
|
||||||
|
try notFound(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.method != .GET) {
|
||||||
|
try methodNotAllowed(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = [_]u8{0};
|
||||||
|
var data = [_][]const u8{&buffer};
|
||||||
|
|
||||||
|
try response.body_writer.writeSplatAll(&data, bytes);
|
||||||
|
|
||||||
|
try response.header_writer.writeAll(web.http.status.ok);
|
||||||
|
try response.header_writer.writeAll("Content-Type: application/octet-stream\r\n");
|
||||||
|
try response.header_writer.print("Content-Length: {d}\r\n", .{response.body_writer.end});
|
||||||
|
try response.header_writer.writeAll("\r\n");
|
||||||
|
|
||||||
|
response.sendHeadersAndBody();
|
||||||
|
} else {
|
||||||
|
try notFound(response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interface() web.RequestHandler {
|
fn interface() web.RequestHandler {
|
||||||
@@ -102,6 +137,7 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
|
|
||||||
var server = try web.Server.init(allocator, init.io, .{
|
var server = try web.Server.init(allocator, init.io, .{
|
||||||
.request_handler = Handler.interface(),
|
.request_handler = Handler.interface(),
|
||||||
|
.body_write_buffer_huge_pages = body_write_buffer_huge_pages,
|
||||||
.ssl_ctx = ssl_ctx,
|
.ssl_ctx = ssl_ctx,
|
||||||
});
|
});
|
||||||
defer server.deinit(allocator);
|
defer server.deinit(allocator);
|
||||||
|
|||||||
Reference in New Issue
Block a user