build Request and stringify Response working
This commit is contained in:
parent
a459ea9dd3
commit
e4d89fe903
2 changed files with 72 additions and 23 deletions
|
@ -44,8 +44,6 @@ pub const Server = struct {
|
|||
const req_stream = try buffer.toOwnedSlice();
|
||||
const req = try Request.build(req_stream);
|
||||
|
||||
std.debug.print("Request sent by client:\n{s}", .{buffer.items});
|
||||
|
||||
for (rt) |r| {
|
||||
if (eql(u8, r[0], req.uri)) {
|
||||
_ = r[1](req);
|
||||
|
@ -54,7 +52,7 @@ pub const Server = struct {
|
|||
}
|
||||
|
||||
_ = try conn.stream.write("HTTP/1.1 200 OK\r\n");
|
||||
_ = try conn.stream.write("Content-Type: text/html\r\n\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>");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,21 @@ pub const Route = tuple(&.{ []const u8, *const fn (Request) Response });
|
|||
pub const Header = struct {
|
||||
key: []const u8,
|
||||
value: []const u8,
|
||||
|
||||
pub fn stringify(header: Header) []const u8 {
|
||||
var string = std.ArrayList(u8).init(allocator);
|
||||
string.appendSlice(header.key) catch unreachable;
|
||||
string.appendSlice(": ") catch unreachable;
|
||||
string.appendSlice(header.value) catch unreachable;
|
||||
const out = string.toOwnedSlice() catch "";
|
||||
return out;
|
||||
}
|
||||
|
||||
test "stringify Header" {
|
||||
var header = Header{ .key = "User-Agent", .value = "Testbot" };
|
||||
const compare = "User-Agent: Testbot";
|
||||
try std.testing.expect(std.mem.eql(u8, header.stringify(), compare[0..]));
|
||||
}
|
||||
};
|
||||
|
||||
/// The HTTP Version.
|
||||
|
@ -89,47 +104,53 @@ pub const Request = struct {
|
|||
body: []const u8,
|
||||
|
||||
pub fn build(bytes: []const u8) !Request {
|
||||
var lines = std.mem.split(u8, bytes, "\n");
|
||||
var req: Request = undefined;
|
||||
var parts = std.mem.split(u8, bytes, "\r\n");
|
||||
const header = parts.first();
|
||||
var header_lines = std.mem.split(u8, header, "\n");
|
||||
var header_buffer = std.ArrayList(Header).init(allocator);
|
||||
|
||||
var items = std.mem.split(u8, lines.first(), " ");
|
||||
req.method = Method.parse(items.first());
|
||||
req.uri = if (items.next()) |value| value else "";
|
||||
var header_items = std.mem.split(u8, header_lines.first(), " ");
|
||||
req.method = Method.parse(header_items.first());
|
||||
req.uri = if (header_items.next()) |value| value else "";
|
||||
|
||||
if (items.next()) |value| {
|
||||
if (header_items.next()) |value| {
|
||||
req.httpVersion = HTTP_Version.parse(value);
|
||||
} else {
|
||||
req.httpVersion = HTTP_Version.HTTP1_1;
|
||||
}
|
||||
|
||||
while (lines.next()) |line| {
|
||||
while (header_lines.next()) |line| {
|
||||
var headers = std.mem.split(u8, line, ": ");
|
||||
const item1 = headers.first();
|
||||
const item2 = if (headers.next()) |value| value else unreachable;
|
||||
const header = Header{ .key = item1, .value = item2 };
|
||||
try header_buffer.append(header);
|
||||
const header_pair = Header{ .key = item1, .value = item2 };
|
||||
try header_buffer.append(header_pair);
|
||||
}
|
||||
req.headers = header_buffer.toOwnedSlice() catch &[_]Header{Header{ .key = "", .value = "" }};
|
||||
req.body = if (parts.next()) |value| value else "";
|
||||
return req;
|
||||
}
|
||||
};
|
||||
|
||||
test "function to build a Request" {
|
||||
const bytes = "GET /test HTTP/1.1\nHost: localhost:8080\nUser-Agent: Testbot";
|
||||
const req = try Request.build(bytes);
|
||||
try std.testing.expect(req.method == Method.GET);
|
||||
try std.testing.expect(req.httpVersion == HTTP_Version.HTTP1_1);
|
||||
try std.testing.expect(std.mem.eql(u8, req.uri, "/test"));
|
||||
try std.testing.expect(std.mem.eql(u8, req.headers[1].key, "User-Agent"));
|
||||
try std.testing.expect(std.mem.eql(u8, req.headers[1].value, "Testbot"));
|
||||
try std.testing.expect(std.mem.eql(u8, req.headers[0].key, "Host"));
|
||||
try std.testing.expect(std.mem.eql(u8, req.headers[0].value, "localhost:8080"));
|
||||
}
|
||||
// Test the Request build function
|
||||
test "build a Request" {
|
||||
const bytes = "GET /test HTTP/1.1\nHost: localhost:8080\nUser-Agent: Testbot\r\nThis is the test body!";
|
||||
const req = try Request.build(bytes);
|
||||
try std.testing.expect(req.method == Method.GET);
|
||||
try std.testing.expect(req.httpVersion == HTTP_Version.HTTP1_1);
|
||||
try std.testing.expect(std.mem.eql(u8, req.uri, "/test"));
|
||||
try std.testing.expect(std.mem.eql(u8, req.headers[1].key, "User-Agent"));
|
||||
try std.testing.expect(std.mem.eql(u8, req.headers[1].value, "Testbot"));
|
||||
try std.testing.expect(std.mem.eql(u8, req.headers[0].key, "Host"));
|
||||
try std.testing.expect(std.mem.eql(u8, req.headers[0].value, "localhost:8080"));
|
||||
try std.testing.expect(std.mem.eql(u8, req.body, "This is the test body!"));
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a standard http-Response sent by the webapp (server).
|
||||
/// It is the return type of every handling function.
|
||||
pub const Response = struct {
|
||||
httpVersion: HTTP_Version = HTTP_Version.HTTP1_1,
|
||||
/// Response status, default is "200 OK"
|
||||
status: stat.Status = stat.Status.OK,
|
||||
/// Response eaders sent by the server
|
||||
|
@ -156,4 +177,34 @@ 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
|
||||
test {
|
||||
std.testing.refAllDecls(@This());
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue