HttpServer
This commit is contained in:
parent
21a153ba9d
commit
04d83a603c
3 changed files with 80 additions and 33 deletions
|
@ -8,41 +8,44 @@ pub const Connection = struct {
|
||||||
id: Id,
|
id: Id,
|
||||||
address: std.net.Address,
|
address: std.net.Address,
|
||||||
stream: std.net.Stream,
|
stream: std.net.Stream,
|
||||||
|
|
||||||
|
fn new(id: Id, std_conn: std.net.Connection) Connection {
|
||||||
|
std.log.debug("new connection conn_id={}", .{id});
|
||||||
|
return .{
|
||||||
|
.id = id,
|
||||||
|
.address = std_conn.address,
|
||||||
|
.stream = std_conn.stream,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(self: Connection) void {
|
||||||
|
std.log.debug("terminating connection conn_id={}", .{self.id});
|
||||||
|
self.stream.close();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ConnectionServer = struct {
|
pub const ConnectionServer = struct {
|
||||||
pub const Handler = fn (Connection) callconv(.Async) void;
|
|
||||||
|
|
||||||
alloc: std.mem.Allocator,
|
|
||||||
next_conn_id: std.atomic.Atomic(Connection.Id) = std.atomic.Atomic(Connection.Id).init(1),
|
next_conn_id: std.atomic.Atomic(Connection.Id) = std.atomic.Atomic(Connection.Id).init(1),
|
||||||
handler: Handler,
|
stream_server: std.net.StreamServer,
|
||||||
|
|
||||||
pub fn run(self: *ConnectionServer, addr: std.net.Address) noreturn {
|
pub fn listen(addr: std.net.Address) !ConnectionServer {
|
||||||
var srv = std.net.StreamServer.init(.{ .reuse_address = true });
|
var self = ConnectionServer{
|
||||||
defer srv.deinit();
|
.stream_server = std.net.StreamServer.init(.{ .reuse_address = true }),
|
||||||
|
};
|
||||||
|
errdefer self.stream_server.deinit();
|
||||||
|
|
||||||
try srv.listen(addr);
|
try self.stream_server.listen(addr);
|
||||||
|
return self;
|
||||||
while (true) {
|
|
||||||
const conn = try srv.accept();
|
|
||||||
self.handle(conn.stream, conn.address);
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle(self: *ConnectionServer, stream: std.net.Stream, address: std.net.Address) void {
|
pub fn accept(self: *ConnectionServer) !Connection {
|
||||||
const conn = Connection{
|
const conn = try self.stream_server.accept();
|
||||||
.id = self.next_conn_id.fetchAdd(1, .SeqCst),
|
const id = self.next_conn_id.fetchAdd(1, .SeqCst);
|
||||||
.address = address,
|
|
||||||
.stream = stream,
|
|
||||||
};
|
|
||||||
|
|
||||||
defer conn.stream.close();
|
return Connection.new(id, conn);
|
||||||
std.log.debug("new connection conn_id={}", .{conn.id});
|
}
|
||||||
|
|
||||||
async self.handler(conn);
|
pub fn shutdown(self: *ConnectionServer) void {
|
||||||
|
self.stream_server.deinit();
|
||||||
std.log.debug("terminating connection conn_id={}", .{conn.id});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,6 +43,7 @@ fn parseLine(alloc: std.mem.Allocator, request: *Request, reader: anytype) !void
|
||||||
error.StreamTooLong => return error.RequestUriTooLong,
|
error.StreamTooLong => return error.RequestUriTooLong,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
|
errdefer alloc.free(request.path);
|
||||||
|
|
||||||
try checkProto(reader);
|
try checkProto(reader);
|
||||||
|
|
||||||
|
@ -91,7 +92,14 @@ fn checkProto(reader: anytype) !void {
|
||||||
fn parseHeaders(allocator: std.mem.Allocator, reader: anytype) !Headers {
|
fn parseHeaders(allocator: std.mem.Allocator, reader: anytype) !Headers {
|
||||||
var map = Headers.init(allocator);
|
var map = Headers.init(allocator);
|
||||||
errdefer map.deinit();
|
errdefer map.deinit();
|
||||||
// TODO: free map keys/values
|
// todo:
|
||||||
|
//errdefer {
|
||||||
|
//var iter = map.iterator();
|
||||||
|
//while (iter.next()) |it| {
|
||||||
|
//allocator.free(it.key_ptr);
|
||||||
|
//allocator.free(it.value_ptr);
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
var buf: [1024]u8 = undefined;
|
var buf: [1024]u8 = undefined;
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,53 @@ const std = @import("std");
|
||||||
const util = @import("util");
|
const util = @import("util");
|
||||||
const http = @import("./lib.zig");
|
const http = @import("./lib.zig");
|
||||||
|
|
||||||
|
const Request = http.Request;
|
||||||
const Connection = http.Connection;
|
const Connection = http.Connection;
|
||||||
|
|
||||||
const request_buf_size = 1 << 16;
|
const request_buf_size = 1 << 16;
|
||||||
|
|
||||||
fn handleConnection(conn: http.Connection) void {
|
pub const Context = struct {
|
||||||
var request_buf: [request_buf_size]u8 = undefined;
|
alloc: std.mem.Allocator,
|
||||||
var fba = std.heap.FixedBufferAllocator.init(&request_buf);
|
request: Request,
|
||||||
|
connection: Connection,
|
||||||
|
|
||||||
const request = http.Request.parse(fba.allocator(), conn.stream.reader()) catch |err| handleError(conn.stream.writer(), err);
|
const Writer = http.ResponseStream(Connection.Writer);
|
||||||
_ = request;
|
|
||||||
}
|
pub fn openResponse(self: *Context, headers: *const http.Headers, status: http.Status) !Writer {
|
||||||
|
return try http.response_stream.open(self.alloc, self.connection.stream.writer(), headers, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(_: *Context) void {
|
||||||
|
// todo: deallocate request
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const HttpServer = struct {
|
||||||
|
conn_server: http.ConnectionServer,
|
||||||
|
pub fn listen(addr: std.net.Address) !HttpServer {
|
||||||
|
return .{
|
||||||
|
.conn_server = try http.ConnectionServer.listen(addr),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accept(self: *HttpServer, alloc: std.mem.Allocator) !Context {
|
||||||
|
while (true) {
|
||||||
|
const conn = try self.conn_server.accept();
|
||||||
|
errdefer conn.close();
|
||||||
|
|
||||||
|
const req = http.Request.parse(alloc, conn.stream.reader()) catch |err| {
|
||||||
|
_ = handleError(conn.stream.writer(), err);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
return .{ .connection = conn, .request = req, .alloc = alloc };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shutdown(self: *HttpServer) void {
|
||||||
|
self.conn_server.shutdown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
fn handleError(writer: anytype, err: anyerror) !void {
|
fn handleError(writer: anytype, err: anyerror) !void {
|
||||||
const status: http.Status = switch (err) {
|
const status: http.Status = switch (err) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue