srctree

Jeremy Hertel parent ac87aa07 64140e6e
remove quickStart and add sendHTML

examples/auth-cookie.zig added: 79, removed: 74, total 5
@@ -97,8 +97,7 @@ fn index(frame: *Frame) Router.Error!void {
username,
});
 
try frame.quickStart();
try frame.sendRawSlice(page);
try frame.sendHTML(.ok, page);
}
 
/// Sample "login" page. Just visiting `/create` will generate and give a valid
 
examples/basic.zig added: 79, removed: 74, total 5
@@ -28,6 +28,5 @@ fn route(frame: *verse.Frame) !BuildFn {
}
 
fn index(frame: *verse.Frame) Router.Error!void {
try frame.quickStart();
try frame.sendRawSlice("hello world");
try frame.sendHTML(.ok, "hello world");
}
 
examples/cookies.zig added: 79, removed: 74, total 5
@@ -48,6 +48,5 @@ fn index(frame: *verse.Frame) Router.Error!void {
.name = "best-flavor",
.value = random_cookie,
});
try frame.quickStart();
try frame.sendRawSlice(found);
try frame.sendHTML(.ok, found);
}
 
examples/endpoint/index.zig added: 79, removed: 74, total 5
@@ -16,13 +16,11 @@ pub const verse_endpoints = verse.Endpoints(.{
});
 
pub fn index(frame: *Frame) !void {
try frame.quickStart();
try frame.sendRawSlice("hello world");
try frame.sendHTML(.ok, "hello world");
}
 
fn hi(frame: *Frame) !void {
try frame.quickStart();
try frame.sendRawSlice("hi, mom!");
try frame.sendHTML(.ok, "hi, mom!");
}
 
const verse = @import("verse");
 
examples/endpoint/random.zig added: 79, removed: 74, total 5
@@ -9,9 +9,8 @@ pub const verse_routes = [_]Router.Match{
};
 
fn number(frame: *Frame) !void {
try frame.quickStart();
var buffer: [0xff]u8 = undefined;
try frame.sendRawSlice(try std.fmt.bufPrint(&buffer, "{}", .{random.int(usize)}));
try frame.sendHTML(.ok, try std.fmt.bufPrint(&buffer, "{}", .{random.int(usize)}));
}
 
const quotes = enum {
@@ -26,11 +25,9 @@ const quotes = enum {
};
 
fn quote(frame: *Frame) !void {
try frame.quickStart();
var buffer: [0xff]u8 = undefined;
const rand_quote = @tagName(random.enumValue(quotes));
try frame.sendRawSlice("<p>");
try frame.sendRawSlice(rand_quote);
try frame.sendRawSlice("</p>");
try frame.sendHTML(.ok, try std.fmt.bufPrint(&buffer, "<p>{s}</p>", .{rand_quote}));
}
 
const std = @import("std");
 
examples/request-userdata.zig added: 79, removed: 74, total 5
@@ -18,7 +18,6 @@ const Root = struct {
};
 
fn post(frame: *verse.Frame) verse.Router.Error!void {
try frame.quickStart();
var buffer: [0xffffff]u8 = undefined;
var page = try print(&buffer, page_html, .{"page never generated"});
 
@@ -27,7 +26,7 @@ const Root = struct {
// If post_data.validate is unable to translate the received
// user data into the given type, it will return an error.
page = try print(&buffer, page_html, .{"Invalid data submitted!"});
return try frame.sendRawSlice(page);
return try frame.sendHTML(.ok, page);
};
 
// Because neither fields in RequiredData is optional; they
@@ -36,10 +35,10 @@ const Root = struct {
// still required.
if (required_data.username.len == 0) {
page = try print(&buffer, page_html, .{"Username must not be empty!"});
return try frame.sendRawSlice(page);
return try frame.sendHTML(.ok, page);
} else if (required_data.email.len == 0) {
page = try print(&buffer, page_html, .{"email must not be empty!"});
return try frame.sendRawSlice(page);
return try frame.sendHTML(.ok, page);
}
 
// As with all user data, you must be **extremely** careful using
@@ -75,7 +74,7 @@ const Root = struct {
});
}
 
try frame.sendRawSlice(page);
try frame.sendHTML(.ok, page);
}
 
pub fn index(frame: *verse.Frame) !void {
@@ -91,8 +90,7 @@ const Root = struct {
 
const page = try print(&buffer, page_html, .{form});
 
try frame.quickStart();
try frame.sendRawSlice(page);
try frame.sendHTML(.ok, page);
}
 
const page_html =
 
src/frame.zig added: 79, removed: 74, total 5
@@ -45,19 +45,25 @@ cookie_jar: Cookies.Jar,
content_type: ?ContentType = ContentType.default,
status: ?std.http.Status = null,
 
wrote_headers: bool = false,
 
const Frame = @This();
 
pub const SendError = error{
WrongPhase,
HeadersFinished,
ResponseClosed,
UnknownStatus,
} || NetworkError;
 
/// sendPage is the default way to respond in verse using the Template system.
/// sendPage will flush headers to the client before sending Page data
pub fn sendPage(vrs: *Frame, page: anytype) NetworkError!void {
try vrs.quickStart();
vrs.status = .ok;
 
vrs.sendHeaders() catch |err| switch (err) {
error.BrokenPipe, error.IOWriteFailure => |e| return e,
else => {},
};
 
try vrs.sendRawSlice("\r\n");
 
switch (vrs.downstream) {
.http, .zwsgi => |stream| {
@@ -86,8 +92,8 @@ pub fn sendPage(vrs: *Frame, page: anytype) NetworkError!void {
 
/// sendRawSlice will allow you to send data directly to the client. It will not
/// verify the current state, and will allow you to inject data into the HTTP
/// headers. If you only want to send response body data, call quickStart() to
/// send all headers to the client
/// headers. If you only want to send response body data, call sendHeaders() to
/// send all headers to the client.
pub fn sendRawSlice(vrs: *Frame, slice: []const u8) NetworkError!void {
vrs.writeAll(slice) catch |err| switch (err) {
error.BrokenPipe => |e| return e,
@@ -97,7 +103,7 @@ pub fn sendRawSlice(vrs: *Frame, slice: []const u8) NetworkError!void {
 
/// Takes a any object, that can be represented by json, converts it into a
/// json string, and sends to the client.
pub fn sendJSON(vrs: *Frame, json: anytype, comptime code: std.http.Status) !void {
pub fn sendJSON(vrs: *Frame, json: anytype, comptime code: std.http.Status) NetworkError!void {
if (code == .no_content) {
@compileError("Sending JSON is not supported with status code no content");
}
@@ -108,7 +114,13 @@ pub fn sendJSON(vrs: *Frame, json: anytype, comptime code: std.http.Status) !voi
.parameter = .@"utf-8",
};
 
try vrs.quickStart();
vrs.sendHeaders() catch |err| switch (err) {
error.BrokenPipe, error.IOWriteFailure => |e| return e,
else => {},
};
 
try vrs.sendRawSlice("\r\n");
 
const data = std.json.stringifyAlloc(vrs.alloc, json, .{
.emit_null_optional_fields = false,
}) catch |err| {
@@ -121,6 +133,22 @@ pub fn sendJSON(vrs: *Frame, json: anytype, comptime code: std.http.Status) !voi
};
}
 
pub fn sendHTML(frame: *Frame, comptime code: std.http.Status, html: []const u8) NetworkError!void {
frame.status = code;
frame.content_type = .{
.base = .{ .text = .html },
.parameter = .@"utf-8",
};
 
frame.sendHeaders() catch |err| switch (err) {
error.BrokenPipe, error.IOWriteFailure => |e| return e,
else => {},
};
 
try frame.sendRawSlice("\r\n");
try frame.sendRawSlice(html);
}
 
pub fn redirect(vrs: *Frame, loc: []const u8, comptime scode: std.http.Status) NetworkError!void {
vrs.status = switch (scode) {
.multiple_choice,
@@ -134,7 +162,11 @@ pub fn redirect(vrs: *Frame, loc: []const u8, comptime scode: std.http.Status) N
=> scode,
else => @compileError("redirect() can only be called with a 3xx redirection code"),
};
try vrs.sendHeaders();
 
vrs.sendHeaders() catch |err| switch (err) {
error.BrokenPipe, error.IOWriteFailure => |e| return e,
else => {},
};
 
var vect = [3]iovec_c{
.{ .base = "Location: ".ptr, .len = 10 },
@@ -164,7 +196,11 @@ pub fn init(a: Allocator, req: *const Request, auth: Auth.Provider) !Frame {
};
}
 
pub fn sendHeaders(vrs: *Frame) NetworkError!void {
pub fn sendHeaders(vrs: *Frame) SendError!void {
if (vrs.wrote_headers) {
return SendError.HeadersFinished;
}
 
switch (vrs.downstream) {
.http, .zwsgi => |stream| {
var vect: [HEADER_VEC_COUNT]iovec_c = undefined;
@@ -243,6 +279,8 @@ pub fn sendHeaders(vrs: *Frame) NetworkError!void {
},
.buffer => unreachable,
}
 
vrs.wrote_headers = true;
}
 
/// Helper function to return a default error page for a given http status code.
@@ -250,25 +288,6 @@ pub fn sendError(vrs: *Frame, comptime code: std.http.Status) !void {
return Router.defaultResponse(code)(vrs);
}
 
/// This function may be removed in the future
pub fn quickStart(vrs: *Frame) NetworkError!void {
if (vrs.status == null) vrs.status = .ok;
switch (vrs.downstream) {
.http, .zwsgi => |_| {
vrs.sendHeaders() catch |err| switch (err) {
error.BrokenPipe => |e| return e,
else => unreachable,
};
 
vrs.writeAll("\r\n") catch |err| switch (err) {
error.BrokenPipe => |e| return e,
else => unreachable,
};
},
else => unreachable,
}
}
 
pub fn headersAdd(vrs: *Frame, comptime name: []const u8, value: []const u8) !void {
try vrs.headers.add(name, value);
}
 
src/router.zig added: 79, removed: 74, total 5
@@ -212,30 +212,23 @@ pub fn defaultResponse(comptime code: std.http.Status) BuildFn {
}
 
fn notFound(frame: *Frame) Error!void {
frame.status = .not_found;
const E404 = @embedFile("fallback_html/404.html");
try frame.quickStart();
return frame.sendRawSlice(E404);
return frame.sendHTML(.not_found, E404);
}
 
fn internalServerError(vrs: *Frame) Error!void {
vrs.status = .internal_server_error;
const E500 = @embedFile("fallback_html/500.html");
try vrs.quickStart();
return vrs.sendRawSlice(E500);
return vrs.sendHTML(.internal_server_error, E500);
}
 
fn methodNotAllowed(frame: *Frame) Error!void {
frame.status = .method_not_allowed;
const E405 = @embedFile("fallback_html/405.html");
try frame.quickStart();
return frame.sendRawSlice(E405);
return frame.sendHTML(.method_not_allowed, E405);
}
 
fn default(frame: *Frame) Error!void {
const index = @embedFile("fallback_html/index.html");
try frame.quickStart();
return frame.sendRawSlice(index);
return frame.sendHTML(.ok, index);
}
 
pub const RoutingError = error{
 
src/static-file.zig added: 79, removed: 74, total 5
@@ -15,6 +15,9 @@ pub fn fileOnDisk(frame: *Frame) Route.Error!void {
const static = std.fs.cwd().openDir("static", .{}) catch return error.Unrouteable;
const fdata = static.readFileAlloc(frame.alloc, fname, 0xFFFFFF) catch return error.Unknown;
 
try frame.quickStart();
try frame.sendRawSlice(fdata);
frame.sendHeaders() catch |err| switch (err) {
error.BrokenPipe, error.IOWriteFailure => |e| return e,
else => unreachable,
};
try frame.sendHTML(.ok, fdata);
}