I have some code that works fine for tests using the std.io.<Reader/Writer>.fixed buffer, but when I try to use sockets it fails. I think I’m just not confident enough in socket programming in Zig, combined with the new IO interface.
const std = @import("std");
const testing = std.testing;
const src = @embedFile("index.html");
const responseBufferSize = src.len + 64;
fn respondToRequest(req: *std.http.Server.Request) !void {
if (req.head.method != .GET) {
try req.respond("", .{ .status = .method_not_allowed, .reason = "Method Not Allowed" });
return;
}
if (!std.ascii.eqlIgnoreCase(req.head.target, "/") and !std.ascii.eqlIgnoreCase(req.head.target, "/index.html")) {
try req.respond("", .{ .status = .not_found, .reason = "Not Found" });
return;
}
try req.respond(src, .{});
}
pub fn main() !void {
const address = try std.net.Address.parseIp4("127.0.0.1", 8080);
var sock = try address.listen(std.net.Address.ListenOptions{ .reuse_address = true });
defer sock.deinit();
std.debug.print("Listening on 127.0.0.1:{d}!\n", .{address.getPort()});
while (true) {
std.debug.print("Waiting for a connection...\n", .{});
var conn = try sock.accept();
defer conn.stream.close();
var input: [1024]u8 = undefined;
var output: [1024]u8 = undefined;
@memset(&input, 0);
@memset(&output, 0);
var writer = conn.stream.writer(&output).interface;
var reader = conn.stream.reader(&input);
var server = std.http.Server.init(reader.interface(), &writer);
var req = try server.receiveHead();
try respondToRequest(&req);
}
}
test "404" {
const input = "GET /this/path/doesnt/exist HTTP/1.0\r\nSomeHeaderKey: SomeHeaderValue\r\n\r\n";
var output: [1024]u8 = undefined;
@memset(&output, 0);
var reader = std.io.Reader.fixed(input);
var writer = std.io.Writer.fixed(&output);
var server = std.http.Server.init(&reader, &writer);
var req = try server.receiveHead();
try respondToRequest(&req);
try testing.expectStringStartsWith(&output, "HTTP/1.1 404 Not Found\r\n");
}
test "405" {
const input = "POST /index.html HTTP/1.0\r\nSomeHeaderKey: SomeHeaderValue\r\n\r\n";
var output: [1024]u8 = undefined;
@memset(&output, 0);
var reader = std.io.Reader.fixed(input);
var writer = std.io.Writer.fixed(&output);
var server = std.http.Server.init(&reader, &writer);
var req = try server.receiveHead();
try respondToRequest(&req);
try testing.expectStringStartsWith(&output, "HTTP/1.1 405 Method Not Allowed\r\n");
}
test "200" {
const input = "GET /index.html HTTP/1.0\r\nSomeHeaderKey: SomeHeaderValue\r\n\r\n";
var output: [1024]u8 = undefined;
@memset(&output, 0);
var reader = std.io.Reader.fixed(input);
var writer = std.io.Writer.fixed(&output);
var server = std.http.Server.init(&reader, &writer);
var req = try server.receiveHead();
try respondToRequest(&req);
try testing.expectStringStartsWith(&output, "HTTP/1.1 200 OK\r\n");
try testing.expect(std.mem.indexOf(u8, &output, src) != null);
}
I tried this code with curl http://localhost:8080/, but get this error:
Listening on 127.0.0.1:8080!
Waiting for a connection...
thread 791807 panic: reached unreachable code
/opt/homebrew/Cellar/zig/0.15.1/lib/zig/std/posix.zig:6176:26: 0x102f65e97 in sendmsg (webServer)
.BADF => unreachable, // always a race condition
^
/opt/homebrew/Cellar/zig/0.15.1/lib/zig/std/net.zig:2297:50: 0x102f5f30f in drain (webServer)
return io_w.consume(posix.sendmsg(w.file_writer.file.handle, &msg, flags) catch |err| {
^
/opt/homebrew/Cellar/zig/0.15.1/lib/zig/std/Io/Writer.zig:316:39: 0x102eda687 in defaultFlush (webServer)
while (w.end != 0) _ = try drainFn(w, &.{""}, 1);
^
/opt/homebrew/Cellar/zig/0.15.1/lib/zig/std/Io/Writer.zig:310:26: 0x102efa02b in flush (webServer)
return w.vtable.flush(w);
^
/opt/homebrew/Cellar/zig/0.15.1/lib/zig/std/http/Server.zig:329:37: 0x102f595fb in respond (webServer)
try request.server.out.flush();
^
/Users/tmp/Projects/webServer/src/main.zig:18:20: 0x102f594b3 in respondToRequest (webServer)
try req.respond(src, .{});
^
/Users/tmp/Projects/webServer/src/main.zig:44:29: 0x102f59ad7 in main (webServer)
try respondToRequest(&req);
^
/opt/homebrew/Cellar/zig/0.15.1/lib/zig/std/start.zig:627:37: 0x102f5abab in main (webServer)
const result = root.main() catch |err| {
^
???:?:?: 0x1809b1d53 in ??? (???)
???:?:?: 0x0 in ??? (???)