srctree

Gregory Mullen parent 51fcd014 833b40b6
error docs and improved error handling

src/errors.zig added: 43, removed: 19, total 24
@@ -1,3 +1,5 @@
/// Errors that indicate something is wrong with the host system verse is
/// running ontop of.
pub const ServerError = error{
OutOfMemory,
NoSpaceLeft,
@@ -5,6 +7,8 @@ pub const ServerError = error{
Unknown,
};
 
/// Errors resulting from data from the client preventing verse, or an endpoint
/// from returning a valid response.
pub const ClientError = error{
Abusive,
BadData,
@@ -12,11 +16,13 @@ pub const ClientError = error{
InvalidURI,
Unauthenticated,
Unrouteable,
NetworkCrash,
};
 
/// Networking or other IO errors.
pub const NetworkError = error{
NetworkCrash,
/// Common and usually banal error when the client disconnects before the
/// full response is delivered.
BrokenPipe,
};
 
pub const Error = ServerError || ClientError || NetworkError;
 
src/router.zig added: 43, removed: 19, total 24
@@ -230,7 +230,7 @@ pub fn defaultBuilder(vrs: *Verse, build: BuildFn) void {
error.NoSpaceLeft,
error.OutOfMemory,
=> @panic("OOM"),
error.NetworkCrash => log.warn("client disconnect", .{}),
error.BrokenPipe => log.warn("client disconnect", .{}),
error.Unrouteable => {
// Reaching an Unrouteable error here should be impossible as
// the router has decided the target endpoint is correct.
@@ -244,9 +244,9 @@ pub fn defaultBuilder(vrs: *Verse, build: BuildFn) void {
},
error.NotImplemented,
error.Unknown,
=> unreachable, // This is an implementation error by the page. So
// we crash. If you've reached this, something is
// wrong with your site.
=> unreachable,
// This is an implementation error by the page. So we crash. If
// you've reached this, something is wrong with your site.
error.InvalidURI,
=> log.err("Unexpected error '{}'\n", .{err}),
error.Abusive,
 
src/verse.zig added: 43, removed: 19, total 24
@@ -15,6 +15,7 @@ pub const UriIter = Router.UriIter;
pub const Auth = @import("auth.zig");
 
const Error = @import("errors.zig").Error;
const NetworkError = @import("errors.zig").NetworkError;
 
pub const Verse = @This();
 
@@ -47,7 +48,9 @@ pub fn init(a: Allocator, req: *const Request, res: Response, reqdata: RequestDa
};
}
 
pub fn sendPage(vrs: *Verse, page: anytype) Error!void {
/// 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: *Verse, page: anytype) NetworkError!void {
try vrs.quickStart();
const loggedin = if (vrs.auth.valid()) "<a href=\"#\">Logged In</a>" else "Public";
const T = @TypeOf(page.*);
@@ -61,16 +64,25 @@ pub fn sendPage(vrs: *Verse, page: anytype) Error!void {
};
}
 
///
pub fn sendRawSlice(vrs: *Verse, slice: []const u8) Error!void {
vrs.response.send(slice) catch return error.Unknown;
/// 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
pub fn sendRawSlice(vrs: *Verse, slice: []const u8) NetworkError!void {
vrs.response.send(slice) catch |err| switch (err) {
error.BrokenPipe => |e| return e,
else => unreachable,
};
}
 
pub fn sendError(vrs: *Verse, comptime code: std.http.Status) Error!void {
/// Helper function to return a default error page for a given http status code.
pub fn sendError(vrs: *Verse, comptime code: std.http.Status) NetworkError!void {
return Router.defaultResponse(code)(vrs);
}
 
pub fn sendJSON(vrs: *Verse, json: anytype) Error!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: *Verse, json: anytype) NetworkError!void {
try vrs.quickStart();
const data = std.json.stringifyAlloc(vrs.alloc, json, .{
.emit_null_optional_fields = false,
@@ -78,14 +90,20 @@ pub fn sendJSON(vrs: *Verse, json: anytype) Error!void {
log.err("Error trying to print json {}", .{err});
return error.Unknown;
};
vrs.response.writeAll(data) catch unreachable;
vrs.response.finish() catch unreachable;
vrs.response.writeAll(data) catch |err| switch (err) {
error.BrokenPipe => |e| return e,
else => unreachable,
};
vrs.response.finish() catch |err| switch (err) {
error.BrokenPipe => |e| return e,
else => unreachable,
};
}
 
/// This function may be removed in the future
pub fn quickStart(vrs: *Verse) Error!void {
pub fn quickStart(vrs: *Verse) NetworkError!void {
vrs.response.start() catch |err| switch (err) {
error.BrokenPipe => return error.NetworkCrash,
error.BrokenPipe => |e| return e,
else => unreachable,
};
}