mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 07:04:08 +00:00
introduced error union to request fn return type
This commit is contained in:
parent
7503f090ee
commit
fcce4517de
32 changed files with 246 additions and 217 deletions
|
@ -5,7 +5,7 @@ var gpa = std.heap.GeneralPurposeAllocator(.{
|
|||
.thread_safe = true,
|
||||
}){};
|
||||
|
||||
fn on_request_verbose(r: zap.Request) void {
|
||||
fn on_request_verbose(r: zap.Request) !void {
|
||||
// use a local buffer for the parsed accept headers
|
||||
var accept_buffer: [1024]u8 = undefined;
|
||||
var fba = std.heap.FixedBufferAllocator.init(&accept_buffer);
|
||||
|
@ -21,38 +21,38 @@ fn on_request_verbose(r: zap.Request) void {
|
|||
break :content_type .HTML;
|
||||
};
|
||||
|
||||
r.setContentType(content_type) catch return;
|
||||
try r.setContentType(content_type);
|
||||
switch (content_type) {
|
||||
.TEXT => {
|
||||
r.sendBody("Hello from ZAP!!!") catch return;
|
||||
try r.sendBody("Hello from ZAP!!!");
|
||||
},
|
||||
.HTML => {
|
||||
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
|
||||
try r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
||||
},
|
||||
.XML => {
|
||||
r.sendBody(
|
||||
try r.sendBody(
|
||||
\\<?xml version="1.0" encoding="UTF-8"?>
|
||||
\\<message>
|
||||
\\ <warning>
|
||||
\\ Hello from ZAP!!!
|
||||
\\ </warning>
|
||||
\\</message>
|
||||
) catch return;
|
||||
);
|
||||
},
|
||||
.JSON => {
|
||||
var buffer: [128]u8 = undefined;
|
||||
const json = zap.util.stringifyBuf(&buffer, .{ .message = "Hello from ZAP!!!" }, .{}) orelse return;
|
||||
r.sendJson(json) catch return;
|
||||
const json = try zap.util.stringifyBuf(&buffer, .{ .message = "Hello from ZAP!!!" }, .{});
|
||||
try r.sendJson(json);
|
||||
},
|
||||
.XHTML => {
|
||||
r.sendBody(
|
||||
try r.sendBody(
|
||||
\\<?xml version="1.0" encoding="UTF-8"?>
|
||||
\\<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
|
||||
\\ <body>
|
||||
\\ <h1>Hello from ZAP!!!</h1>
|
||||
\\ </body>
|
||||
\\</html>
|
||||
) catch return;
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ const zap = @import("zap");
|
|||
const Handler = struct {
|
||||
var alloc: std.mem.Allocator = undefined;
|
||||
|
||||
pub fn on_request(r: zap.Request) void {
|
||||
pub fn on_request(r: zap.Request) !void {
|
||||
// parse for FORM (body) parameters first
|
||||
r.parseBody() catch |err| {
|
||||
std.log.err("Parse Body error: {any}. Expected if body is empty", .{err});
|
||||
|
@ -24,7 +24,7 @@ const Handler = struct {
|
|||
//
|
||||
// HERE WE HANDLE THE BINARY FILE
|
||||
//
|
||||
const params = r.parametersToOwnedList(Handler.alloc, false) catch unreachable;
|
||||
const params = try r.parametersToOwnedList(Handler.alloc, false);
|
||||
defer params.deinit();
|
||||
for (params.items) |kv| {
|
||||
if (kv.value) |v| {
|
||||
|
@ -82,7 +82,7 @@ const Handler = struct {
|
|||
} else |err| {
|
||||
std.log.err("cannot check for terminate param: {any}\n", .{err});
|
||||
}
|
||||
r.sendJson("{ \"ok\": true }") catch unreachable;
|
||||
try r.sendJson("{ \"ok\": true }");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ pub fn main() !void {
|
|||
const Handler = struct {
|
||||
var alloc: std.mem.Allocator = undefined;
|
||||
|
||||
pub fn on_request(r: zap.Request) void {
|
||||
pub fn on_request(r: zap.Request) !void {
|
||||
std.debug.print("\n=====================================================\n", .{});
|
||||
defer std.debug.print("=====================================================\n\n", .{});
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@ const UserWeb = @import("userweb.zig");
|
|||
const StopEndpoint = @import("stopendpoint.zig");
|
||||
|
||||
// this is just to demo that we can catch arbitrary slugs as fallback
|
||||
fn on_request(r: zap.Request) void {
|
||||
fn on_request(r: zap.Request) !void {
|
||||
if (r.path) |the_path| {
|
||||
std.debug.print("REQUESTED PATH: {s}\n", .{the_path});
|
||||
}
|
||||
|
||||
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
|
||||
try r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
|
|
|
@ -6,6 +6,7 @@ const zap = @import("zap");
|
|||
pub const Self = @This();
|
||||
|
||||
path: []const u8,
|
||||
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
|
||||
|
||||
pub fn init(path: []const u8) Self {
|
||||
return .{
|
||||
|
@ -13,14 +14,14 @@ pub fn init(path: []const u8) Self {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn get(e: *Self, r: zap.Request) void {
|
||||
pub fn get(e: *Self, r: zap.Request) anyerror!void {
|
||||
_ = e;
|
||||
_ = r;
|
||||
zap.stop();
|
||||
}
|
||||
|
||||
pub fn post(_: *Self, _: zap.Request) void {}
|
||||
pub fn put(_: *Self, _: zap.Request) void {}
|
||||
pub fn delete(_: *Self, _: zap.Request) void {}
|
||||
pub fn patch(_: *Self, _: zap.Request) void {}
|
||||
pub fn options(_: *Self, _: zap.Request) void {}
|
||||
pub fn post(_: *Self, _: zap.Request) anyerror!void {}
|
||||
pub fn put(_: *Self, _: zap.Request) anyerror!void {}
|
||||
pub fn delete(_: *Self, _: zap.Request) anyerror!void {}
|
||||
pub fn patch(_: *Self, _: zap.Request) anyerror!void {}
|
||||
pub fn options(_: *Self, _: zap.Request) anyerror!void {}
|
||||
|
|
|
@ -11,6 +11,7 @@ alloc: std.mem.Allocator = undefined,
|
|||
_users: Users = undefined,
|
||||
|
||||
path: []const u8,
|
||||
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
|
||||
|
||||
pub fn init(
|
||||
a: std.mem.Allocator,
|
||||
|
@ -42,8 +43,8 @@ fn userIdFromPath(self: *Self, path: []const u8) ?usize {
|
|||
return null;
|
||||
}
|
||||
|
||||
pub fn put(_: *Self, _: zap.Request) void {}
|
||||
pub fn get(self: *Self, r: zap.Request) void {
|
||||
pub fn put(_: *Self, _: zap.Request) anyerror!void {}
|
||||
pub fn get(self: *Self, r: zap.Request) anyerror!void {
|
||||
if (r.path) |path| {
|
||||
// /users
|
||||
if (path.len == self.path.len) {
|
||||
|
@ -52,33 +53,31 @@ pub fn get(self: *Self, r: zap.Request) void {
|
|||
var jsonbuf: [256]u8 = undefined;
|
||||
if (self.userIdFromPath(path)) |id| {
|
||||
if (self._users.get(id)) |user| {
|
||||
if (zap.util.stringifyBuf(&jsonbuf, user, .{})) |json| {
|
||||
r.sendJson(json) catch return;
|
||||
}
|
||||
const json = try zap.util.stringifyBuf(&jsonbuf, user, .{});
|
||||
try r.sendJson(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn listUsers(self: *Self, r: zap.Request) void {
|
||||
fn listUsers(self: *Self, r: zap.Request) !void {
|
||||
if (self._users.toJSON()) |json| {
|
||||
defer self.alloc.free(json);
|
||||
r.sendJson(json) catch return;
|
||||
try r.sendJson(json);
|
||||
} else |err| {
|
||||
std.debug.print("LIST error: {}\n", .{err});
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post(self: *Self, r: zap.Request) void {
|
||||
pub fn post(self: *Self, r: zap.Request) anyerror!void {
|
||||
if (r.body) |body| {
|
||||
const maybe_user: ?std.json.Parsed(User) = std.json.parseFromSlice(User, self.alloc, body, .{}) catch null;
|
||||
if (maybe_user) |u| {
|
||||
defer u.deinit();
|
||||
if (self._users.addByName(u.value.first_name, u.value.last_name)) |id| {
|
||||
var jsonbuf: [128]u8 = undefined;
|
||||
if (zap.util.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| {
|
||||
r.sendJson(json) catch return;
|
||||
}
|
||||
const json = try zap.util.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{});
|
||||
try r.sendJson(json);
|
||||
} else |err| {
|
||||
std.debug.print("ADDING error: {}\n", .{err});
|
||||
return;
|
||||
|
@ -87,7 +86,7 @@ pub fn post(self: *Self, r: zap.Request) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn patch(self: *Self, r: zap.Request) void {
|
||||
pub fn patch(self: *Self, r: zap.Request) anyerror!void {
|
||||
if (r.path) |path| {
|
||||
if (self.userIdFromPath(path)) |id| {
|
||||
if (self._users.get(id)) |_| {
|
||||
|
@ -97,13 +96,11 @@ pub fn patch(self: *Self, r: zap.Request) void {
|
|||
defer u.deinit();
|
||||
var jsonbuf: [128]u8 = undefined;
|
||||
if (self._users.update(id, u.value.first_name, u.value.last_name)) {
|
||||
if (zap.util.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| {
|
||||
r.sendJson(json) catch return;
|
||||
}
|
||||
const json = try zap.util.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{});
|
||||
try r.sendJson(json);
|
||||
} else {
|
||||
if (zap.util.stringifyBuf(&jsonbuf, .{ .status = "ERROR", .id = id }, .{})) |json| {
|
||||
r.sendJson(json) catch return;
|
||||
}
|
||||
const json = try zap.util.stringifyBuf(&jsonbuf, .{ .status = "ERROR", .id = id }, .{});
|
||||
try r.sendJson(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,26 +109,24 @@ pub fn patch(self: *Self, r: zap.Request) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn delete(self: *Self, r: zap.Request) void {
|
||||
pub fn delete(self: *Self, r: zap.Request) anyerror!void {
|
||||
if (r.path) |path| {
|
||||
if (self.userIdFromPath(path)) |id| {
|
||||
var jsonbuf: [128]u8 = undefined;
|
||||
if (self._users.delete(id)) {
|
||||
if (zap.util.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| {
|
||||
r.sendJson(json) catch return;
|
||||
}
|
||||
const json = try zap.util.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{});
|
||||
try r.sendJson(json);
|
||||
} else {
|
||||
if (zap.util.stringifyBuf(&jsonbuf, .{ .status = "ERROR", .id = id }, .{})) |json| {
|
||||
r.sendJson(json) catch return;
|
||||
}
|
||||
const json = try zap.util.stringifyBuf(&jsonbuf, .{ .status = "ERROR", .id = id }, .{});
|
||||
try r.sendJson(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn options(_: *Self, r: zap.Request) void {
|
||||
r.setHeader("Access-Control-Allow-Origin", "*") catch return;
|
||||
r.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS") catch return;
|
||||
pub fn options(_: *Self, r: zap.Request) anyerror!void {
|
||||
try r.setHeader("Access-Control-Allow-Origin", "*");
|
||||
try r.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
||||
r.setStatus(zap.http.StatusCode.no_content);
|
||||
r.markAsFinished(true);
|
||||
}
|
||||
|
|
|
@ -13,24 +13,25 @@ const HTTP_RESPONSE: []const u8 =
|
|||
const Endpoint = struct {
|
||||
// the slug
|
||||
path: []const u8,
|
||||
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
|
||||
|
||||
// authenticated requests go here
|
||||
pub fn get(_: *Endpoint, r: zap.Request) void {
|
||||
pub fn get(_: *Endpoint, r: zap.Request) !void {
|
||||
r.sendBody(HTTP_RESPONSE) catch return;
|
||||
}
|
||||
|
||||
// just for fun, we also catch the unauthorized callback
|
||||
pub fn unauthorized(_: *Endpoint, r: zap.Request) void {
|
||||
pub fn unauthorized(_: *Endpoint, r: zap.Request) !void {
|
||||
r.setStatus(.unauthorized);
|
||||
r.sendBody("UNAUTHORIZED ACCESS") catch return;
|
||||
}
|
||||
|
||||
// not implemented, don't care
|
||||
pub fn post(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn put(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn delete(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn patch(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn options(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn post(_: *Endpoint, _: zap.Request) !void {}
|
||||
pub fn put(_: *Endpoint, _: zap.Request) !void {}
|
||||
pub fn delete(_: *Endpoint, _: zap.Request) !void {}
|
||||
pub fn patch(_: *Endpoint, _: zap.Request) !void {}
|
||||
pub fn options(_: *Endpoint, _: zap.Request) !void {}
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const std = @import("std");
|
||||
const zap = @import("zap");
|
||||
|
||||
fn on_request_verbose(r: zap.Request) void {
|
||||
fn on_request_verbose(r: zap.Request) !void {
|
||||
if (r.path) |the_path| {
|
||||
std.debug.print("PATH: {s}\n", .{the_path});
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ fn on_request_verbose(r: zap.Request) void {
|
|||
if (r.query) |the_query| {
|
||||
std.debug.print("QUERY: {s}\n", .{the_query});
|
||||
}
|
||||
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
|
||||
try r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
||||
}
|
||||
|
||||
fn on_request_minimal(r: zap.Request) void {
|
||||
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
|
||||
fn on_request_minimal(r: zap.Request) !void {
|
||||
try r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const std = @import("std");
|
||||
const zap = @import("zap");
|
||||
|
||||
fn on_request(r: zap.Request) void {
|
||||
fn on_request(r: zap.Request) !void {
|
||||
const m = r.methodAsEnum();
|
||||
const m_str = r.method orelse "";
|
||||
const p = r.path orelse "/";
|
||||
|
@ -20,8 +20,8 @@ fn on_request(r: zap.Request) void {
|
|||
std.debug.print(">> BODY: {s}\n", .{the_body});
|
||||
}
|
||||
|
||||
r.setContentTypeFromPath() catch return;
|
||||
r.sendBody(
|
||||
try r.setContentTypeFromPath();
|
||||
try r.sendBody(
|
||||
\\ <html><body>
|
||||
\\ <h1>Hello from ZAP!!!</h1>
|
||||
\\ <form action="/" method="post">
|
||||
|
@ -32,7 +32,7 @@ fn on_request(r: zap.Request) void {
|
|||
\\ <button>Send</button>
|
||||
\\ </form>
|
||||
\\ </body></html>
|
||||
) catch return;
|
||||
);
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
|
|
|
@ -6,7 +6,7 @@ const User = struct {
|
|||
last_name: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
fn on_request(r: zap.Request) void {
|
||||
fn on_request(r: zap.Request) !void {
|
||||
if (r.methodAsEnum() != .GET) return;
|
||||
|
||||
// /user/n
|
||||
|
@ -14,16 +14,16 @@ fn on_request(r: zap.Request) void {
|
|||
if (the_path.len < 7 or !std.mem.startsWith(u8, the_path, "/user/"))
|
||||
return;
|
||||
|
||||
const user_id: usize = @as(usize, @intCast(the_path[6] - 0x30));
|
||||
const user_id: usize = @intCast(the_path[6] - 0x30);
|
||||
std.debug.print("user_id: {d}\n", .{user_id});
|
||||
std.debug.print("users: {d}\n", .{users.count()});
|
||||
const user = users.get(user_id);
|
||||
std.debug.print("user: {?}\n", .{user});
|
||||
|
||||
var buf: [100]u8 = undefined;
|
||||
var buf: [256]u8 = undefined;
|
||||
var json_to_send: []const u8 = undefined;
|
||||
if (zap.util.stringifyBuf(&buf, user, .{})) |json| {
|
||||
json_to_send = json;
|
||||
} else {
|
||||
json_to_send = "null";
|
||||
}
|
||||
json_to_send = try zap.util.stringifyBuf(&buf, user, .{});
|
||||
|
||||
std.debug.print("<< json: {s}\n", .{json_to_send});
|
||||
r.setContentType(.JSON) catch return;
|
||||
r.setContentTypeFromFilename("test.json") catch return;
|
||||
|
|
|
@ -32,7 +32,7 @@ pub fn main() !void {
|
|||
const Handler = struct {
|
||||
var alloc: std.mem.Allocator = undefined;
|
||||
|
||||
pub fn on_request(r: zap.Request) void {
|
||||
pub fn on_request(r: zap.Request) !void {
|
||||
std.debug.print("\n=====================================================\n", .{});
|
||||
defer std.debug.print("=====================================================\n\n", .{});
|
||||
|
||||
|
@ -69,7 +69,7 @@ pub fn main() !void {
|
|||
// ================================================================
|
||||
|
||||
// iterate over all params as strings
|
||||
var strparams = r.parametersToOwnedStrList(alloc, false) catch unreachable;
|
||||
var strparams = try r.parametersToOwnedStrList(alloc, false);
|
||||
defer strparams.deinit();
|
||||
std.debug.print("\n", .{});
|
||||
for (strparams.items) |kv| {
|
||||
|
@ -79,7 +79,7 @@ pub fn main() !void {
|
|||
std.debug.print("\n", .{});
|
||||
|
||||
// iterate over all params
|
||||
const params = r.parametersToOwnedList(alloc, false) catch unreachable;
|
||||
const params = try r.parametersToOwnedList(alloc, false);
|
||||
defer params.deinit();
|
||||
for (params.items) |kv| {
|
||||
std.log.info("Param `{s}` is {any}", .{ kv.key.str, kv.value });
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const std = @import("std");
|
||||
const zap = @import("zap");
|
||||
|
||||
fn on_request_verbose(r: zap.Request) void {
|
||||
fn on_request_verbose(r: zap.Request) !void {
|
||||
if (r.path) |the_path| {
|
||||
std.debug.print("PATH: {s}\n", .{the_path});
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ fn on_request_verbose(r: zap.Request) void {
|
|||
if (r.query) |the_query| {
|
||||
std.debug.print("QUERY: {s}\n", .{the_query});
|
||||
}
|
||||
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
|
||||
try r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
||||
}
|
||||
|
||||
fn on_request_minimal(r: zap.Request) void {
|
||||
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
|
||||
fn on_request_minimal(r: zap.Request) !void {
|
||||
try r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
||||
}
|
||||
|
||||
fn help_and_exit(filename: []const u8, err: anyerror) void {
|
||||
|
|
|
@ -69,7 +69,7 @@ const UserMiddleWare = struct {
|
|||
}
|
||||
|
||||
// note that the first parameter is of type *Handler, not *Self !!!
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||
|
||||
// this is how we would get our self pointer
|
||||
const self: *Self = @fieldParentPtr("handler", handler);
|
||||
|
@ -113,7 +113,7 @@ const SessionMiddleWare = struct {
|
|||
}
|
||||
|
||||
// note that the first parameter is of type *Handler, not *Self !!!
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||
// this is how we would get our self pointer
|
||||
const self: *Self = @fieldParentPtr("handler", handler);
|
||||
_ = self;
|
||||
|
@ -148,7 +148,7 @@ const HtmlMiddleWare = struct {
|
|||
}
|
||||
|
||||
// note that the first parameter is of type *Handler, not *Self !!!
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||
|
||||
// this is how we would get our self pointer
|
||||
const self: *Self = @fieldParentPtr("handler", handler);
|
||||
|
|
|
@ -57,7 +57,7 @@ const UserMiddleWare = struct {
|
|||
}
|
||||
|
||||
// note that the first parameter is of type *Handler, not *Self !!!
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||
|
||||
// this is how we would get our self pointer
|
||||
const self: *Self = @fieldParentPtr("handler", handler);
|
||||
|
@ -103,7 +103,7 @@ const SessionMiddleWare = struct {
|
|||
}
|
||||
|
||||
// note that the first parameter is of type *Handler, not *Self !!!
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||
// this is how we would get our self pointer
|
||||
const self: *Self = @fieldParentPtr("handler", handler);
|
||||
_ = self;
|
||||
|
@ -146,13 +146,13 @@ const HtmlEndpoint = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn post(_: *HtmlEndpoint, _: zap.Request) void {}
|
||||
pub fn put(_: *HtmlEndpoint, _: zap.Request) void {}
|
||||
pub fn delete(_: *HtmlEndpoint, _: zap.Request) void {}
|
||||
pub fn patch(_: *HtmlEndpoint, _: zap.Request) void {}
|
||||
pub fn options(_: *HtmlEndpoint, _: zap.Request) void {}
|
||||
pub fn post(_: *HtmlEndpoint, _: zap.Request) !void {}
|
||||
pub fn put(_: *HtmlEndpoint, _: zap.Request) !void {}
|
||||
pub fn delete(_: *HtmlEndpoint, _: zap.Request) !void {}
|
||||
pub fn patch(_: *HtmlEndpoint, _: zap.Request) !void {}
|
||||
pub fn options(_: *HtmlEndpoint, _: zap.Request) !void {}
|
||||
|
||||
pub fn get(_: *Self, r: zap.Request) void {
|
||||
pub fn get(_: *Self, r: zap.Request) !void {
|
||||
var buf: [1024]u8 = undefined;
|
||||
var userFound: bool = false;
|
||||
var sessionFound: bool = false;
|
||||
|
@ -169,12 +169,12 @@ const HtmlEndpoint = struct {
|
|||
sessionFound = true;
|
||||
|
||||
std.debug.assert(r.isFinished() == false);
|
||||
const message = std.fmt.bufPrint(&buf, "User: {s} / {s}, Session: {s} / {s}", .{
|
||||
const message = try std.fmt.bufPrint(&buf, "User: {s} / {s}, Session: {s} / {s}", .{
|
||||
user.name,
|
||||
user.email,
|
||||
session.info,
|
||||
session.token,
|
||||
}) catch unreachable;
|
||||
});
|
||||
r.setContentType(.TEXT) catch unreachable;
|
||||
r.sendBody(message) catch unreachable;
|
||||
std.debug.assert(r.isFinished() == true);
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
const zap = @import("zap");
|
||||
const Mustache = @import("zap").Mustache;
|
||||
|
||||
fn on_request(r: zap.Request) void {
|
||||
fn on_request(r: zap.Request) !void {
|
||||
const template =
|
||||
\\ {{=<< >>=}}
|
||||
\\ * Users:
|
||||
|
|
|
@ -3,39 +3,39 @@ const zap = @import("zap");
|
|||
|
||||
// NOTE: this is a super simplified example, just using a hashmap to map
|
||||
// from HTTP path to request function.
|
||||
fn dispatch_routes(r: zap.Request) void {
|
||||
fn dispatch_routes(r: zap.Request) !void {
|
||||
// dispatch
|
||||
if (r.path) |the_path| {
|
||||
if (routes.get(the_path)) |foo| {
|
||||
foo(r);
|
||||
try foo(r);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// or default: present menu
|
||||
r.sendBody(
|
||||
try r.sendBody(
|
||||
\\ <html>
|
||||
\\ <body>
|
||||
\\ <p><a href="/static">static</a></p>
|
||||
\\ <p><a href="/dynamic">dynamic</a></p>
|
||||
\\ </body>
|
||||
\\ </html>
|
||||
) catch return;
|
||||
);
|
||||
}
|
||||
|
||||
fn static_site(r: zap.Request) void {
|
||||
r.sendBody("<html><body><h1>Hello from STATIC ZAP!</h1></body></html>") catch return;
|
||||
fn static_site(r: zap.Request) !void {
|
||||
try r.sendBody("<html><body><h1>Hello from STATIC ZAP!</h1></body></html>");
|
||||
}
|
||||
|
||||
var dynamic_counter: i32 = 0;
|
||||
fn dynamic_site(r: zap.Request) void {
|
||||
fn dynamic_site(r: zap.Request) !void {
|
||||
dynamic_counter += 1;
|
||||
var buf: [128]u8 = undefined;
|
||||
const filled_buf = std.fmt.bufPrintZ(
|
||||
const filled_buf = try std.fmt.bufPrintZ(
|
||||
&buf,
|
||||
"<html><body><h1>Hello # {d} from DYNAMIC ZAP!!!</h1></body></html>",
|
||||
.{dynamic_counter},
|
||||
) catch "ERROR";
|
||||
r.sendBody(filled_buf) catch return;
|
||||
);
|
||||
try r.sendBody(filled_buf);
|
||||
}
|
||||
|
||||
fn setup_routes(a: std.mem.Allocator) !void {
|
||||
|
|
|
@ -5,7 +5,7 @@ fn MAKE_MEGA_ERROR() !void {
|
|||
return error.MEGA_ERROR;
|
||||
}
|
||||
|
||||
fn MY_REQUEST_HANDLER(r: zap.Request) void {
|
||||
fn MY_REQUEST_HANDLER(r: zap.Request) !void {
|
||||
MAKE_MEGA_ERROR() catch |err| {
|
||||
r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505);
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ var read_len: ?usize = null;
|
|||
|
||||
const testfile = @embedFile("testfile.txt");
|
||||
|
||||
pub fn on_request(r: zap.Request) void {
|
||||
pub fn on_request(r: zap.Request) !void {
|
||||
// Sends a file if present in the filesystem orelse returns an error.
|
||||
//
|
||||
// - efficiently sends a file using gzip compression
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const std = @import("std");
|
||||
const zap = @import("zap");
|
||||
|
||||
fn on_request(r: zap.Request) void {
|
||||
fn on_request(r: zap.Request) !void {
|
||||
r.setStatus(.not_found);
|
||||
r.sendBody("<html><body><h1>404 - File not found</h1></body></html>") catch return;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
const zap = @import("zap");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
fn on_request_verbose(r: zap.Request) void {
|
||||
fn on_request_verbose(r: zap.Request) !void {
|
||||
if (r.path) |the_path| {
|
||||
std.debug.print("PATH: {s}\n", .{the_path});
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub const SomePackage = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn getA(self: *Self, req: zap.Request) void {
|
||||
pub fn getA(self: *Self, req: zap.Request) !void {
|
||||
std.log.warn("get_a_requested", .{});
|
||||
|
||||
const string = std.fmt.allocPrint(
|
||||
|
@ -41,7 +41,7 @@ pub const SomePackage = struct {
|
|||
req.sendBody(string) catch return;
|
||||
}
|
||||
|
||||
pub fn getB(self: *Self, req: zap.Request) void {
|
||||
pub fn getB(self: *Self, req: zap.Request) !void {
|
||||
std.log.warn("get_b_requested", .{});
|
||||
|
||||
const string = std.fmt.allocPrint(
|
||||
|
@ -54,7 +54,7 @@ pub const SomePackage = struct {
|
|||
req.sendBody(string) catch return;
|
||||
}
|
||||
|
||||
pub fn incrementA(self: *Self, req: zap.Request) void {
|
||||
pub fn incrementA(self: *Self, req: zap.Request) !void {
|
||||
std.log.warn("increment_a_requested", .{});
|
||||
|
||||
self.a += 1;
|
||||
|
@ -63,10 +63,10 @@ pub const SomePackage = struct {
|
|||
}
|
||||
};
|
||||
|
||||
fn not_found(req: zap.Request) void {
|
||||
fn not_found(req: zap.Request) !void {
|
||||
std.debug.print("not found handler", .{});
|
||||
|
||||
req.sendBody("Not found") catch return;
|
||||
try req.sendBody("Not found");
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
|
|
|
@ -25,38 +25,38 @@ const img = @embedFile("./html/Ziggy_the_Ziguana.svg.png");
|
|||
var authenticator: Authenticator = undefined;
|
||||
|
||||
// the login page (embedded)
|
||||
fn on_login(r: zap.Request) void {
|
||||
r.sendBody(loginpage) catch return;
|
||||
fn on_login(r: zap.Request) !void {
|
||||
try r.sendBody(loginpage);
|
||||
}
|
||||
|
||||
// the "normal page"
|
||||
fn on_normal_page(r: zap.Request) void {
|
||||
fn on_normal_page(r: zap.Request) !void {
|
||||
zap.debug("on_normal_page()\n", .{});
|
||||
r.sendBody(
|
||||
try r.sendBody(
|
||||
\\ <html><body>
|
||||
\\ <h1>Hello from ZAP!!!</h1>
|
||||
\\ <p>You are logged in!!!</>
|
||||
\\ <center><a href="/logout">logout</a></center>
|
||||
\\ </body></html>
|
||||
) catch return;
|
||||
);
|
||||
}
|
||||
|
||||
// the logged-out page
|
||||
fn on_logout(r: zap.Request) void {
|
||||
fn on_logout(r: zap.Request) !void {
|
||||
zap.debug("on_logout()\n", .{});
|
||||
authenticator.logout(&r);
|
||||
// note, the link below doesn't matter as the authenticator will send us
|
||||
// straight to the /login page
|
||||
r.sendBody(
|
||||
try r.sendBody(
|
||||
\\ <html><body>
|
||||
\\ <p>You are logged out!!!</p>
|
||||
\\ <br>
|
||||
\\ <p> <a href="/">Log back in</a></p>
|
||||
\\ </body></html>
|
||||
) catch return;
|
||||
);
|
||||
}
|
||||
|
||||
fn on_request(r: zap.Request) void {
|
||||
fn on_request(r: zap.Request) !void {
|
||||
switch (authenticator.authenticateRequest(&r)) {
|
||||
.Handled => {
|
||||
// the authenticator handled the entire request for us.
|
||||
|
@ -80,8 +80,8 @@ fn on_request(r: zap.Request) void {
|
|||
// the authenticator. Hence, we name the img for the /login
|
||||
// page: /login/Ziggy....png
|
||||
if (std.mem.startsWith(u8, p, "/login/Ziggy_the_Ziguana.svg.png")) {
|
||||
r.setContentTypeFromPath() catch unreachable;
|
||||
r.sendBody(img) catch unreachable;
|
||||
try r.setContentTypeFromPath();
|
||||
try r.sendBody(img);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -163,13 +163,13 @@ fn handle_websocket_message(
|
|||
//
|
||||
// HTTP stuff
|
||||
//
|
||||
fn on_request(r: zap.Request) void {
|
||||
fn on_request(r: zap.Request) !void {
|
||||
r.setHeader("Server", "zap.example") catch unreachable;
|
||||
r.sendBody(
|
||||
try r.sendBody(
|
||||
\\ <html><body>
|
||||
\\ <h1>This is a simple Websocket chatroom example</h1>
|
||||
\\ </body></html>
|
||||
) catch return;
|
||||
);
|
||||
}
|
||||
|
||||
fn on_upgrade(r: zap.Request, target_protocol: []const u8) void {
|
||||
|
|
128
src/endpoint.zig
128
src/endpoint.zig
|
@ -55,6 +55,16 @@ const std = @import("std");
|
|||
const zap = @import("zap.zig");
|
||||
const auth = @import("http_auth.zig");
|
||||
|
||||
/// Endpoint request error handling strategy
|
||||
pub const ErrorStrategy = enum {
|
||||
/// log errors to console
|
||||
log_to_console,
|
||||
/// log errors to console AND generate a HTML response
|
||||
log_to_response,
|
||||
/// raise errors -> TODO: clarify: where can they be caught? in App.run()
|
||||
raise,
|
||||
};
|
||||
|
||||
// zap types
|
||||
const Request = zap.Request;
|
||||
const ListenerSettings = zap.HttpListenerSettings;
|
||||
|
@ -69,6 +79,14 @@ pub fn checkEndpointType(T: type) void {
|
|||
@compileError(@typeName(T) ++ " has no path field");
|
||||
}
|
||||
|
||||
if (@hasField(T, "error_strategy")) {
|
||||
if (@FieldType(T, "error_strategy") != ErrorStrategy) {
|
||||
@compileError(@typeName(@FieldType(T, "error_strategy")) ++ " has wrong type, expected: zap.Endpoint.ErrorStrategy");
|
||||
}
|
||||
} else {
|
||||
@compileError(@typeName(T) ++ " has no error_strategy field");
|
||||
}
|
||||
|
||||
const methods_to_check = [_][]const u8{
|
||||
"get",
|
||||
"post",
|
||||
|
@ -79,8 +97,8 @@ pub fn checkEndpointType(T: type) void {
|
|||
};
|
||||
inline for (methods_to_check) |method| {
|
||||
if (@hasDecl(T, method)) {
|
||||
if (@TypeOf(@field(T, method)) != fn (_: *T, _: Request) void) {
|
||||
@compileError(method ++ " method of " ++ @typeName(T) ++ " has wrong type:\n" ++ @typeName(@TypeOf(T.get)) ++ "\nexpected:\n" ++ @typeName(fn (_: *T, _: Request) void));
|
||||
if (@TypeOf(@field(T, method)) != fn (_: *T, _: Request) anyerror!void) {
|
||||
@compileError(method ++ " method of " ++ @typeName(T) ++ " has wrong type:\n" ++ @typeName(@TypeOf(T.get)) ++ "\nexpected:\n" ++ @typeName(fn (_: *T, _: Request) anyerror!void));
|
||||
}
|
||||
} else {
|
||||
@compileError(@typeName(T) ++ " has no method named `" ++ method ++ "`");
|
||||
|
@ -88,58 +106,65 @@ pub fn checkEndpointType(T: type) void {
|
|||
}
|
||||
}
|
||||
|
||||
const EndpointWrapper = struct {
|
||||
pub const Wrapper = struct {
|
||||
call: *const fn (*Wrapper, zap.Request) void = undefined,
|
||||
pub const Wrapper = struct {
|
||||
pub const Internal = struct {
|
||||
call: *const fn (*Internal, zap.Request) anyerror!void = undefined,
|
||||
path: []const u8,
|
||||
destroy: *const fn (allocator: std.mem.Allocator, *Wrapper) void = undefined,
|
||||
destroy: *const fn (allocator: std.mem.Allocator, *Internal) void = undefined,
|
||||
};
|
||||
pub fn Wrap(T: type) type {
|
||||
return struct {
|
||||
wrapped: *T,
|
||||
wrapper: Wrapper,
|
||||
wrapper: Internal,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn unwrap(wrapper: *Wrapper) *Self {
|
||||
pub fn unwrap(wrapper: *Internal) *Self {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroy(allocator: std.mem.Allocator, wrapper: *Wrapper) void {
|
||||
pub fn destroy(allocator: std.mem.Allocator, wrapper: *Internal) void {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
pub fn onRequestWrapped(wrapper: *Wrapper, r: zap.Request) void {
|
||||
pub fn onRequestWrapped(wrapper: *Internal, r: zap.Request) !void {
|
||||
var self: *Self = Self.unwrap(wrapper);
|
||||
self.onRequest(r);
|
||||
try self.onRequest(r);
|
||||
}
|
||||
|
||||
pub fn onRequest(self: *Self, r: zap.Request) void {
|
||||
switch (r.methodAsEnum()) {
|
||||
.GET => return self.wrapped.*.get(r),
|
||||
.POST => return self.wrapped.*.post(r),
|
||||
.PUT => return self.wrapped.*.put(r),
|
||||
.DELETE => return self.wrapped.*.delete(r),
|
||||
.PATCH => return self.wrapped.*.patch(r),
|
||||
.OPTIONS => return self.wrapped.*.options(r),
|
||||
else => {
|
||||
// TODO: log that method is ignored
|
||||
},
|
||||
pub fn onRequest(self: *Self, r: zap.Request) !void {
|
||||
const ret = switch (r.methodAsEnum()) {
|
||||
.GET => self.wrapped.*.get(r),
|
||||
.POST => self.wrapped.*.post(r),
|
||||
.PUT => self.wrapped.*.put(r),
|
||||
.DELETE => self.wrapped.*.delete(r),
|
||||
.PATCH => self.wrapped.*.patch(r),
|
||||
.OPTIONS => self.wrapped.*.options(r),
|
||||
else => error.UnsupportedHtmlRequestMethod,
|
||||
};
|
||||
if (ret) {
|
||||
// handled without error
|
||||
} else |err| {
|
||||
switch (self.wrapped.*.error_strategy) {
|
||||
.raise => return err,
|
||||
.log_to_response => return r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505),
|
||||
.log_to_console => zap.debug("Error in {} {s} : {}", .{ Self, r.method orelse "(no method)", err }),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(T: type, value: *T) EndpointWrapper.Wrap(T) {
|
||||
pub fn init(T: type, value: *T) Wrapper.Wrap(T) {
|
||||
checkEndpointType(T);
|
||||
var ret: EndpointWrapper.Wrap(T) = .{
|
||||
var ret: Wrapper.Wrap(T) = .{
|
||||
.wrapped = value,
|
||||
.wrapper = .{ .path = value.path },
|
||||
};
|
||||
ret.wrapper.call = EndpointWrapper.Wrap(T).onRequestWrapped;
|
||||
ret.wrapper.destroy = EndpointWrapper.Wrap(T).destroy;
|
||||
ret.wrapper.call = Wrapper.Wrap(T).onRequestWrapped;
|
||||
ret.wrapper.destroy = Wrapper.Wrap(T).destroy;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
@ -150,6 +175,7 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
|||
authenticator: *Authenticator,
|
||||
ep: *EndpointType,
|
||||
path: []const u8,
|
||||
error_strategy: ErrorStrategy,
|
||||
const Self = @This();
|
||||
|
||||
/// Init the authenticating endpoint. Pass in a pointer to the endpoint
|
||||
|
@ -160,61 +186,62 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
|||
.authenticator = authenticator,
|
||||
.ep = e,
|
||||
.path = e.path,
|
||||
.error_strategy = e.error_strategy,
|
||||
};
|
||||
}
|
||||
|
||||
/// Authenticates GET requests using the Authenticator.
|
||||
pub fn get(self: *Self, r: zap.Request) void {
|
||||
switch (self.authenticator.authenticateRequest(&r)) {
|
||||
pub fn get(self: *Self, r: zap.Request) anyerror!void {
|
||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||
.AuthOK => self.ep.*.get(r),
|
||||
.Handled => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Authenticates POST requests using the Authenticator.
|
||||
pub fn post(self: *Self, r: zap.Request) void {
|
||||
switch (self.authenticator.authenticateRequest(&r)) {
|
||||
pub fn post(self: *Self, r: zap.Request) anyerror!void {
|
||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||
.AuthOK => self.ep.*.post(r),
|
||||
.Handled => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Authenticates PUT requests using the Authenticator.
|
||||
pub fn put(self: *Self, r: zap.Request) void {
|
||||
switch (self.authenticator.authenticateRequest(&r)) {
|
||||
pub fn put(self: *Self, r: zap.Request) anyerror!void {
|
||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||
.AuthOK => self.ep.*.put(r),
|
||||
.Handled => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Authenticates DELETE requests using the Authenticator.
|
||||
pub fn delete(self: *Self, r: zap.Request) void {
|
||||
switch (self.authenticator.authenticateRequest(&r)) {
|
||||
pub fn delete(self: *Self, r: zap.Request) anyerror!void {
|
||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||
.AuthOK => self.ep.*.delete(r),
|
||||
.Handled => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Authenticates PATCH requests using the Authenticator.
|
||||
pub fn patch(self: *Self, r: zap.Request) void {
|
||||
switch (self.authenticator.authenticateRequest(&r)) {
|
||||
pub fn patch(self: *Self, r: zap.Request) anyerror!void {
|
||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||
.AuthOK => self.ep.*.patch(r),
|
||||
.Handled => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Authenticates OPTIONS requests using the Authenticator.
|
||||
pub fn options(self: *Self, r: zap.Request) void {
|
||||
switch (self.authenticator.authenticateRequest(&r)) {
|
||||
pub fn options(self: *Self, r: zap.Request) anyerror!void {
|
||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||
.AuthOK => self.ep.*.put(r),
|
||||
.Handled => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -237,7 +264,7 @@ pub const Listener = struct {
|
|||
const Self = @This();
|
||||
|
||||
/// Internal static struct of member endpoints
|
||||
var endpoints: std.ArrayListUnmanaged(*EndpointWrapper.Wrapper) = .empty;
|
||||
var endpoints: std.ArrayListUnmanaged(*Wrapper.Internal) = .empty;
|
||||
|
||||
/// Internal, static request handler callback. Will be set to the optional,
|
||||
/// user-defined request callback that only gets called if no endpoints match
|
||||
|
@ -303,23 +330,22 @@ pub const Listener = struct {
|
|||
}
|
||||
const EndpointType = @typeInfo(@TypeOf(e)).pointer.child;
|
||||
checkEndpointType(EndpointType);
|
||||
const wrapper = try self.allocator.create(EndpointWrapper.Wrap(EndpointType));
|
||||
wrapper.* = EndpointWrapper.init(EndpointType, e);
|
||||
const wrapper = try self.allocator.create(Wrapper.Wrap(EndpointType));
|
||||
wrapper.* = Wrapper.init(EndpointType, e);
|
||||
try endpoints.append(self.allocator, &wrapper.wrapper);
|
||||
}
|
||||
|
||||
fn onRequest(r: Request) void {
|
||||
fn onRequest(r: Request) !void {
|
||||
if (r.path) |p| {
|
||||
for (endpoints.items) |wrapper| {
|
||||
if (std.mem.startsWith(u8, p, wrapper.path)) {
|
||||
wrapper.call(wrapper, r);
|
||||
return;
|
||||
return try wrapper.call(wrapper, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if set, call the user-provided default callback
|
||||
if (on_request) |foo| {
|
||||
foo(r);
|
||||
try foo(r);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ pub fn Handler(comptime ContextType: anytype) type {
|
|||
// will be set
|
||||
allocator: ?std.mem.Allocator = null,
|
||||
|
||||
pub const RequestFn = *const fn (*Self, zap.Request, *ContextType) bool;
|
||||
pub const RequestFn = *const fn (*Self, zap.Request, *ContextType) anyerror!bool;
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(on_request: RequestFn, other: ?*Self) Self {
|
||||
|
@ -30,7 +30,7 @@ pub fn Handler(comptime ContextType: anytype) type {
|
|||
// example for handling a request request
|
||||
// which you can use in your components, e.g.:
|
||||
// return self.handler.handleOther(r, context);
|
||||
pub fn handleOther(self: *Self, r: zap.Request, context: *ContextType) bool {
|
||||
pub fn handleOther(self: *Self, r: zap.Request, context: *ContextType) !bool {
|
||||
// in structs embedding a handler, we'd @fieldParentPtr the first
|
||||
// param to get to the real self
|
||||
|
||||
|
@ -41,7 +41,7 @@ pub fn Handler(comptime ContextType: anytype) type {
|
|||
var other_handler_finished = false;
|
||||
if (self.other_handler) |other_handler| {
|
||||
if (other_handler.on_request) |on_request| {
|
||||
other_handler_finished = on_request(other_handler, r, context);
|
||||
other_handler_finished = try on_request(other_handler, r, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,19 +96,19 @@ pub fn EndpointHandler(comptime HandlerType: anytype, comptime EndpointType: any
|
|||
///
|
||||
/// If `breakOnFinish` is `true`, the handler will stop handing requests down the chain if
|
||||
/// the endpoint processed the request.
|
||||
pub fn onRequest(handler: *HandlerType, r: zap.Request, context: *ContextType) bool {
|
||||
pub fn onRequest(handler: *HandlerType, r: zap.Request, context: *ContextType) !bool {
|
||||
const self: *Self = @fieldParentPtr("handler", handler);
|
||||
r.setUserContext(context);
|
||||
if (!self.options.checkPath or
|
||||
std.mem.startsWith(u8, r.path orelse "", self.endpoint.path))
|
||||
{
|
||||
switch (r.methodAsEnum()) {
|
||||
.GET => self.endpoint.*.get(r),
|
||||
.POST => self.endpoint.*.post(r),
|
||||
.PUT => self.endpoint.*.put(r),
|
||||
.DELETE => self.endpoint.*.delete(r),
|
||||
.PATCH => self.endpoint.*.patch(r),
|
||||
.OPTIONS => self.endpoint.*.options(r),
|
||||
.GET => try self.endpoint.*.get(r),
|
||||
.POST => try self.endpoint.*.post(r),
|
||||
.PUT => try self.endpoint.*.put(r),
|
||||
.DELETE => try self.endpoint.*.delete(r),
|
||||
.PATCH => try self.endpoint.*.patch(r),
|
||||
.OPTIONS => try self.endpoint.*.options(r),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ pub fn Listener(comptime ContextType: anytype) type {
|
|||
/// Create your own listener if you want different behavior.
|
||||
/// (Didn't want to make this a callback. Submit an issue if you really
|
||||
/// think that's an issue).
|
||||
pub fn onRequest(r: zap.Request) void {
|
||||
pub fn onRequest(r: zap.Request) !void {
|
||||
// we are the 1st handler in the chain, so we create a context
|
||||
var context: ContextType = .{};
|
||||
|
||||
|
@ -191,7 +191,7 @@ pub fn Listener(comptime ContextType: anytype) type {
|
|||
initial_handler.allocator = allocator;
|
||||
if (initial_handler.on_request) |on_request| {
|
||||
// we don't care about the return value at the top level
|
||||
_ = on_request(initial_handler, r, &context);
|
||||
_ = try on_request(initial_handler, r, &context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ pub const Options = struct {
|
|||
};
|
||||
|
||||
const CallbackTag = enum { bound, unbound };
|
||||
const BoundHandler = *fn (*const anyopaque, zap.Request) void;
|
||||
const BoundHandler = *fn (*const anyopaque, zap.Request) anyerror!void;
|
||||
const Callback = union(CallbackTag) {
|
||||
bound: struct { instance: usize, handler: usize },
|
||||
unbound: zap.HttpRequestFn,
|
||||
|
@ -94,24 +94,24 @@ pub fn on_request_handler(self: *Self) zap.HttpRequestFn {
|
|||
return zap_on_request;
|
||||
}
|
||||
|
||||
fn zap_on_request(r: zap.Request) void {
|
||||
fn zap_on_request(r: zap.Request) !void {
|
||||
return serve(_instance, r);
|
||||
}
|
||||
|
||||
fn serve(self: *Self, r: zap.Request) void {
|
||||
fn serve(self: *Self, r: zap.Request) !void {
|
||||
const path = r.path orelse "/";
|
||||
|
||||
if (self.routes.get(path)) |routeInfo| {
|
||||
switch (routeInfo) {
|
||||
.bound => |b| @call(.auto, @as(BoundHandler, @ptrFromInt(b.handler)), .{ @as(*anyopaque, @ptrFromInt(b.instance)), r }),
|
||||
.unbound => |h| h(r),
|
||||
.bound => |b| try @call(.auto, @as(BoundHandler, @ptrFromInt(b.handler)), .{ @as(*anyopaque, @ptrFromInt(b.instance)), r }),
|
||||
.unbound => |h| try h(r),
|
||||
}
|
||||
} else if (self.not_found) |handler| {
|
||||
// not found handler
|
||||
handler(r);
|
||||
try handler(r);
|
||||
} else {
|
||||
// default 404 output
|
||||
r.setStatus(.not_found);
|
||||
r.sendBody("404 Not Found") catch return;
|
||||
try r.sendBody("404 Not Found");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,8 +149,9 @@ fn makeRequestThread(a: std.mem.Allocator, url: []const u8, auth: ?ClientAuthReq
|
|||
|
||||
pub const Endpoint = struct {
|
||||
path: []const u8,
|
||||
error_strategy: zap.Endpoint.ErrorStrategy = .raise,
|
||||
|
||||
pub fn get(e: *Endpoint, r: zap.Request) void {
|
||||
pub fn get(e: *Endpoint, r: zap.Request) !void {
|
||||
_ = e;
|
||||
r.sendBody(HTTP_RESPONSE) catch return;
|
||||
received_response = HTTP_RESPONSE;
|
||||
|
@ -158,7 +159,7 @@ pub const Endpoint = struct {
|
|||
zap.stop();
|
||||
}
|
||||
|
||||
pub fn unauthorized(e: *Endpoint, r: zap.Request) void {
|
||||
pub fn unauthorized(e: *Endpoint, r: zap.Request) !void {
|
||||
_ = e;
|
||||
r.setStatus(.unauthorized);
|
||||
r.sendBody("UNAUTHORIZED ACCESS") catch return;
|
||||
|
@ -166,11 +167,11 @@ pub const Endpoint = struct {
|
|||
std.time.sleep(1 * std.time.ns_per_s);
|
||||
zap.stop();
|
||||
}
|
||||
pub fn post(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn put(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn delete(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn patch(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn options(_: *Endpoint, _: zap.Request) void {}
|
||||
pub fn post(_: *Endpoint, _: zap.Request) !void {}
|
||||
pub fn put(_: *Endpoint, _: zap.Request) !void {}
|
||||
pub fn delete(_: *Endpoint, _: zap.Request) !void {}
|
||||
pub fn patch(_: *Endpoint, _: zap.Request) !void {}
|
||||
pub fn options(_: *Endpoint, _: zap.Request) !void {}
|
||||
};
|
||||
//
|
||||
// end of http client code
|
||||
|
|
|
@ -30,7 +30,7 @@ test "http parameters" {
|
|||
var paramOneSlice: ?[]const u8 = null;
|
||||
var paramSlices: zap.Request.ParamSliceIterator = undefined;
|
||||
|
||||
pub fn on_request(r: zap.Request) void {
|
||||
pub fn on_request(r: zap.Request) !void {
|
||||
ran = true;
|
||||
r.parseQuery();
|
||||
param_count = r.getParamCount();
|
||||
|
|
|
@ -24,7 +24,7 @@ fn makeRequest(a: std.mem.Allocator, url: []const u8) !void {
|
|||
fn makeRequestThread(a: std.mem.Allocator, url: []const u8) !std.Thread {
|
||||
return try std.Thread.spawn(.{}, makeRequest, .{ a, url });
|
||||
}
|
||||
pub fn on_request(r: zap.Request) void {
|
||||
pub fn on_request(r: zap.Request) !void {
|
||||
r.sendFile("src/tests/testfile.txt") catch unreachable;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,12 +74,12 @@ pub fn stringifyBuf(
|
|||
buffer: []u8,
|
||||
value: anytype,
|
||||
options: std.json.StringifyOptions,
|
||||
) ?[]const u8 {
|
||||
) ![]const u8 {
|
||||
var fba = std.heap.FixedBufferAllocator.init(buffer);
|
||||
var string = std.ArrayList(u8).init(fba.allocator());
|
||||
if (std.json.stringify(value, options, string.writer())) {
|
||||
return string.items;
|
||||
} else |_| { // error
|
||||
return null;
|
||||
} else |err| { // error
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
|
13
src/zap.zig
13
src/zap.zig
|
@ -132,7 +132,7 @@ pub const ContentType = enum {
|
|||
pub const FioHttpRequestFn = *const fn (r: [*c]fio.http_s) callconv(.C) void;
|
||||
|
||||
/// Zap Http request callback function type.
|
||||
pub const HttpRequestFn = *const fn (Request) void;
|
||||
pub const HttpRequestFn = *const fn (Request) anyerror!void;
|
||||
|
||||
/// websocket connection upgrade callback type
|
||||
/// fn(request, targetstring)
|
||||
|
@ -202,8 +202,10 @@ pub const HttpListener = struct {
|
|||
req.markAsFinished(false);
|
||||
std.debug.assert(l.settings.on_request != null);
|
||||
if (l.settings.on_request) |on_request| {
|
||||
// l.settings.on_request.?(req);
|
||||
on_request(req);
|
||||
on_request(req) catch |err| {
|
||||
// TODO: log / handle the error in a better way
|
||||
std.debug.print("zap on_request error: {}", .{err});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +227,10 @@ pub const HttpListener = struct {
|
|||
var user_context: Request.UserContext = .{};
|
||||
req._user_context = &user_context;
|
||||
|
||||
l.settings.on_response.?(req);
|
||||
l.settings.on_response.?(req) catch |err| {
|
||||
// TODO: log / handle the error in a better way
|
||||
std.debug.print("zap on_response error: {}", .{err});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const std = @import("std");
|
||||
const zap = @import("zap");
|
||||
|
||||
fn on_request(r: zap.Request) void {
|
||||
fn on_request(r: zap.Request) !void {
|
||||
r.setStatus(.not_found);
|
||||
r.sendBody("<html><body><h1>404 - File not found</h1></body></html>") catch return;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const std = @import("std");
|
||||
const zap = @import("zap");
|
||||
|
||||
fn on_request_minimal(r: zap.Request) void {
|
||||
r.sendBody("Hello from ZAP!!!") catch return;
|
||||
fn on_request_minimal(r: zap.Request) !void {
|
||||
try r.sendBody("Hello from ZAP!!!");
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
|
|
Loading…
Add table
Reference in a new issue