First version is working! Now ready for testing ;)
This commit is contained in:
parent
e4d89fe903
commit
9d75b30c9c
3 changed files with 60 additions and 40 deletions
12
src/main.zig
12
src/main.zig
|
@ -1,13 +1,19 @@
|
|||
const std = @import("std");
|
||||
const zrv = @import("zerve.zig");
|
||||
const allocator = std.heap.page_allocator;
|
||||
|
||||
pub fn main() !void {
|
||||
var rt = [_]zrv.Route{.{ "/", index }};
|
||||
var rt = [_]zrv.Route{ .{ "/", index }, .{ "/about/", about } };
|
||||
|
||||
try zrv.Server.listen("0.0.0.0", 8080, &rt);
|
||||
try zrv.Server.listen("0.0.0.0", 8080, &rt, allocator);
|
||||
}
|
||||
|
||||
fn index(req: zrv.Request) zrv.Response {
|
||||
_ = req;
|
||||
return zrv.Response.write("hello!");
|
||||
return zrv.Response.new("hello!");
|
||||
}
|
||||
|
||||
fn about(req: zrv.Request) zrv.Response {
|
||||
_ = req;
|
||||
return zrv.Response.new("about site");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
const std = @import("std");
|
||||
const allocator = std.heap.page_allocator;
|
||||
const eql = std.mem.eql;
|
||||
|
||||
const types = @import("types.zig");
|
||||
|
@ -7,8 +6,11 @@ const Route = types.Route;
|
|||
const Request = types.Request;
|
||||
const Response = types.Response;
|
||||
|
||||
/// Server is a namespace to configure IP and Port the app will listen to, as well as
|
||||
/// the routing paths (`[]Route`) it shall handle.
|
||||
/// You can also choose an allocator that the app will use for dynamic memory allocation.
|
||||
pub const Server = struct {
|
||||
pub fn listen(ip: []const u8, port: u16, rt: []const Route) !void {
|
||||
pub fn listen(ip: []const u8, port: u16, rt: []const Route, allocator: std.mem.Allocator) !void {
|
||||
|
||||
// Init server
|
||||
const server_options: std.net.StreamServer.Options = .{};
|
||||
|
@ -40,20 +42,56 @@ pub const Server = struct {
|
|||
try buffer.appendSlice(chunk_buf[0..]);
|
||||
if (std.mem.containsAtLeast(u8, buffer.items, 2, "\r\n")) break;
|
||||
}
|
||||
// Building the Request
|
||||
// Build the Request
|
||||
const req_stream = try buffer.toOwnedSlice();
|
||||
const req = try Request.build(req_stream);
|
||||
var req = try Request.build(req_stream);
|
||||
|
||||
// if there ist a path set in the uri trim the trailing slash in order to accept it later during the matching check.
|
||||
if (req.uri.len > 1) req.uri = std.mem.trimRight(u8, req.uri, "/");
|
||||
|
||||
// Building the response
|
||||
// First initialize a notfound Response that is being changed if a Route path matches with Request URI.
|
||||
var res = Response.notfound("");
|
||||
|
||||
// Do the matching check. Iterate over the Routes and change the Response being sent in case of matching.
|
||||
for (rt) |r| {
|
||||
if (eql(u8, r[0], req.uri)) {
|
||||
_ = r[1](req);
|
||||
break;
|
||||
var req_path = r[0];
|
||||
// Trim a possible trailing slash from Route path in order to accept it during the matching process.
|
||||
if (req_path.len > 1) req_path = std.mem.trimRight(u8, req_path, "/");
|
||||
if (eql(u8, req_path, req.uri)) {
|
||||
// If URI matches, change response with handling function.
|
||||
res = r[1](req);
|
||||
}
|
||||
}
|
||||
|
||||
_ = try conn.stream.write("HTTP/1.1 200 OK\r\n");
|
||||
_ = try conn.stream.write("Content-Type: text/html\nUser-Agent: Testbot\r\n\r\n");
|
||||
_ = try conn.stream.write("<h1>It works!</h1>");
|
||||
// Stringify the Response and send it to the client.
|
||||
const response_string = try stringify(res, allocator);
|
||||
_ = try conn.stream.writeAll(response_string);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Function that turns Response into a string
|
||||
fn stringify(r: Response, allocator: std.mem.Allocator) ![]const u8 {
|
||||
var res = std.ArrayList(u8).init(allocator);
|
||||
try res.appendSlice(r.httpVersion.stringify());
|
||||
try res.append(' ');
|
||||
try res.appendSlice(r.status.stringify());
|
||||
try res.appendSlice("\r\n");
|
||||
|
||||
for (r.headers) |header| {
|
||||
try res.appendSlice(header.stringify());
|
||||
try res.appendSlice("\n");
|
||||
}
|
||||
try res.appendSlice("\r\n\r\n");
|
||||
try res.appendSlice(r.body);
|
||||
|
||||
return try res.toOwnedSlice();
|
||||
}
|
||||
|
||||
test "stringify Response" {
|
||||
const allocator = std.heap.page_allocator;
|
||||
const headers = [_]types.Header{.{ .key = "User-Agent", .value = "Testbot" }};
|
||||
const res = Response{ .headers = &headers, .body = "This is the body!" };
|
||||
|
||||
try std.testing.expect(eql(u8, try stringify(res, allocator), "HTTP/1.1 200 OK\r\nUser-Agent: Testbot\n\r\n\r\nThis is the body!"));
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ pub const Header = struct {
|
|||
key: []const u8,
|
||||
value: []const u8,
|
||||
|
||||
/// Turns the header key and value into a string.
|
||||
pub fn stringify(header: Header) []const u8 {
|
||||
var string = std.ArrayList(u8).init(allocator);
|
||||
string.appendSlice(header.key) catch unreachable;
|
||||
|
@ -159,7 +160,7 @@ pub const Response = struct {
|
|||
body: []const u8 = "",
|
||||
|
||||
/// Write a simple response.
|
||||
pub fn write(s: []const u8) Response {
|
||||
pub fn new(s: []const u8) Response {
|
||||
return Response{ .body = s };
|
||||
}
|
||||
|
||||
|
@ -177,31 +178,6 @@ pub const Response = struct {
|
|||
pub fn forbidden(s: []u8) Response {
|
||||
return Response{ .status = stat.Status.FORBIDDEN, .body = s };
|
||||
}
|
||||
|
||||
pub fn stringify(r: Response) ![]const u8 {
|
||||
var res = std.ArrayList(u8).init(allocator);
|
||||
try res.appendSlice(r.httpVersion.stringify());
|
||||
try res.append(' ');
|
||||
try res.appendSlice(r.status.stringify());
|
||||
try res.appendSlice("\r\n");
|
||||
|
||||
for (r.headers) |header| {
|
||||
try res.appendSlice(header.stringify());
|
||||
try res.appendSlice("\n");
|
||||
}
|
||||
try res.appendSlice("\r\n\r\n");
|
||||
try res.appendSlice(r.body);
|
||||
|
||||
return try res.toOwnedSlice();
|
||||
}
|
||||
|
||||
test "stringify Response" {
|
||||
const eql = std.mem.eql;
|
||||
const headers = [_]Header{.{ .key = "User-Agent", .value = "Testbot" }};
|
||||
const res = Response{ .headers = &headers, .body = "This is the body!" };
|
||||
|
||||
try std.testing.expect(eql(u8, try res.stringify(), "HTTP/1.1 200 OK\r\nUser-Agent: Testbot\n\r\n\r\nThis is the body!"));
|
||||
}
|
||||
};
|
||||
|
||||
// Run all tests, even the nested ones
|
||||
|
|
Loading…
Reference in a new issue