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