diff --git a/build.zig b/build.zig index c45924d..9cbd45c 100644 --- a/build.zig +++ b/build.zig @@ -23,15 +23,10 @@ const api_pkg = std.build.Pkg{ .dependencies = &.{ util_pkg, sql_pkg }, }; -const template_pkg = std.build.Pkg{ - .name = "template", - .source = std.build.FileSource.relative("src/template/lib.zig"), -}; - const main_pkg = std.build.Pkg{ .name = "main", .source = std.build.FileSource.relative("src/main/main.zig"), - .dependencies = &.{ util_pkg, http_pkg, sql_pkg, api_pkg, template_pkg }, + .dependencies = &.{ util_pkg, http_pkg, sql_pkg, api_pkg }, }; pub fn build(b: *std.build.Builder) void { @@ -53,7 +48,6 @@ pub fn build(b: *std.build.Builder) void { exe.addPackage(util_pkg); exe.addPackage(http_pkg); exe.addPackage(api_pkg); - exe.addPackage(template_pkg); exe.linkSystemLibrary("sqlite3"); exe.linkSystemLibrary("pq"); diff --git a/src/http/lib.zig b/src/http/lib.zig index 26f7756..ce97ad1 100644 --- a/src/http/lib.zig +++ b/src/http/lib.zig @@ -10,10 +10,10 @@ pub const socket = @import("./socket.zig"); pub const Method = std.http.Method; pub const Status = std.http.Status; -pub const Request = request.Request(server.Stream.Reader); +pub const Request = request.Request(std.net.Stream.Reader); +pub const serveConn = server.serveConn; pub const Response = server.Response; pub const Handler = server.Handler; -pub const Server = server.Server; pub const Fields = @import("./headers.zig").Fields; diff --git a/src/http/server.zig b/src/http/server.zig index 21a83be..d81d77a 100644 --- a/src/http/server.zig +++ b/src/http/server.zig @@ -4,15 +4,13 @@ const http = @import("./lib.zig"); const response = @import("./server/response.zig"); const request = @import("./request.zig"); -const os = std.os; pub const Response = struct { alloc: std.mem.Allocator, - stream: Stream, + stream: std.net.Stream, should_close: bool = false, - - pub const ResponseStream = response.ResponseStream(Stream.Writer); - pub fn open(self: *Response, status: http.Status, headers: *const http.Fields) !ResponseStream { + pub const Stream = response.ResponseStream(std.net.Stream.Writer); + pub fn open(self: *Response, status: http.Status, headers: *const http.Fields) !Stream { if (headers.get("Connection")) |hdr| { if (std.ascii.indexOfIgnoreCase(hdr, "close")) |_| self.should_close = true; } @@ -20,129 +18,44 @@ pub const Response = struct { return response.open(self.alloc, self.stream.writer(), headers, status); } - pub fn upgrade(self: *Response, status: http.Status, headers: *const http.Fields) !Stream { + pub fn upgrade(self: *Response, status: http.Status, headers: *const http.Fields) !std.net.Stream { try response.writeRequestHeader(self.stream.writer(), headers, status); return self.stream; } }; -pub const StreamKind = enum { - tcp, -}; -pub const Stream = struct { - kind: StreamKind, +const Request = http.Request; +const request_buf_size = 1 << 16; - socket: os.socket_t, +pub fn serveConn(conn: std.net.StreamServer.Connection, ctx: anytype, handler: anytype, alloc: std.mem.Allocator) !void { + // TODO: Timeouts + while (true) { + std.log.debug("waiting for request", .{}); + var arena = std.heap.ArenaAllocator.init(alloc); + defer arena.deinit(); - pub fn close(self: Stream) void { - os.closeSocket(self.socket); - } - - pub const ReadError = os.RecvFromError; - pub const WriteError = os.SendError; - - pub const Reader = std.io.Reader(Stream, ReadError, read); - pub const Writer = std.io.Writer(Stream, WriteError, write); - - pub fn read(self: Stream, buffer: []u8) ReadError!usize { - if (std.io.is_async) @compileError("TODO: async not supported"); - if (self.kind != .tcp) @panic("TODO"); - - return os.recv(self.socket, buffer, 0); - } - - pub fn write(self: Stream, buffer: []const u8) WriteError!usize { - if (std.io.is_async) @compileError("TODO: Async not supported yet"); - if (self.kind != .tcp) @panic("TODO"); - - return os.send(self.socket, buffer, os.MSG.NOSIGNAL); - } - - pub fn reader(self: Stream) Reader { - return .{ .context = self }; - } - - pub fn writer(self: Stream) Writer { - return .{ .context = self }; - } -}; - -pub const Server = struct { - tcp_server: std.net.StreamServer, - - pub fn init() Server { - return Server{ - .tcp_server = std.net.StreamServer.init(.{ .reuse_address = true }), + var req = request.parse(arena.allocator(), conn.stream.reader()) catch |err| { + return handleError(conn.stream.writer(), err) catch {}; }; + std.log.debug("done parsing", .{}); + + var res = Response{ + .alloc = arena.allocator(), + .stream = conn.stream, + }; + + handler(ctx, &req, &res); + std.log.debug("done handling", .{}); + + if (req.headers.get("Connection")) |hdr| { + if (std.ascii.indexOfIgnoreCase(hdr, "close")) |_| return; + } else if (req.headers.get("Keep-Alive")) |hdr| { + std.log.debug("keep-alive: {s}", .{hdr}); + } else if (req.protocol == .http_1_0) return; + + if (res.should_close) return; } - - pub fn deinit(self: *Server) void { - self.tcp_server.deinit(); - } - - pub fn listen(self: *Server, address: std.net.Address) !void { - try self.tcp_server.listen(address); - } - - pub const Connection = struct { - stream: Stream, - address: std.net.Address, - }; - - pub fn handleLoop( - self: *Server, - allocator: std.mem.Allocator, - ctx: anytype, - handler: anytype, - ) void { - while (true) { - const conn = self.tcp_server.accept() catch |err| { - if (err == error.SocketNotListening) return; - - std.log.err("Error occurred accepting connection: {}", .{err}); - continue; - }; - - serveConn( - allocator, - Connection{ - .stream = Stream{ .kind = .tcp, .socket = conn.stream.handle }, - .address = conn.address, - }, - ctx, - handler, - ); - } - } - - fn serveConn( - allocator: std.mem.Allocator, - conn: Connection, - ctx: anytype, - handler: anytype, - ) void { - while (true) { - var req = request.parse(allocator, conn.stream.reader()) catch |err| { - return handleError(conn.stream.writer(), err) catch {}; - }; - - var res = Response{ - .alloc = allocator, - .stream = conn.stream, - }; - - handler(ctx, &req, &res); - - if (req.headers.get("Connection")) |hdr| { - if (std.ascii.indexOfIgnoreCase(hdr, "close")) |_| return; - } else if (req.headers.get("Keep-Alive")) |_| { - // TODO: Support this - return; - } else if (req.protocol == .http_1_0) return; - if (res.should_close) return; - } - } -}; +} /// Writes an error response message and requests closure of the connection fn handleError(writer: anytype, err: anyerror) !void { diff --git a/src/http/socket.zig b/src/http/socket.zig index ab885bb..eab1a1d 100644 --- a/src/http/socket.zig +++ b/src/http/socket.zig @@ -1,7 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const http = @import("./lib.zig"); -const Stream = @import("./server.zig").Stream; +const Stream = std.net.Stream; const Opcode = enum(u4) { continuation = 0x0, diff --git a/src/main/controllers.zig b/src/main/controllers.zig index 3fcfd6a..f162fc0 100644 --- a/src/main/controllers.zig +++ b/src/main/controllers.zig @@ -262,7 +262,7 @@ pub const Response = struct { try stream.finish(); } - pub fn open(self: *Self, status_code: http.Status) !http.Response.ResponseStream { + pub fn open(self: *Self, status_code: http.Status) !http.Response.Stream { std.debug.assert(!self.opened); self.opened = true; diff --git a/src/main/controllers/web/index.tmpl.html b/src/main/controllers/web/index.fmt.html similarity index 77% rename from src/main/controllers/web/index.tmpl.html rename to src/main/controllers/web/index.fmt.html index 1011070..15b263f 100644 --- a/src/main/controllers/web/index.tmpl.html +++ b/src/main/controllers/web/index.fmt.html @@ -2,17 +2,18 @@ - { .community.name } + {[community_name]s}
-

{ .community.name }

+

{[community_name]s}

+ Cluster Admin pseudocommunity

Login