1
0
Fork 0
mirror of https://github.com/zigzap/zap.git synced 2025-10-20 15:14:08 +00:00

API cleanup #1

--------------

- EndpointListener.register() // was: addEndpoint
- no more Simple
- getEndpoint -> endpoint()
This commit is contained in:
renerocksai 2024-01-08 15:50:46 +01:00
parent 5a284fc96d
commit 3d651229f8
32 changed files with 353 additions and 252 deletions

View file

@ -113,9 +113,9 @@ port and docs dir: `zig build docserver && zig-out/bin/docserver --port=8989
less type-safe than `zap.Middleware`'s use of contexts. less type-safe than `zap.Middleware`'s use of contexts.
- [**Per Request Contexts**](./src/zap.zig#L102) : With the introduction of - [**Per Request Contexts**](./src/zap.zig#L102) : With the introduction of
`setUserContext()` and `getUserContext()`, you can, of course use those two in `setUserContext()` and `getUserContext()`, you can, of course use those two in
projects that don't use `zap.SimpleEndpoint` or `zap.Middleware`, too, if you projects that don't use `zap.Endpoint` or `zap.Middleware`, too, if you
really, really, absolutely don't find another way to solve your context really, really, absolutely don't find another way to solve your context
problem. **We recommend using a `zap.SimpleEndpoint`** inside of a struct that problem. **We recommend using a `zap.Endpoint`** inside of a struct that
can provide all the context you need **instead**. You get access to your can provide all the context you need **instead**. You get access to your
struct in the callbacks via the `@fieldParentPtr()` trick that is used struct in the callbacks via the `@fieldParentPtr()` trick that is used
extensively in Zap's examples, like the [endpoint extensively in Zap's examples, like the [endpoint
@ -376,7 +376,7 @@ $ zig build run-routes
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
fn on_request(r: zap.SimpleRequest) void { fn on_request(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});
} }
@ -388,7 +388,7 @@ fn on_request(r: zap.SimpleRequest) void {
} }
pub fn main() !void { pub fn main() !void {
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = on_request, .on_request = on_request,
.log = true, .log = true,

View file

@ -12,7 +12,7 @@ For convenience, Authenticator types exist that can authenticate requests.
Zap also provides an `AuthenticatingEndpoint` endpoint-wrapper. Have a look at the [example](../examples/endpoint_auth) and the [tests](../src/tests/test_auth.zig). Zap also provides an `AuthenticatingEndpoint` endpoint-wrapper. Have a look at the [example](../examples/endpoint_auth) and the [tests](../src/tests/test_auth.zig).
The following describes the Authenticator types. All of them provide the The following describes the Authenticator types. All of them provide the
`authenticateRequest()` function, which takes a `zap.SimpleRequest` and returns `authenticateRequest()` function, which takes a `zap.Request` and returns
a bool value whether it could be authenticated or not. a bool value whether it could be authenticated or not.
Further down, we show how to use the Authenticators, and also the Further down, we show how to use the Authenticators, and also the
@ -60,7 +60,7 @@ var auth = try zap.BearerAuthSingle.init(allocator, token, null);
defer auth.deinit(); defer auth.deinit();
fn on_request(r: zap.SimpleRequest) void { fn on_request(r: zap.Request) void {
if(authenticator.authenticateRequest(r)) { if(authenticator.authenticateRequest(r)) {
r.sendBody( r.sendBody(
\\ <html><body> \\ <html><body>
@ -94,7 +94,7 @@ var auth = try zap.BearerAuthMulti(Set).init(allocator, &set, null);
defer auth.deinit(); defer auth.deinit();
fn on_request(r: zap.SimpleRequest) void { fn on_request(r: zap.Request) void {
if(authenticator.authenticateRequest(r)) { if(authenticator.authenticateRequest(r)) {
r.sendBody( r.sendBody(
\\ <html><body> \\ <html><body>
@ -132,7 +132,7 @@ var auth = try Authenticator.init(a, &map, null);
defer auth.deinit(); defer auth.deinit();
fn on_request(r: zap.SimpleRequest) void { fn on_request(r: zap.Request) void {
if(authenticator.authenticateRequest(r)) { if(authenticator.authenticateRequest(r)) {
r.sendBody( r.sendBody(
\\ <html><body> \\ <html><body>
@ -168,7 +168,7 @@ var auth = try Authenticator.init(allocator, &set, null);
defer auth.deinit(); defer auth.deinit();
fn on_request(r: zap.SimpleRequest) void { fn on_request(r: zap.Request) void {
if(authenticator.authenticateRequest(r)) { if(authenticator.authenticateRequest(r)) {
r.sendBody( r.sendBody(
\\ <html><body> \\ <html><body>
@ -206,13 +206,13 @@ const HTTP_RESPONSE: []const u8 =
; ;
// authenticated requests go here // authenticated requests go here
fn endpoint_http_get(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn endpoint_http_get(e: *zap.Endpoint, r: zap.Request) void {
_ = e; _ = e;
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
fn endpoint_http_unauthorized(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn endpoint_http_unauthorized(e: *zap.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;
@ -220,7 +220,7 @@ fn endpoint_http_unauthorized(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void
pub fn main() !void { pub fn main() !void {
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -233,7 +233,7 @@ pub fn main() !void {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = zap.SimpleEndpoint.init(.{ var ep = zap.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -248,7 +248,7 @@ pub fn main() !void {
const BearerAuthEndpoint = zap.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = zap.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
std.debug.print( std.debug.print(

View file

@ -58,14 +58,14 @@ Now that I think I've made my point 😊, you can, of course always do the
following: following:
```zig ```zig
fn on_request_with_errors(r: zap.SimpleHttpRequest) !void { fn on_request_with_errors(r: zap.HttpRequest) !void {
// do all the try stuff here // do all the try stuff here
} }
``` ```
```zig ```zig
// THIS IS WHAT YOU PASS TO THE LISTENER / ENDPONT / ... // THIS IS WHAT YOU PASS TO THE LISTENER / ENDPONT / ...
fn on_request(r: zap.SimpleHttpRequest) void { fn on_request(r: zap.HttpRequest) void {
on_request_with_errors(r) catch |err| { on_request_with_errors(r) catch |err| {
// log the error or use: // log the error or use:
return r.returnWithErrorStackTrace(err); return r.returnWithErrorStackTrace(err);

View file

@ -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.SimpleRequest) void { pub fn on_request(r: zap.Request) void {
// check for FORM parameters // check for FORM parameters
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});
@ -92,7 +92,7 @@ pub fn main() !void {
Handler.alloc = allocator; Handler.alloc = allocator;
// setup listener // setup listener
var listener = zap.SimpleHttpListener.init( var listener = zap.HttpListener.init(
.{ .{
.port = 3000, .port = 3000,
.on_request = Handler.on_request, .on_request = Handler.on_request,

View file

@ -33,7 +33,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.SimpleRequest) 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", .{});
@ -98,7 +98,7 @@ pub fn main() !void {
Handler.alloc = allocator; Handler.alloc = allocator;
// setup listener // setup listener
var listener = zap.SimpleHttpListener.init( var listener = zap.HttpListener.init(
.{ .{
.port = 3000, .port = 3000,
.on_request = Handler.on_request, .on_request = Handler.on_request,

View file

@ -1,10 +1,10 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
const Endpoint = @import("endpoint.zig"); 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 // this is just to demo that we can catch arbitrary slugs
fn on_request(r: zap.SimpleRequest) 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});
} }
@ -21,7 +21,7 @@ pub fn main() !void {
// we scope everything that can allocate within this block for leak detection // we scope everything that can allocate within this block for leak detection
{ {
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
allocator, allocator,
.{ .{
.port = 3000, .port = 3000,
@ -34,19 +34,20 @@ pub fn main() !void {
); );
defer listener.deinit(); defer listener.deinit();
var endpoint = Endpoint.init(allocator, "/users"); // /users endpoint
defer endpoint.deinit(); var userWeb = UserWeb.init(allocator, "/users");
defer userWeb.deinit();
var stopEp = StopEndpoint.init("/stop"); var stopEp = StopEndpoint.init("/stop");
// add endpoint // register endpoints with the listener
try listener.addEndpoint(endpoint.getUserEndpoint()); try listener.register(userWeb.endpoint());
try listener.addEndpoint(stopEp.getEndpoint()); try listener.register(stopEp.endpoint());
// fake some users // fake some users
var uid: usize = undefined; var uid: usize = undefined;
uid = try endpoint.getUsers().addByName("renerocksai", null); uid = try userWeb.users().addByName("renerocksai", null);
uid = try endpoint.getUsers().addByName("renerocksai", "your mom"); uid = try userWeb.users().addByName("renerocksai", "your mom");
// listen // listen
try listener.listen(); try listener.listen();

View file

@ -5,24 +5,24 @@ const zap = @import("zap");
/// the main thread usually continues at the instructions after the call to zap.start(). /// the main thread usually continues at the instructions after the call to zap.start().
pub const Self = @This(); pub const Self = @This();
endpoint: zap.SimpleEndpoint = undefined, ep: zap.Endpoint = undefined,
pub fn init( pub fn init(
path: []const u8, path: []const u8,
) Self { ) Self {
return .{ return .{
.endpoint = zap.SimpleEndpoint.init(.{ .ep = zap.Endpoint.init(.{
.path = path, .path = path,
.get = get, .get = get,
}), }),
}; };
} }
pub fn getEndpoint(self: *Self) *zap.SimpleEndpoint { pub fn endpoint(self: *Self) *zap.Endpoint {
return &self.endpoint; return &self.ep;
} }
fn get(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn get(e: *zap.Endpoint, r: zap.Request) void {
_ = e; _ = e;
_ = r; _ = r;
zap.stop(); zap.stop();

View file

@ -8,8 +8,8 @@ const User = Users.User;
pub const Self = @This(); pub const Self = @This();
alloc: std.mem.Allocator = undefined, alloc: std.mem.Allocator = undefined,
endpoint: zap.SimpleEndpoint = undefined, ep: zap.Endpoint = undefined,
users: Users = undefined, _users: Users = undefined,
pub fn init( pub fn init(
a: std.mem.Allocator, a: std.mem.Allocator,
@ -17,8 +17,8 @@ pub fn init(
) Self { ) Self {
return .{ return .{
.alloc = a, .alloc = a,
.users = Users.init(a), ._users = Users.init(a),
.endpoint = zap.SimpleEndpoint.init(.{ .ep = zap.Endpoint.init(.{
.path = user_path, .path = user_path,
.get = getUser, .get = getUser,
.post = postUser, .post = postUser,
@ -31,30 +31,30 @@ pub fn init(
} }
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
self.users.deinit(); self._users.deinit();
} }
pub fn getUsers(self: *Self) *Users { pub fn users(self: *Self) *Users {
return &self.users; return &self._users;
} }
pub fn getUserEndpoint(self: *Self) *zap.SimpleEndpoint { pub fn endpoint(self: *Self) *zap.Endpoint {
return &self.endpoint; return &self.ep;
} }
fn userIdFromPath(self: *Self, path: []const u8) ?usize { fn userIdFromPath(self: *Self, path: []const u8) ?usize {
if (path.len >= self.endpoint.settings.path.len + 2) { if (path.len >= self.ep.settings.path.len + 2) {
if (path[self.endpoint.settings.path.len] != '/') { if (path[self.ep.settings.path.len] != '/') {
return null; return null;
} }
const idstr = path[self.endpoint.settings.path.len + 1 ..]; const idstr = path[self.ep.settings.path.len + 1 ..];
return std.fmt.parseUnsigned(usize, idstr, 10) catch null; return std.fmt.parseUnsigned(usize, idstr, 10) catch null;
} }
return null; return null;
} }
fn getUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn getUser(e: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "endpoint", e); const self = @fieldParentPtr(Self, "ep", e);
if (r.path) |path| { if (r.path) |path| {
// /users // /users
if (path.len == e.settings.path.len) { if (path.len == e.settings.path.len) {
@ -62,7 +62,7 @@ fn getUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) 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.stringifyBuf(&jsonbuf, user, .{})) |json| { if (zap.stringifyBuf(&jsonbuf, user, .{})) |json| {
r.sendJson(json) catch return; r.sendJson(json) catch return;
} }
@ -71,8 +71,8 @@ fn getUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
} }
} }
fn listUsers(self: *Self, r: zap.SimpleRequest) 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; r.sendJson(json) catch return;
} else |err| { } else |err| {
@ -80,13 +80,13 @@ fn listUsers(self: *Self, r: zap.SimpleRequest) void {
} }
} }
fn postUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn postUser(e: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "endpoint", e); const self = @fieldParentPtr(Self, "ep", e);
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.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| { if (zap.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| {
r.sendJson(json) catch return; r.sendJson(json) catch return;
@ -99,17 +99,17 @@ fn postUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
} }
} }
fn putUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn putUser(e: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "endpoint", e); const self = @fieldParentPtr(Self, "ep", e);
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)) |_| {
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();
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.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| { if (zap.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| {
r.sendJson(json) catch return; r.sendJson(json) catch return;
} }
@ -125,12 +125,12 @@ fn putUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
} }
} }
fn deleteUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn deleteUser(e: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "endpoint", e); const self = @fieldParentPtr(Self, "ep", e);
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.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| { if (zap.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| {
r.sendJson(json) catch return; r.sendJson(json) catch return;
} }
@ -143,7 +143,7 @@ fn deleteUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
} }
} }
fn optionsUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn optionsUser(e: *zap.Endpoint, r: zap.Request) void {
_ = e; _ = e;
r.setHeader("Access-Control-Allow-Origin", "*") catch return; r.setHeader("Access-Control-Allow-Origin", "*") catch return;
r.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS") catch return; r.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS") catch return;

View file

@ -11,13 +11,13 @@ const HTTP_RESPONSE: []const u8 =
; ;
// authenticated requests go here // authenticated requests go here
fn endpoint_http_get(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn endpoint_http_get(e: *zap.Endpoint, r: zap.Request) void {
_ = e; _ = e;
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
fn endpoint_http_unauthorized(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { fn endpoint_http_unauthorized(e: *zap.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;
@ -25,7 +25,7 @@ fn endpoint_http_unauthorized(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void
pub fn main() !void { pub fn main() !void {
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -38,7 +38,7 @@ pub fn main() !void {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = zap.SimpleEndpoint.init(.{ var ep = zap.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -53,7 +53,7 @@ pub fn main() !void {
const BearerAuthEndpoint = zap.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = zap.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
std.debug.print( std.debug.print(

View file

@ -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.SimpleRequest) 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});
} }
@ -12,12 +12,12 @@ fn on_request_verbose(r: zap.SimpleRequest) void {
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return; r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
} }
fn on_request_minimal(r: zap.SimpleRequest) void { fn on_request_minimal(r: zap.Request) void {
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return; r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
} }
pub fn main() !void { pub fn main() !void {
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = on_request_verbose, .on_request = on_request_verbose,
.log = true, .log = true,

View file

@ -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.SimpleRequest) void { fn on_request(r: zap.Request) void {
const m = r.method orelse ""; const m = r.method orelse "";
const p = r.path orelse "/"; const p = r.path orelse "/";
const qm = if (r.query) |_| "?" else ""; const qm = if (r.query) |_| "?" else "";
@ -35,7 +35,7 @@ fn on_request(r: zap.SimpleRequest) void {
} }
pub fn main() !void { pub fn main() !void {
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = on_request, .on_request = on_request,
.log = false, .log = false,

View file

@ -6,7 +6,7 @@ const User = struct {
last_name: ?[]const u8 = null, last_name: ?[]const u8 = null,
}; };
fn on_request(r: zap.SimpleRequest) void { fn on_request(r: zap.Request) void {
if (!std.mem.eql(u8, r.method.?, "GET")) if (!std.mem.eql(u8, r.method.?, "GET"))
return; return;
@ -43,7 +43,7 @@ fn setupUserData(a: std.mem.Allocator) !void {
pub fn main() !void { pub fn main() !void {
const a = std.heap.page_allocator; const a = std.heap.page_allocator;
try setupUserData(a); try setupUserData(a);
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = on_request, .on_request = on_request,
.log = false, .log = false,

View file

@ -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.SimpleRequest) 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", .{});
@ -98,7 +98,7 @@ pub fn main() !void {
Handler.alloc = allocator; Handler.alloc = allocator;
// setup listener // setup listener
var listener = zap.SimpleHttpListener.init( var listener = zap.HttpListener.init(
.{ .{
.port = 3000, .port = 3000,
.on_request = Handler.on_request, .on_request = Handler.on_request,

View file

@ -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.SimpleRequest) 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});
} }
@ -12,7 +12,7 @@ fn on_request_verbose(r: zap.SimpleRequest) void {
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return; r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
} }
fn on_request_minimal(r: zap.SimpleRequest) void { fn on_request_minimal(r: zap.Request) void {
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return; r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
} }
@ -51,7 +51,7 @@ pub fn main() !void {
}); });
defer tls.deinit(); defer tls.deinit();
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 4443, .port = 4443,
.on_request = on_request_verbose, .on_request = on_request_verbose,
.log = true, .log = true,

View file

@ -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.SimpleRequest, 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 = @fieldParentPtr(Self, "handler", handler); const self = @fieldParentPtr(Self, "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.SimpleRequest, 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 = @fieldParentPtr(Self, "handler", handler); const self = @fieldParentPtr(Self, "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.SimpleRequest, 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 = @fieldParentPtr(Self, "handler", handler); const self = @fieldParentPtr(Self, "handler", handler);

View file

@ -56,7 +56,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.SimpleRequest, 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 = @fieldParentPtr(Self, "handler", handler); const self = @fieldParentPtr(Self, "handler", handler);
@ -102,7 +102,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.SimpleRequest, 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 = @fieldParentPtr(Self, "handler", handler); const self = @fieldParentPtr(Self, "handler", handler);
_ = self; _ = self;
@ -137,24 +137,24 @@ const SessionMiddleWare = struct {
// parameter. // parameter.
// //
const HtmlEndpoint = struct { const HtmlEndpoint = struct {
endpoint: zap.SimpleEndpoint = undefined, ep: zap.Endpoint = undefined,
const Self = @This(); const Self = @This();
pub fn init() Self { pub fn init() Self {
return .{ return .{
.endpoint = zap.SimpleEndpoint.init(.{ .ep = zap.Endpoint.init(.{
.path = "/doesn'tmatter", .path = "/doesn'tmatter",
.get = get, .get = get,
}), }),
}; };
} }
pub fn getEndpoint(self: *Self) *zap.SimpleEndpoint { pub fn endpoint(self: *Self) *zap.Endpoint {
return &self.endpoint; return &self.ep;
} }
pub fn get(ep: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { pub fn get(ep: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "endpoint", ep); const self = @fieldParentPtr(Self, "ep", ep);
_ = self; _ = self;
var buf: [1024]u8 = undefined; var buf: [1024]u8 = undefined;
@ -207,7 +207,7 @@ pub fn main() !void {
// we wrap the endpoint with a middleware handler // we wrap the endpoint with a middleware handler
var htmlHandler = zap.Middleware.EndpointHandler(Handler, Context).init( var htmlHandler = zap.Middleware.EndpointHandler(Handler, Context).init(
htmlEndpoint.getEndpoint(), // the endpoint htmlEndpoint.endpoint(), // the endpoint
null, // no other handler (we are the last in the chain) null, // no other handler (we are the last in the chain)
true, // break on finish. See EndpointHandler for this. Not applicable here. true, // break on finish. See EndpointHandler for this. Not applicable here.
); );

View file

@ -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.SimpleRequest) void { fn on_request(r: zap.Request) void {
const template = const template =
\\ {{=<< >>=}} \\ {{=<< >>=}}
\\ * Users: \\ * Users:
@ -49,7 +49,7 @@ fn on_request(r: zap.SimpleRequest) void {
} }
pub fn main() !void { pub fn main() !void {
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = on_request, .on_request = on_request,
.log = true, .log = true,

View file

@ -1,7 +1,9 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
fn dispatch_routes(r: zap.SimpleRequest) void { // 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 {
// dispatch // dispatch
if (r.path) |the_path| { if (r.path) |the_path| {
if (routes.get(the_path)) |foo| { if (routes.get(the_path)) |foo| {
@ -20,12 +22,12 @@ fn dispatch_routes(r: zap.SimpleRequest) void {
) catch return; ) catch return;
} }
fn static_site(r: zap.SimpleRequest) void { fn static_site(r: zap.Request) void {
r.sendBody("<html><body><h1>Hello from STATIC ZAP!</h1></body></html>") catch return; r.sendBody("<html><body><h1>Hello from STATIC ZAP!</h1></body></html>") catch return;
} }
var dynamic_counter: i32 = 0; var dynamic_counter: i32 = 0;
fn dynamic_site(r: zap.SimpleRequest) 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 = std.fmt.bufPrintZ(
@ -37,16 +39,16 @@ fn dynamic_site(r: zap.SimpleRequest) void {
} }
fn setup_routes(a: std.mem.Allocator) !void { fn setup_routes(a: std.mem.Allocator) !void {
routes = std.StringHashMap(zap.SimpleHttpRequestFn).init(a); routes = std.StringHashMap(zap.HttpRequestFn).init(a);
try routes.put("/static", static_site); try routes.put("/static", static_site);
try routes.put("/dynamic", dynamic_site); try routes.put("/dynamic", dynamic_site);
} }
var routes: std.StringHashMap(zap.SimpleHttpRequestFn) = undefined; var routes: std.StringHashMap(zap.HttpRequestFn) = undefined;
pub fn main() !void { pub fn main() !void {
try setup_routes(std.heap.page_allocator); try setup_routes(std.heap.page_allocator);
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = dispatch_routes, .on_request = dispatch_routes,
.log = true, .log = true,

View file

@ -5,14 +5,14 @@ fn MAKE_MEGA_ERROR() !void {
return error.MEGA_ERROR; return error.MEGA_ERROR;
} }
fn MY_REQUEST_HANDLER(r: zap.SimpleRequest) void { fn MY_REQUEST_HANDLER(r: zap.Request) void {
MAKE_MEGA_ERROR() catch |err| { MAKE_MEGA_ERROR() catch |err| {
r.sendError(err, 505); r.sendError(err, 505);
}; };
} }
pub fn main() !void { pub fn main() !void {
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = MY_REQUEST_HANDLER, .on_request = MY_REQUEST_HANDLER,
.log = true, .log = true,

View file

@ -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.SimpleRequest) 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
@ -27,7 +27,7 @@ pub fn on_request(r: zap.SimpleRequest) void {
pub fn main() !void { pub fn main() !void {
// setup listener // setup listener
var listener = zap.SimpleHttpListener.init( var listener = zap.HttpListener.init(
.{ .{
.port = 3000, .port = 3000,
.on_request = on_request, .on_request = on_request,

View file

@ -1,13 +1,13 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
fn on_request(r: zap.SimpleRequest) 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;
} }
pub fn main() !void { pub fn main() !void {
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = on_request, .on_request = on_request,
.public_folder = "examples/serve", .public_folder = "examples/serve",

View file

@ -20,17 +20,17 @@ const loginpage = @embedFile("html/login.html");
const img = @embedFile("./html/Ziggy_the_Ziguana.svg.png"); const img = @embedFile("./html/Ziggy_the_Ziguana.svg.png");
// global vars yeah! // global vars yeah!
// in bigger projects, we'd probably make use of zap.SimpleEndpoint or // in bigger projects, we'd probably make use of zap.Endpoint or
// zap.Middleware and "hide" stuff like authenticators in there // zap.Middleware and "hide" stuff like authenticators in there
var authenticator: Authenticator = undefined; var authenticator: Authenticator = undefined;
// the login page (embedded) // the login page (embedded)
fn on_login(r: zap.SimpleRequest) void { fn on_login(r: zap.Request) void {
r.sendBody(loginpage) catch return; r.sendBody(loginpage) catch return;
} }
// the "normal page" // the "normal page"
fn on_normal_page(r: zap.SimpleRequest) void { fn on_normal_page(r: zap.Request) void {
zap.debug("on_normal_page()\n", .{}); zap.debug("on_normal_page()\n", .{});
r.sendBody( r.sendBody(
\\ <html><body> \\ <html><body>
@ -42,7 +42,7 @@ fn on_normal_page(r: zap.SimpleRequest) void {
} }
// the logged-out page // the logged-out page
fn on_logout(r: zap.SimpleRequest) 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
@ -56,7 +56,7 @@ fn on_logout(r: zap.SimpleRequest) void {
) catch return; ) catch return;
} }
fn on_request(r: zap.SimpleRequest) 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.
@ -124,7 +124,7 @@ pub fn main() !void {
// to detect leaks // to detect leaks
{ {
const allocator = gpa.allocator(); const allocator = gpa.allocator();
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = on_request, .on_request = on_request,
.log = true, .log = true,

View file

@ -162,7 +162,7 @@ fn handle_websocket_message(
// //
// HTTP stuff // HTTP stuff
// //
fn on_request(r: zap.SimpleRequest) void { fn on_request(r: zap.Request) void {
r.setHeader("Server", "zap.example") catch unreachable; r.setHeader("Server", "zap.example") catch unreachable;
r.sendBody( r.sendBody(
\\ <html><body> \\ <html><body>
@ -171,7 +171,7 @@ fn on_request(r: zap.SimpleRequest) void {
) catch return; ) catch return;
} }
fn on_upgrade(r: zap.SimpleRequest, target_protocol: []const u8) void { fn on_upgrade(r: zap.Request, target_protocol: []const u8) void {
// make sure we're talking the right protocol // make sure we're talking the right protocol
if (!std.mem.eql(u8, target_protocol, "websocket")) { if (!std.mem.eql(u8, target_protocol, "websocket")) {
std.log.warn("received illegal protocol: {s}", .{target_protocol}); std.log.warn("received illegal protocol: {s}", .{target_protocol});
@ -207,7 +207,7 @@ pub fn main() !void {
defer GlobalContextManager.deinit(); defer GlobalContextManager.deinit();
// setup listener // setup listener
var listener = zap.SimpleHttpListener.init( var listener = zap.HttpListener.init(
.{ .{
.port = 3010, .port = 3010,
.on_request = on_request, .on_request = on_request,

View file

@ -2,29 +2,86 @@ 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");
const Request = zap.SimpleRequest; // zap types
const ListenerSettings = zap.SimpleHttpListenerSettings; const Request = zap.Request;
const Listener = zap.SimpleHttpListener; const ListenerSettings = zap.HttpListenerSettings;
const Listener = zap.HttpListener;
pub const RequestFn = *const fn (self: *SimpleEndpoint, r: Request) void; /// Type of the request function callbacks.
pub const SimpleEndpointSettings = struct { pub const RequestFn = *const fn (self: *Endpoint, r: Request) void;
/// Settings to initialize an Endpoint
pub const EndpointSettings = struct {
/// path / slug of the endpoint
path: []const u8, path: []const u8,
/// callback to GET request handler
get: ?RequestFn = null, get: ?RequestFn = null,
/// callback to POST request handler
post: ?RequestFn = null, post: ?RequestFn = null,
/// callback to PUT request handler
put: ?RequestFn = null, put: ?RequestFn = null,
/// callback to DELETE request handler
delete: ?RequestFn = null, delete: ?RequestFn = null,
/// callback to PATCH request handler
patch: ?RequestFn = null, patch: ?RequestFn = null,
/// callback to OPTIONS request handler
options: ?RequestFn = null, options: ?RequestFn = null,
/// only applicable to AuthenticatingEndpoint /// Only applicable to AuthenticatingEndpoint: handler for unauthorized requests
unauthorized: ?RequestFn = null, unauthorized: ?RequestFn = null,
}; };
pub const SimpleEndpoint = struct { /// The simple Endpoint struct. Create one and pass in your callbacks. Then,
settings: SimpleEndpointSettings, /// pass it to a HttpListener's `register()` function to register with the
/// listener.
///
/// **NOTE**: A common endpoint pattern for zap is to create your own struct
/// that embeds an Endpoint, provides specific callbacks, and uses
/// `@fieldParentPtr` to get a reference to itself.
///
/// Example:
/// A simple endpoint listening on the /stop route that shuts down zap.
/// The main thread usually continues at the instructions after the call to zap.start().
///
/// ```zig
/// // file: stopendpoint.zig
///
/// pub const Self = @This();
///
/// ep: zap.Endpoint = undefined,
///
/// pub fn init(
/// path: []const u8,
/// ) Self {
/// return .{
/// .ep = zap.Endpoint.init(.{
/// .path = path,
/// .get = get,
/// }),
/// };
/// }
///
/// // access the internal Endpoint
/// pub fn endpoint(self: *Self) *zap.Endpoint {
/// return &self.ep;
/// }
///
/// fn get(e: *zap.Endpoint, r: zap.Request) void {
/// const self: *Self = @fieldParentPtr(Self, "ep", e);
/// _ = self;
/// _ = e;
/// _ = r;
/// zap.stop();
/// }
/// ```
pub const Endpoint = struct {
settings: EndpointSettings,
const Self = @This(); const Self = @This();
pub fn init(s: SimpleEndpointSettings) Self { /// Initialize the endpoint.
/// Set only the callbacks you need. Requests of HTTP methods without a
/// provided callback will be ignored.
pub fn init(s: EndpointSettings) Self {
return .{ return .{
.settings = .{ .settings = .{
.path = s.path, .path = s.path,
@ -39,12 +96,14 @@ pub const SimpleEndpoint = struct {
}; };
} }
fn nop(self: *SimpleEndpoint, r: Request) void { // no operation. Dummy handler function for ignoring unset request types.
fn nop(self: *Endpoint, r: Request) void {
_ = self; _ = self;
_ = r; _ = r;
} }
pub fn onRequest(self: *SimpleEndpoint, r: zap.SimpleRequest) void { /// The global request handler for this Endpoint, called by the listener.
pub fn onRequest(self: *Endpoint, r: zap.Request) void {
if (r.method) |m| { if (r.method) |m| {
if (std.mem.eql(u8, m, "GET")) if (std.mem.eql(u8, m, "GET"))
return self.settings.get.?(self, r); return self.settings.get.?(self, r);
@ -62,19 +121,23 @@ pub const SimpleEndpoint = struct {
} }
}; };
/// Wrap an endpoint with an authenticator /// Wrap an endpoint with an Authenticator -> new Endpoint of type Endpoint
/// is available via the `endpoint()` function.
pub fn AuthenticatingEndpoint(comptime Authenticator: type) type { pub fn AuthenticatingEndpoint(comptime Authenticator: type) type {
return struct { return struct {
authenticator: *Authenticator, authenticator: *Authenticator,
endpoint: *SimpleEndpoint, ep: *Endpoint,
auth_endpoint: SimpleEndpoint, auth_endpoint: Endpoint,
const Self = @This(); const Self = @This();
pub fn init(e: *SimpleEndpoint, authenticator: *Authenticator) Self { /// Init the authenticating endpoint. Pass in a pointer to the endpoint
/// you want to wrap, and the Authenticator that takes care of authenticating
/// requests.
pub fn init(e: *Endpoint, authenticator: *Authenticator) Self {
return .{ return .{
.authenticator = authenticator, .authenticator = authenticator,
.endpoint = e, .ep = e,
.auth_endpoint = SimpleEndpoint.init(.{ .auth_endpoint = Endpoint.init(.{
.path = e.settings.path, .path = e.settings.path,
// we override only the set ones. the other ones // we override only the set ones. the other ones
// are set to null anyway -> will be nopped out // are set to null anyway -> will be nopped out
@ -89,20 +152,21 @@ pub fn AuthenticatingEndpoint(comptime Authenticator: type) type {
}; };
} }
/// get the auth endpoint struct so we can be stored in the listener /// Get the auth endpoint struct of type Endpoint so it can be stored in the listener.
/// when the listener calls the auth_endpoint, onRequest will have /// When the listener calls the auth_endpoint, onRequest will have
/// access to all of us via fieldParentPtr /// access to all of this via fieldParentPtr
pub fn getEndpoint(self: *Self) *SimpleEndpoint { pub fn endpoint(self: *Self) *Endpoint {
return &self.auth_endpoint; return &self.auth_endpoint;
} }
/// here, the auth_endpoint will be passed in /// GET: here, the auth_endpoint will be passed in as endpoint.
pub fn get(e: *SimpleEndpoint, r: zap.SimpleRequest) void { /// Authenticates GET requests using the Authenticator.
pub fn get(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e); const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) { switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => { .AuthFailed => {
if (e.settings.unauthorized) |unauthorized| { if (e.settings.unauthorized) |unauthorized| {
unauthorized(authEp.endpoint, r); unauthorized(authEp.ep, r);
return; return;
} else { } else {
r.setStatus(.unauthorized); r.setStatus(.unauthorized);
@ -110,18 +174,19 @@ pub fn AuthenticatingEndpoint(comptime Authenticator: type) type {
return; return;
} }
}, },
.AuthOK => authEp.endpoint.settings.get.?(authEp.endpoint, r), .AuthOK => authEp.ep.settings.get.?(authEp.ep, r),
.Handled => {}, .Handled => {},
} }
} }
/// here, the auth_endpoint will be passed in /// POST: here, the auth_endpoint will be passed in as endpoint.
pub fn post(e: *SimpleEndpoint, r: zap.SimpleRequest) void { /// Authenticates POST requests using the Authenticator.
pub fn post(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e); const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) { switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => { .AuthFailed => {
if (e.settings.unauthorized) |unauthorized| { if (e.settings.unauthorized) |unauthorized| {
unauthorized(authEp.endpoint, r); unauthorized(authEp.ep, r);
return; return;
} else { } else {
r.setStatus(.unauthorized); r.setStatus(.unauthorized);
@ -129,18 +194,19 @@ pub fn AuthenticatingEndpoint(comptime Authenticator: type) type {
return; return;
} }
}, },
.AuthOK => authEp.endpoint.settings.post.?(authEp.endpoint, r), .AuthOK => authEp.ep.settings.post.?(authEp.ep, r),
.Handled => {}, .Handled => {},
} }
} }
/// here, the auth_endpoint will be passed in /// PUT: here, the auth_endpoint will be passed in as endpoint.
pub fn put(e: *SimpleEndpoint, r: zap.SimpleRequest) void { /// Authenticates PUT requests using the Authenticator.
pub fn put(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e); const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) { switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => { .AuthFailed => {
if (e.settings.unauthorized) |unauthorized| { if (e.settings.unauthorized) |unauthorized| {
unauthorized(authEp.endpoint, r); unauthorized(authEp.ep, r);
return; return;
} else { } else {
r.setStatus(.unauthorized); r.setStatus(.unauthorized);
@ -148,18 +214,19 @@ pub fn AuthenticatingEndpoint(comptime Authenticator: type) type {
return; return;
} }
}, },
.AuthOK => authEp.endpoint.settings.put.?(authEp.endpoint, r), .AuthOK => authEp.ep.settings.put.?(authEp.ep, r),
.Handled => {}, .Handled => {},
} }
} }
/// here, the auth_endpoint will be passed in /// DELETE: here, the auth_endpoint will be passed in as endpoint.
pub fn delete(e: *SimpleEndpoint, r: zap.SimpleRequest) void { /// Authenticates DELETE requests using the Authenticator.
pub fn delete(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e); const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) { switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => { .AuthFailed => {
if (e.settings.unauthorized) |unauthorized| { if (e.settings.unauthorized) |unauthorized| {
unauthorized(authEp.endpoint, r); unauthorized(authEp.ep, r);
return; return;
} else { } else {
r.setStatus(.unauthorized); r.setStatus(.unauthorized);
@ -167,18 +234,19 @@ pub fn AuthenticatingEndpoint(comptime Authenticator: type) type {
return; return;
} }
}, },
.AuthOK => authEp.endpoint.settings.delete.?(authEp.endpoint, r), .AuthOK => authEp.ep.settings.delete.?(authEp.ep, r),
.Handled => {}, .Handled => {},
} }
} }
/// here, the auth_endpoint will be passed in /// PATCH: here, the auth_endpoint will be passed in as endpoint.
pub fn patch(e: *SimpleEndpoint, r: zap.SimpleRequest) void { /// Authenticates PATCH requests using the Authenticator.
pub fn patch(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e); const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) { switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => { .AuthFailed => {
if (e.settings.unauthorized) |unauthorized| { if (e.settings.unauthorized) |unauthorized| {
unauthorized(authEp.endpoint, r); unauthorized(authEp.ep, r);
return; return;
} else { } else {
r.setStatus(.unauthorized); r.setStatus(.unauthorized);
@ -186,18 +254,19 @@ pub fn AuthenticatingEndpoint(comptime Authenticator: type) type {
return; return;
} }
}, },
.AuthOK => authEp.endpoint.settings.patch.?(authEp.endpoint, r), .AuthOK => authEp.ep.settings.patch.?(authEp.ep, r),
.Handled => {}, .Handled => {},
} }
} }
/// here, the auth_endpoint will be passed in /// OPTIONS: here, the auth_endpoint will be passed in as endpoint.
pub fn options(e: *SimpleEndpoint, r: zap.SimpleRequest) void { /// Authenticates OPTIONS requests using the Authenticator.
pub fn options(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e); const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) { switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => { .AuthFailed => {
if (e.settings.unauthorized) |unauthorized| { if (e.settings.unauthorized) |unauthorized| {
unauthorized(authEp.endpoint, r); unauthorized(authEp.ep, r);
return; return;
} else { } else {
r.setStatus(.unauthorized); r.setStatus(.unauthorized);
@ -205,7 +274,7 @@ pub fn AuthenticatingEndpoint(comptime Authenticator: type) type {
return; return;
} }
}, },
.AuthOK => authEp.endpoint.settings.put.?(authEp.endpoint, r), .AuthOK => authEp.ep.settings.put.?(authEp.ep, r),
.Handled => {}, .Handled => {},
} }
} }
@ -213,26 +282,44 @@ pub fn AuthenticatingEndpoint(comptime Authenticator: type) type {
} }
pub const EndpointListenerError = error{ pub const EndpointListenerError = error{
/// Since we use .startsWith to check for matching paths, you cannot use
/// endpoint paths that overlap at the beginning. --> When trying to register
/// an endpoint whose path would shadow an already registered one, you will
/// receive this error.
EndpointPathShadowError, EndpointPathShadowError,
}; };
// NOTE: We switch on path.startsWith -> so use endpoints with distinctly /// The listener with ednpoint support
// starting names!! ///
pub const SimpleEndpointListener = struct { /// NOTE: It switches on path.startsWith -> so use endpoints with distinctly starting names!!
pub const EndpointListener = struct {
listener: Listener, listener: Listener,
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
const Self = @This(); const Self = @This();
/// static struct member endpoints /// Internal static struct of member endpoints
var endpoints: std.ArrayList(*SimpleEndpoint) = undefined; var endpoints: std.ArrayList(*Endpoint) = undefined;
var on_request: ?zap.SimpleHttpRequestFn = null;
/// Internal, static request handler callback. Will be set to the optional,
/// user-defined request callback that only gets called if no endpoints match
/// a request.
var on_request: ?zap.HttpRequestFn = null;
/// Initialize a new endpoint listener. Note, if you pass an `on_request`
/// callback in the provided ListenerSettings, this request callback will be
/// called every time a request arrives that no endpoint matches.
pub fn init(a: std.mem.Allocator, l: ListenerSettings) Self { pub fn init(a: std.mem.Allocator, l: ListenerSettings) Self {
endpoints = std.ArrayList(*SimpleEndpoint).init(a); endpoints = std.ArrayList(*Endpoint).init(a);
var ls = l; // take copy of listener settings // take copy of listener settings before modifying the callback field
var ls = l;
// override the settings with our internal, actul callback function
// so that "we" will be called on request
ls.on_request = onRequest; ls.on_request = onRequest;
// store the settings-provided request callback for later use
on_request = l.on_request; on_request = l.on_request;
return .{ return .{
.listener = Listener.init(ls), .listener = Listener.init(ls),
@ -240,16 +327,25 @@ pub const SimpleEndpointListener = struct {
}; };
} }
/// De-init the listener and free its resources.
/// Registered endpoints will not be de-initialized automatically; just removed
/// from the internal map.
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
_ = self; _ = self;
endpoints.deinit(); endpoints.deinit();
} }
/// Call this to start listening. After this, no more endpoints can be
/// registered.
pub fn listen(self: *Self) !void { pub fn listen(self: *Self) !void {
try self.listener.listen(); try self.listener.listen();
} }
pub fn addEndpoint(self: *Self, e: *SimpleEndpoint) !void { /// Register an endpoint with this listener.
/// NOTE: endpoint paths are matched with startsWith -> so use endpoints with distinctly starting names!!
/// If you try to register an endpoint whose path would shadow an already registered one, you will
/// receive an EndpointPathShadowError.
pub fn register(self: *Self, e: *Endpoint) !void {
_ = self; _ = self;
for (endpoints.items) |other| { for (endpoints.items) |other| {
if (std.mem.startsWith( if (std.mem.startsWith(
@ -276,6 +372,7 @@ pub const SimpleEndpointListener = struct {
} }
} }
} }
// if set, call the user-provided default callback
if (on_request) |foo| { if (on_request) |foo| {
foo(r); foo(r);
} }

View file

@ -34,7 +34,7 @@ pub fn checkAuthHeader(scheme: AuthScheme, auth_header: []const u8) bool {
}; };
} }
pub fn extractAuthHeader(scheme: AuthScheme, r: *const zap.SimpleRequest) ?[]const u8 { pub fn extractAuthHeader(scheme: AuthScheme, r: *const zap.Request) ?[]const u8 {
return switch (scheme) { return switch (scheme) {
.Basic => |b| r.getHeader(b.headerFieldStrFio()), .Basic => |b| r.getHeader(b.headerFieldStrFio()),
.Bearer => |b| r.getHeader(b.headerFieldStrFio()), .Bearer => |b| r.getHeader(b.headerFieldStrFio()),
@ -180,7 +180,7 @@ pub fn BasicAuth(comptime Lookup: type, comptime kind: BasicAuthStrategy) type {
.Token68 => return self.authenticateToken68(auth_header), .Token68 => return self.authenticateToken68(auth_header),
} }
} }
pub fn authenticateRequest(self: *Self, r: *const zap.SimpleRequest) AuthResult { pub fn authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
zap.debug("AUTHENTICATE REQUEST\n", .{}); zap.debug("AUTHENTICATE REQUEST\n", .{});
if (extractAuthHeader(.Basic, r)) |auth_header| { if (extractAuthHeader(.Basic, r)) |auth_header| {
zap.debug("Authentication Header found!\n", .{}); zap.debug("Authentication Header found!\n", .{});
@ -234,7 +234,7 @@ pub const BearerAuthSingle = struct {
return if (std.mem.eql(u8, token, self.token)) .AuthOK else .AuthFailed; return if (std.mem.eql(u8, token, self.token)) .AuthOK else .AuthFailed;
} }
pub fn authenticateRequest(self: *Self, r: *const zap.SimpleRequest) AuthResult { pub fn authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
if (extractAuthHeader(.Bearer, r)) |auth_header| { if (extractAuthHeader(.Bearer, r)) |auth_header| {
return self.authenticate(auth_header); return self.authenticate(auth_header);
} }
@ -292,7 +292,7 @@ pub fn BearerAuthMulti(comptime Lookup: type) type {
return if (self.lookup.*.contains(token)) .AuthOK else .AuthFailed; return if (self.lookup.*.contains(token)) .AuthOK else .AuthFailed;
} }
pub fn authenticateRequest(self: *Self, r: *const zap.SimpleRequest) AuthResult { pub fn authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
if (extractAuthHeader(.Bearer, r)) |auth_header| { if (extractAuthHeader(.Bearer, r)) |auth_header| {
return self.authenticate(auth_header); return self.authenticate(auth_header);
} }
@ -405,7 +405,7 @@ pub fn UserPassSessionAuth(comptime Lookup: type, comptime lockedPwLookups: bool
} }
/// Check for session token cookie, remove the token from the valid tokens /// Check for session token cookie, remove the token from the valid tokens
pub fn logout(self: *Self, r: *const zap.SimpleRequest) void { pub fn logout(self: *Self, r: *const zap.Request) void {
// we erase the list of valid tokens server-side // we erase the list of valid tokens server-side
if (r.setCookie(.{ if (r.setCookie(.{
.name = self.settings.cookieName, .name = self.settings.cookieName,
@ -439,7 +439,7 @@ pub fn UserPassSessionAuth(comptime Lookup: type, comptime lockedPwLookups: bool
} }
} }
fn _internal_authenticateRequest(self: *Self, r: *const zap.SimpleRequest) AuthResult { fn _internal_authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
// if we're requesting the login page, let the request through // if we're requesting the login page, let the request through
if (r.path) |p| { if (r.path) |p| {
if (std.mem.startsWith(u8, p, self.settings.loginPage)) { if (std.mem.startsWith(u8, p, self.settings.loginPage)) {
@ -530,7 +530,7 @@ pub fn UserPassSessionAuth(comptime Lookup: type, comptime lockedPwLookups: bool
return .AuthFailed; return .AuthFailed;
} }
pub fn authenticateRequest(self: *Self, r: *const zap.SimpleRequest) AuthResult { pub fn authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
switch (self._internal_authenticateRequest(r)) { switch (self._internal_authenticateRequest(r)) {
.AuthOK => { .AuthOK => {
// username and pass are ok -> created token, set header, caller can continue // username and pass are ok -> created token, set header, caller can continue
@ -550,7 +550,7 @@ pub fn UserPassSessionAuth(comptime Lookup: type, comptime lockedPwLookups: bool
} }
} }
fn redirect(self: *Self, r: *const zap.SimpleRequest) !void { fn redirect(self: *Self, r: *const zap.Request) !void {
try r.redirectTo(self.settings.loginPage, self.settings.redirectCode); try r.redirectTo(self.settings.loginPage, self.settings.redirectCode);
} }

View file

@ -46,7 +46,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.SimpleRequest, *ContextType) bool; pub const RequestFn = *const fn (*Self, zap.Request, *ContextType) 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 {
@ -59,7 +59,7 @@ pub fn Handler(comptime ContextType: anytype) type {
// example for handling request // example for handling 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.SimpleRequest, 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
@ -80,16 +80,16 @@ pub fn Handler(comptime ContextType: anytype) type {
}; };
} }
/// A convenience handler for artibrary zap.SimpleEndpoint /// A convenience handler for artibrary zap.Endpoint
pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anytype) type { pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anytype) type {
return struct { return struct {
handler: HandlerType, handler: HandlerType,
endpoint: *zap.SimpleEndpoint, endpoint: *zap.Endpoint,
breakOnFinish: bool, breakOnFinish: bool,
const Self = @This(); const Self = @This();
pub fn init(endpoint: *zap.SimpleEndpoint, other: ?*HandlerType, breakOnFinish: bool) Self { pub fn init(endpoint: *zap.Endpoint, other: ?*HandlerType, breakOnFinish: bool) Self {
return .{ return .{
.handler = HandlerType.init(onRequest, other), .handler = HandlerType.init(onRequest, other),
.endpoint = endpoint, .endpoint = endpoint,
@ -102,7 +102,7 @@ pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anyt
return &self.handler; return &self.handler;
} }
pub fn onRequest(handler: *HandlerType, r: zap.SimpleRequest, context: *ContextType) bool { pub fn onRequest(handler: *HandlerType, r: zap.Request, context: *ContextType) bool {
var self = @fieldParentPtr(Self, "handler", handler); var self = @fieldParentPtr(Self, "handler", handler);
r.setUserContext(context); r.setUserContext(context);
self.endpoint.onRequest(r); self.endpoint.onRequest(r);
@ -124,8 +124,8 @@ pub const RequestAllocatorFn = *const fn () std.mem.Allocator;
pub fn Listener(comptime ContextType: anytype) type { pub fn Listener(comptime ContextType: anytype) type {
return struct { return struct {
listener: zap.SimpleHttpListener = undefined, listener: zap.HttpListener = undefined,
settings: zap.SimpleHttpListenerSettings, settings: zap.HttpListenerSettings,
// static initial handler // static initial handler
var handler: ?*Handler(ContextType) = undefined; var handler: ?*Handler(ContextType) = undefined;
@ -136,7 +136,7 @@ pub fn Listener(comptime ContextType: anytype) type {
/// initialize the middleware handler /// initialize the middleware handler
/// the passed in settings must have on_request set to null /// the passed in settings must have on_request set to null
pub fn init(settings: zap.SimpleHttpListenerSettings, initial_handler: *Handler(ContextType), request_alloc: ?RequestAllocatorFn) Error!Self { pub fn init(settings: zap.HttpListenerSettings, initial_handler: *Handler(ContextType), request_alloc: ?RequestAllocatorFn) Error!Self {
// override on_request with ourselves // override on_request with ourselves
if (settings.on_request != null) { if (settings.on_request != null) {
return Error.InitOnRequestIsNotNull; return Error.InitOnRequestIsNotNull;
@ -148,7 +148,7 @@ pub fn Listener(comptime ContextType: anytype) type {
.settings = settings, .settings = settings,
}; };
ret.settings.on_request = onRequest; ret.settings.on_request = onRequest;
ret.listener = zap.SimpleHttpListener.init(ret.settings); ret.listener = zap.HttpListener.init(ret.settings);
handler = initial_handler; handler = initial_handler;
return ret; return ret;
} }
@ -161,7 +161,7 @@ pub fn Listener(comptime ContextType: anytype) type {
// but it's actually used obviously. Create your own listener if you // but it's actually used obviously. Create your own listener if you
// want different behavior. // want different behavior.
// Didn't want to make this a callback // Didn't want to make this a callback
pub fn onRequest(r: zap.SimpleRequest) 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 = .{};

View file

@ -106,7 +106,7 @@ const HTTP_RESPONSE: []const u8 =
; ;
var received_response: []const u8 = "null"; var received_response: []const u8 = "null";
fn endpoint_http_get(e: *Endpoints.SimpleEndpoint, r: zap.SimpleRequest) void { fn endpoint_http_get(e: *Endpoints.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;
@ -114,7 +114,7 @@ fn endpoint_http_get(e: *Endpoints.SimpleEndpoint, r: zap.SimpleRequest) void {
zap.fio_stop(); zap.fio_stop();
} }
fn endpoint_http_unauthorized(e: *Endpoints.SimpleEndpoint, r: zap.SimpleRequest) void { fn endpoint_http_unauthorized(e: *Endpoints.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;
@ -181,7 +181,7 @@ test "BearerAuthSingle authenticateRequest OK" {
const token = "ABCDEFG"; const token = "ABCDEFG";
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -194,7 +194,7 @@ test "BearerAuthSingle authenticateRequest OK" {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = Endpoints.SimpleEndpoint.init(.{ var ep = Endpoints.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -209,7 +209,7 @@ test "BearerAuthSingle authenticateRequest OK" {
const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("\n\n*******************************************\n", .{}); // std.debug.print("\n\n*******************************************\n", .{});
@ -234,7 +234,7 @@ test "BearerAuthSingle authenticateRequest test-unauthorized" {
const token = "ABCDEFG"; const token = "ABCDEFG";
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -247,7 +247,7 @@ test "BearerAuthSingle authenticateRequest test-unauthorized" {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = Endpoints.SimpleEndpoint.init(.{ var ep = Endpoints.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -268,7 +268,7 @@ test "BearerAuthSingle authenticateRequest test-unauthorized" {
const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{}); // std.debug.print("Waiting for the following:\n", .{});
@ -291,7 +291,7 @@ test "BearerAuthMulti authenticateRequest OK" {
const token = "ABCDEFG"; const token = "ABCDEFG";
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -304,7 +304,7 @@ test "BearerAuthMulti authenticateRequest OK" {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = Endpoints.SimpleEndpoint.init(.{ var ep = Endpoints.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -319,7 +319,7 @@ test "BearerAuthMulti authenticateRequest OK" {
const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{}); // std.debug.print("Waiting for the following:\n", .{});
@ -342,7 +342,7 @@ test "BearerAuthMulti authenticateRequest test-unauthorized" {
const token = "invalid"; const token = "invalid";
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -355,7 +355,7 @@ test "BearerAuthMulti authenticateRequest test-unauthorized" {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = Endpoints.SimpleEndpoint.init(.{ var ep = Endpoints.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -370,7 +370,7 @@ test "BearerAuthMulti authenticateRequest test-unauthorized" {
const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{}); // std.debug.print("Waiting for the following:\n", .{});
@ -393,7 +393,7 @@ test "BasicAuth Token68 authenticateRequest" {
const token = "QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; const token = "QWxhZGRpbjpvcGVuIHNlc2FtZQ==";
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -406,7 +406,7 @@ test "BasicAuth Token68 authenticateRequest" {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = Endpoints.SimpleEndpoint.init(.{ var ep = Endpoints.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -426,7 +426,7 @@ test "BasicAuth Token68 authenticateRequest" {
const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{}); // std.debug.print("Waiting for the following:\n", .{});
@ -449,7 +449,7 @@ test "BasicAuth Token68 authenticateRequest test-unauthorized" {
const token = "QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; const token = "QWxhZGRpbjpvcGVuIHNlc2FtZQ==";
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -462,7 +462,7 @@ test "BasicAuth Token68 authenticateRequest test-unauthorized" {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = Endpoints.SimpleEndpoint.init(.{ var ep = Endpoints.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -482,7 +482,7 @@ test "BasicAuth Token68 authenticateRequest test-unauthorized" {
const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{}); // std.debug.print("Waiting for the following:\n", .{});
@ -504,7 +504,7 @@ test "BasicAuth UserPass authenticateRequest" {
const a = std.testing.allocator; const a = std.testing.allocator;
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -517,7 +517,7 @@ test "BasicAuth UserPass authenticateRequest" {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = Endpoints.SimpleEndpoint.init(.{ var ep = Endpoints.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -548,7 +548,7 @@ test "BasicAuth UserPass authenticateRequest" {
const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{}); // std.debug.print("Waiting for the following:\n", .{});
@ -570,7 +570,7 @@ test "BasicAuth UserPass authenticateRequest test-unauthorized" {
const a = std.testing.allocator; const a = std.testing.allocator;
// setup listener // setup listener
var listener = zap.SimpleEndpointListener.init( var listener = zap.EndpointListener.init(
a, a,
.{ .{
.port = 3000, .port = 3000,
@ -583,7 +583,7 @@ test "BasicAuth UserPass authenticateRequest test-unauthorized" {
defer listener.deinit(); defer listener.deinit();
// create mini endpoint // create mini endpoint
var ep = Endpoints.SimpleEndpoint.init(.{ var ep = Endpoints.Endpoint.init(.{
.path = "/test", .path = "/test",
.get = endpoint_http_get, .get = endpoint_http_get,
.unauthorized = endpoint_http_unauthorized, .unauthorized = endpoint_http_unauthorized,
@ -615,7 +615,7 @@ test "BasicAuth UserPass authenticateRequest test-unauthorized" {
const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator); const BearerAuthEndpoint = Endpoints.AuthenticatingEndpoint(Authenticator);
var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator);
try listener.addEndpoint(auth_ep.getEndpoint()); try listener.register(auth_ep.endpoint());
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{}); // std.debug.print("Waiting for the following:\n", .{});

View file

@ -34,7 +34,7 @@ test "http parameters" {
var params: ?zap.HttpParamKVList = null; var params: ?zap.HttpParamKVList = null;
var paramOneStr: ?zap.FreeOrNot = null; var paramOneStr: ?zap.FreeOrNot = null;
pub fn on_request(r: zap.SimpleRequest) 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();
@ -55,7 +55,7 @@ test "http parameters" {
Handler.alloc = allocator; Handler.alloc = allocator;
// setup listener // setup listener
var listener = zap.SimpleHttpListener.init( var listener = zap.HttpListener.init(
.{ .{
.port = 3001, .port = 3001,
.on_request = Handler.on_request, .on_request = Handler.on_request,

View file

@ -28,7 +28,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.SimpleRequest) 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;
} }
@ -36,7 +36,7 @@ test "send file" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
// setup listener // setup listener
var listener = zap.SimpleHttpListener.init( var listener = zap.HttpListener.init(
.{ .{
.port = 3002, .port = 3002,
.on_request = on_request, .on_request = on_request,

View file

@ -76,7 +76,7 @@ pub const ContentType = enum {
JSON, JSON,
}; };
pub const SimpleRequest = struct { pub const Request = struct {
path: ?[]const u8, path: ?[]const u8,
query: ?[]const u8, query: ?[]const u8,
body: ?[]const u8, body: ?[]const u8,
@ -90,7 +90,7 @@ pub const SimpleRequest = struct {
/// NEVER touch this field!!!! /// NEVER touch this field!!!!
/// use markAsFinished() and isFinished() instead /// use markAsFinished() and isFinished() instead
/// this is a hack: the listener will put a pointer to this into the udata /// this is a hack: the listener will put a pointer to this into the udata
/// field of `h`. So copies of the SimpleRequest will all have way to the /// field of `h`. So copies of the Request will all have way to the
/// same instance of this field. /// same instance of this field.
_is_finished_request_global: bool, _is_finished_request_global: bool,
/// NEVER touch this field!!!! /// NEVER touch this field!!!!
@ -156,7 +156,7 @@ pub const SimpleRequest = struct {
*anyopaque, *anyopaque,
@ptrFromInt(@intFromPtr(body.ptr)), @ptrFromInt(@intFromPtr(body.ptr)),
), body.len); ), body.len);
debug("SimpleRequest.sendBody(): ret = {}\n", .{ret}); debug("Request.sendBody(): ret = {}\n", .{ret});
if (ret == -1) return error.HttpSendBody; if (ret == -1) return error.HttpSendBody;
self.markAsFinished(true); self.markAsFinished(true);
} }
@ -744,25 +744,26 @@ pub const CookieArgs = struct {
http_only: bool = true, http_only: bool = true,
}; };
pub const HttpRequestFn = *const fn (r: [*c]fio.http_s) callconv(.C) void; pub const FioHttpRequestFn = *const fn (r: [*c]fio.http_s) callconv(.C) void;
pub const SimpleHttpRequestFn = *const fn (SimpleRequest) void;
pub const HttpRequestFn = *const fn (Request) void;
/// websocket connection upgrade /// websocket connection upgrade
/// fn(request, targetstring) /// fn(request, targetstring)
pub const SimpleHttpUpgradeFn = *const fn (r: SimpleRequest, target_protocol: []const u8) void; pub const HttpUpgradeFn = *const fn (r: Request, target_protocol: []const u8) void;
/// http finish, called when zap finishes. You get your udata back in the /// http finish, called when zap finishes. You get your udata back in the
/// struct. /// struct.
pub const SimpleHttpFinishSettings = [*c]fio.struct_http_settings_s; pub const HttpFinishSettings = [*c]fio.struct_http_settings_s;
pub const SimpleHttpFinishFn = *const fn (SimpleHttpFinishSettings) void; pub const HttpFinishFn = *const fn (HttpFinishSettings) void;
pub const SimpleHttpListenerSettings = struct { pub const HttpListenerSettings = struct {
port: usize, port: usize,
interface: [*c]const u8 = null, interface: [*c]const u8 = null,
on_request: ?SimpleHttpRequestFn, on_request: ?HttpRequestFn,
on_response: ?SimpleHttpRequestFn = null, on_response: ?HttpRequestFn = null,
on_upgrade: ?SimpleHttpUpgradeFn = null, on_upgrade: ?HttpUpgradeFn = null,
on_finish: ?SimpleHttpFinishFn = null, on_finish: ?HttpFinishFn = null,
// provide any pointer in there for "user data". it will be passed pack in // provide any pointer in there for "user data". it will be passed pack in
// on_finish()'s copy of the struct_http_settings_s // on_finish()'s copy of the struct_http_settings_s
udata: ?*anyopaque = null, udata: ?*anyopaque = null,
@ -776,13 +777,13 @@ pub const SimpleHttpListenerSettings = struct {
tls: ?Tls = null, tls: ?Tls = null,
}; };
pub const SimpleHttpListener = struct { pub const HttpListener = struct {
settings: SimpleHttpListenerSettings, settings: HttpListenerSettings,
const Self = @This(); const Self = @This();
var the_one_and_only_listener: ?*SimpleHttpListener = null; var the_one_and_only_listener: ?*HttpListener = null;
pub fn init(settings: SimpleHttpListenerSettings) Self { pub fn init(settings: HttpListenerSettings) Self {
std.debug.assert(settings.on_request != null); std.debug.assert(settings.on_request != null);
return .{ return .{
.settings = settings, .settings = settings,
@ -792,10 +793,10 @@ pub const SimpleHttpListener = struct {
// on_upgrade: ?*const fn ([*c]fio.http_s, [*c]u8, usize) callconv(.C) void = null, // on_upgrade: ?*const fn ([*c]fio.http_s, [*c]u8, usize) callconv(.C) void = null,
// on_finish: ?*const fn ([*c]fio.struct_http_settings_s) callconv(.C) void = null, // on_finish: ?*const fn ([*c]fio.struct_http_settings_s) callconv(.C) void = null,
// we could make it dynamic by passing a SimpleHttpListener via udata // we could make it dynamic by passing a HttpListener via udata
pub fn theOneAndOnlyRequestCallBack(r: [*c]fio.http_s) callconv(.C) void { pub fn theOneAndOnlyRequestCallBack(r: [*c]fio.http_s) callconv(.C) void {
if (the_one_and_only_listener) |l| { if (the_one_and_only_listener) |l| {
var req: SimpleRequest = .{ var req: Request = .{
.path = util.fio2str(r.*.path), .path = util.fio2str(r.*.path),
.query = util.fio2str(r.*.query), .query = util.fio2str(r.*.query),
.body = util.fio2str(r.*.body), .body = util.fio2str(r.*.body),
@ -806,7 +807,7 @@ pub const SimpleHttpListener = struct {
}; };
req._is_finished = &req._is_finished_request_global; req._is_finished = &req._is_finished_request_global;
var user_context: SimpleRequest.UserContext = .{}; var user_context: Request.UserContext = .{};
req._user_context = &user_context; req._user_context = &user_context;
req.markAsFinished(false); req.markAsFinished(false);
@ -820,7 +821,7 @@ pub const SimpleHttpListener = struct {
pub fn theOneAndOnlyResponseCallBack(r: [*c]fio.http_s) callconv(.C) void { pub fn theOneAndOnlyResponseCallBack(r: [*c]fio.http_s) callconv(.C) void {
if (the_one_and_only_listener) |l| { if (the_one_and_only_listener) |l| {
var req: SimpleRequest = .{ var req: Request = .{
.path = util.fio2str(r.*.path), .path = util.fio2str(r.*.path),
.query = util.fio2str(r.*.query), .query = util.fio2str(r.*.query),
.body = util.fio2str(r.*.body), .body = util.fio2str(r.*.body),
@ -831,7 +832,7 @@ pub const SimpleHttpListener = struct {
}; };
req._is_finished = &req._is_finished_request_global; req._is_finished = &req._is_finished_request_global;
var user_context: SimpleRequest.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);
@ -840,7 +841,7 @@ pub const SimpleHttpListener = struct {
pub fn theOneAndOnlyUpgradeCallBack(r: [*c]fio.http_s, target: [*c]u8, target_len: usize) callconv(.C) void { pub fn theOneAndOnlyUpgradeCallBack(r: [*c]fio.http_s, target: [*c]u8, target_len: usize) callconv(.C) void {
if (the_one_and_only_listener) |l| { if (the_one_and_only_listener) |l| {
var req: SimpleRequest = .{ var req: Request = .{
.path = util.fio2str(r.*.path), .path = util.fio2str(r.*.path),
.query = util.fio2str(r.*.query), .query = util.fio2str(r.*.query),
.body = util.fio2str(r.*.body), .body = util.fio2str(r.*.body),
@ -852,7 +853,7 @@ pub const SimpleHttpListener = struct {
const zigtarget: []u8 = target[0..target_len]; const zigtarget: []u8 = target[0..target_len];
req._is_finished = &req._is_finished_request_global; req._is_finished = &req._is_finished_request_global;
var user_context: SimpleRequest.UserContext = .{}; var user_context: Request.UserContext = .{};
req._user_context = &user_context; req._user_context = &user_context;
l.settings.on_upgrade.?(req, zigtarget); l.settings.on_upgrade.?(req, zigtarget);
@ -870,7 +871,7 @@ pub const SimpleHttpListener = struct {
var pfolder_len: usize = 0; var pfolder_len: usize = 0;
if (self.settings.public_folder) |pf| { if (self.settings.public_folder) |pf| {
debug("SimpleHttpListener.listen(): public folder is {s}\n", .{pf}); debug("HttpListener.listen(): public folder is {s}\n", .{pf});
pfolder_len = pf.len; pfolder_len = pf.len;
pfolder = pf.ptr; pfolder = pf.ptr;
} }
@ -916,7 +917,7 @@ pub const SimpleHttpListener = struct {
// set ourselves up to handle requests: // set ourselves up to handle requests:
// TODO: do we mind the race condition? // TODO: do we mind the race condition?
// the SimpleHttpRequestFn will check if this is null and not process // the HttpRequestFn will check if this is null and not process
// the request if it isn't set. hence, if started under full load, the // the request if it isn't set. hence, if started under full load, the
// first request(s) might not be serviced, as long as it takes from // first request(s) might not be serviced, as long as it takes from
// fio.http_listen() to here // fio.http_listen() to here
@ -928,10 +929,10 @@ pub const SimpleHttpListener = struct {
// lower level listening // lower level listening
// //
pub const ListenSettings = struct { pub const ListenSettings = struct {
on_request: ?*const fn ([*c]fio.http_s) callconv(.C) void = null, on_request: ?FioHttpRequestFn = null,
on_upgrade: ?*const fn ([*c]fio.http_s, [*c]u8, usize) callconv(.C) void = null, on_upgrade: ?FioHttpRequestFn = null,
on_response: ?*const fn ([*c]fio.http_s) callconv(.C) void = null, on_response: ?FioHttpRequestFn = null,
on_finish: ?*const fn ([*c]fio.struct_http_settings_s) callconv(.C) void = null, on_finish: ?FioHttpRequestFn = null,
public_folder: ?[]const u8 = null, public_folder: ?[]const u8 = null,
max_header_size: usize = 32 * 1024, max_header_size: usize = 32 * 1024,
max_body_size: usize = 50 * 1024 * 1024, max_body_size: usize = 50 * 1024 * 1024,

View file

@ -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.SimpleRequest) 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;
} }
@ -26,7 +26,7 @@ pub fn main() !void {
} }
} }
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = port, .port = port,
.on_request = on_request, .on_request = on_request,
.public_folder = docs_dir, .public_folder = docs_dir,

View file

@ -1,12 +1,12 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
fn on_request_minimal(r: zap.SimpleRequest) void { fn on_request_minimal(r: zap.Request) void {
r.sendBody("Hello from ZAP!!!") catch return; r.sendBody("Hello from ZAP!!!") catch return;
} }
pub fn main() !void { pub fn main() !void {
var listener = zap.SimpleHttpListener.init(.{ var listener = zap.HttpListener.init(.{
.port = 3000, .port = 3000,
.on_request = on_request_minimal, .on_request = on_request_minimal,
.log = false, .log = false,