mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 23:24:09 +00:00
endpoint simplification
This commit is contained in:
parent
3b06a336ef
commit
8e80eecc3e
4 changed files with 121 additions and 230 deletions
|
@ -41,8 +41,8 @@ pub fn main() !void {
|
||||||
var stopEp = StopEndpoint.init("/stop");
|
var stopEp = StopEndpoint.init("/stop");
|
||||||
|
|
||||||
// register endpoints with the listener
|
// register endpoints with the listener
|
||||||
try listener.register(userWeb.endpoint());
|
try listener.register(&userWeb);
|
||||||
try listener.register(stopEp.endpoint());
|
try listener.register(&stopEp);
|
||||||
|
|
||||||
// fake some users
|
// fake some users
|
||||||
var uid: usize = undefined;
|
var uid: usize = undefined;
|
||||||
|
|
|
@ -5,25 +5,22 @@ 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();
|
||||||
|
|
||||||
ep: zap.Endpoint = undefined,
|
|
||||||
|
|
||||||
pub fn init(
|
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
) Self {
|
|
||||||
|
pub fn init(path: []const u8) Self {
|
||||||
return .{
|
return .{
|
||||||
.ep = zap.Endpoint.init(.{
|
|
||||||
.path = path,
|
.path = path,
|
||||||
.get = get,
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn endpoint(self: *Self) *zap.Endpoint {
|
pub fn get(e: *Self, r: zap.Request) void {
|
||||||
return &self.ep;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(e: *zap.Endpoint, r: zap.Request) void {
|
|
||||||
_ = e;
|
_ = e;
|
||||||
_ = r;
|
_ = r;
|
||||||
zap.stop();
|
zap.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn post(_: *Self, _: zap.Request) void {}
|
||||||
|
pub fn put(_: *Self, _: zap.Request) void {}
|
||||||
|
pub fn delete(_: *Self, _: zap.Request) void {}
|
||||||
|
pub fn patch(_: *Self, _: zap.Request) void {}
|
||||||
|
pub fn options(_: *Self, _: zap.Request) void {}
|
||||||
|
|
|
@ -8,9 +8,10 @@ const User = Users.User;
|
||||||
pub const Self = @This();
|
pub const Self = @This();
|
||||||
|
|
||||||
alloc: std.mem.Allocator = undefined,
|
alloc: std.mem.Allocator = undefined,
|
||||||
ep: zap.Endpoint = undefined,
|
|
||||||
_users: Users = undefined,
|
_users: Users = undefined,
|
||||||
|
|
||||||
|
path: []const u8,
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
a: std.mem.Allocator,
|
a: std.mem.Allocator,
|
||||||
user_path: []const u8,
|
user_path: []const u8,
|
||||||
|
@ -18,15 +19,7 @@ pub fn init(
|
||||||
return .{
|
return .{
|
||||||
.alloc = a,
|
.alloc = a,
|
||||||
._users = Users.init(a),
|
._users = Users.init(a),
|
||||||
.ep = zap.Endpoint.init(.{
|
|
||||||
.path = user_path,
|
.path = user_path,
|
||||||
.get = getUser,
|
|
||||||
.post = postUser,
|
|
||||||
.put = putUser,
|
|
||||||
.patch = putUser,
|
|
||||||
.delete = deleteUser,
|
|
||||||
.options = optionsUser,
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,27 +31,22 @@ pub fn users(self: *Self) *Users {
|
||||||
return &self._users;
|
return &self._users;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn endpoint(self: *Self) *zap.Endpoint {
|
|
||||||
return &self.ep;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn userIdFromPath(self: *Self, path: []const u8) ?usize {
|
fn userIdFromPath(self: *Self, path: []const u8) ?usize {
|
||||||
if (path.len >= self.ep.settings.path.len + 2) {
|
if (path.len >= self.path.len + 2) {
|
||||||
if (path[self.ep.settings.path.len] != '/') {
|
if (path[self.path.len] != '/') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const idstr = path[self.ep.settings.path.len + 1 ..];
|
const idstr = path[self.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.Endpoint, r: zap.Request) void {
|
pub fn put(_: *Self, _: zap.Request) void {}
|
||||||
const self: *Self = @fieldParentPtr("ep", e);
|
pub fn get(self: *Self, r: zap.Request) void {
|
||||||
|
|
||||||
if (r.path) |path| {
|
if (r.path) |path| {
|
||||||
// /users
|
// /users
|
||||||
if (path.len == e.settings.path.len) {
|
if (path.len == self.path.len) {
|
||||||
return self.listUsers(r);
|
return self.listUsers(r);
|
||||||
}
|
}
|
||||||
var jsonbuf: [256]u8 = undefined;
|
var jsonbuf: [256]u8 = undefined;
|
||||||
|
@ -81,8 +69,7 @@ fn listUsers(self: *Self, r: zap.Request) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn postUser(e: *zap.Endpoint, r: zap.Request) void {
|
pub fn post(self: *Self, r: zap.Request) void {
|
||||||
const self: *Self = @fieldParentPtr("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| {
|
||||||
|
@ -100,8 +87,7 @@ fn postUser(e: *zap.Endpoint, r: zap.Request) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn putUser(e: *zap.Endpoint, r: zap.Request) void {
|
pub fn patch(self: *Self, r: zap.Request) void {
|
||||||
const self: *Self = @fieldParentPtr("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)) |_| {
|
||||||
|
@ -126,8 +112,7 @@ fn putUser(e: *zap.Endpoint, r: zap.Request) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deleteUser(e: *zap.Endpoint, r: zap.Request) void {
|
pub fn delete(self: *Self, r: zap.Request) void {
|
||||||
const self: *Self = @fieldParentPtr("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;
|
||||||
|
@ -144,8 +129,7 @@ fn deleteUser(e: *zap.Endpoint, r: zap.Request) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn optionsUser(e: *zap.Endpoint, r: zap.Request) void {
|
pub fn options(_: *Self, r: zap.Request) void {
|
||||||
_ = 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;
|
||||||
r.setStatus(zap.StatusCode.no_content);
|
r.setStatus(zap.StatusCode.no_content);
|
||||||
|
|
268
src/endpoint.zig
268
src/endpoint.zig
|
@ -9,222 +9,130 @@ const Request = zap.Request;
|
||||||
const ListenerSettings = zap.HttpListenerSettings;
|
const ListenerSettings = zap.HttpListenerSettings;
|
||||||
const HttpListener = zap.HttpListener;
|
const HttpListener = zap.HttpListener;
|
||||||
|
|
||||||
/// Type of the request function callbacks.
|
const EndpointWrapper = struct {
|
||||||
pub const RequestFn = *const fn (self: *Endpoint, r: Request) void;
|
pub const Wrapper = struct {
|
||||||
|
call: *const fn (*Wrapper, zap.Request) void = undefined,
|
||||||
/// Settings to initialize an Endpoint
|
|
||||||
pub const Settings = struct {
|
|
||||||
/// path / slug of the endpoint
|
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
/// callback to GET request handler
|
destroy: *const fn (allocator: std.mem.Allocator, *Wrapper) void = undefined,
|
||||||
get: ?RequestFn = null,
|
|
||||||
/// callback to POST request handler
|
|
||||||
post: ?RequestFn = null,
|
|
||||||
/// callback to PUT request handler
|
|
||||||
put: ?RequestFn = null,
|
|
||||||
/// callback to DELETE request handler
|
|
||||||
delete: ?RequestFn = null,
|
|
||||||
/// callback to PATCH request handler
|
|
||||||
patch: ?RequestFn = null,
|
|
||||||
/// callback to OPTIONS request handler
|
|
||||||
options: ?RequestFn = null,
|
|
||||||
/// Only applicable to Authenticating Endpoint: handler for unauthorized requests
|
|
||||||
unauthorized: ?RequestFn = null,
|
|
||||||
};
|
};
|
||||||
|
pub fn Wrap(T: type) type {
|
||||||
|
return struct {
|
||||||
|
wrapped: *T,
|
||||||
|
wrapper: Wrapper,
|
||||||
|
|
||||||
settings: Settings,
|
const Self = @This();
|
||||||
|
|
||||||
/// Initialize the endpoint.
|
pub fn unwrap(wrapper: *Wrapper) *Self {
|
||||||
/// Set only the callbacks you need. Requests of HTTP methods without a
|
const self: *Self = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
||||||
/// provided callback will be ignored.
|
return self;
|
||||||
pub fn init(s: Settings) Endpoint {
|
|
||||||
return .{
|
|
||||||
.settings = .{
|
|
||||||
.path = s.path,
|
|
||||||
.get = s.get orelse &nop,
|
|
||||||
.post = s.post orelse &nop,
|
|
||||||
.put = s.put orelse &nop,
|
|
||||||
.delete = s.delete orelse &nop,
|
|
||||||
.patch = s.patch orelse &nop,
|
|
||||||
.options = s.options orelse &nop,
|
|
||||||
.unauthorized = s.unauthorized orelse &nop,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no operation. Dummy handler function for ignoring unset request types.
|
pub fn destroy(allocator: std.mem.Allocator, wrapper: *Wrapper) void {
|
||||||
fn nop(self: *Endpoint, r: Request) void {
|
const self: *Self = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
||||||
_ = self;
|
allocator.destroy(self);
|
||||||
_ = r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The global request handler for this Endpoint, called by the listener.
|
pub fn onRequestWrapped(wrapper: *Wrapper, r: zap.Request) void {
|
||||||
pub fn onRequest(self: *Endpoint, r: zap.Request) void {
|
var self: *Self = Self.unwrap(wrapper);
|
||||||
|
self.onRequest(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn onRequest(self: *Self, r: zap.Request) void {
|
||||||
switch (r.methodAsEnum()) {
|
switch (r.methodAsEnum()) {
|
||||||
.GET => self.settings.get.?(self, r),
|
.GET => return self.wrapped.*.get(r),
|
||||||
.POST => self.settings.post.?(self, r),
|
.POST => return self.wrapped.*.post(r),
|
||||||
.PUT => self.settings.put.?(self, r),
|
.PUT => return self.wrapped.*.put(r),
|
||||||
.DELETE => self.settings.delete.?(self, r),
|
.DELETE => return self.wrapped.*.delete(r),
|
||||||
.PATCH => self.settings.patch.?(self, r),
|
.PATCH => return self.wrapped.*.patch(r),
|
||||||
.OPTIONS => self.settings.options.?(self, r),
|
.OPTIONS => return self.wrapped.*.options(r),
|
||||||
else => return,
|
else => {},
|
||||||
}
|
}
|
||||||
|
// TODO: log that req fn is not implemented on this EP
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(T: type, value: *T) EndpointWrapper.Wrap(T) {
|
||||||
|
var ret: EndpointWrapper.Wrap(T) = .{
|
||||||
|
.wrapped = value,
|
||||||
|
.wrapper = .{ .path = value.path },
|
||||||
|
};
|
||||||
|
ret.wrapper.call = EndpointWrapper.Wrap(T).onRequestWrapped;
|
||||||
|
ret.wrapper.destroy = EndpointWrapper.Wrap(T).destroy;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Wrap an endpoint with an Authenticator -> new Endpoint of type Endpoint
|
/// Wrap an endpoint with an Authenticator -> new Endpoint of type Endpoint
|
||||||
/// is available via the `endpoint()` function.
|
/// is available via the `endpoint()` function.
|
||||||
pub fn Authenticating(comptime Authenticator: type) type {
|
pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
authenticator: *Authenticator,
|
authenticator: *Authenticator,
|
||||||
ep: *Endpoint,
|
ep: *EndpointType,
|
||||||
auth_endpoint: Endpoint,
|
path: []const u8,
|
||||||
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
|
||||||
/// you want to wrap, and the Authenticator that takes care of authenticating
|
/// you want to wrap, and the Authenticator that takes care of authenticating
|
||||||
/// requests.
|
/// requests.
|
||||||
pub fn init(e: *Endpoint, authenticator: *Authenticator) Self {
|
pub fn init(e: *EndpointType, authenticator: *Authenticator) Self {
|
||||||
return .{
|
return .{
|
||||||
.authenticator = authenticator,
|
.authenticator = authenticator,
|
||||||
.ep = e,
|
.ep = e,
|
||||||
.auth_endpoint = Endpoint.init(.{
|
.path = e.path,
|
||||||
.path = e.settings.path,
|
|
||||||
// we override only the set ones. the other ones
|
|
||||||
// are set to null anyway -> will be nopped out
|
|
||||||
.get = if (e.settings.get != null) get else null,
|
|
||||||
.post = if (e.settings.post != null) post else null,
|
|
||||||
.put = if (e.settings.put != null) put else null,
|
|
||||||
.delete = if (e.settings.delete != null) delete else null,
|
|
||||||
.patch = if (e.settings.patch != null) patch else null,
|
|
||||||
.options = if (e.settings.options != null) options else null,
|
|
||||||
.unauthorized = e.settings.unauthorized,
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
|
||||||
/// access to all of this via fieldParentPtr
|
|
||||||
pub fn endpoint(self: *Self) *Endpoint {
|
|
||||||
return &self.auth_endpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// GET: here, the auth_endpoint will be passed in as endpoint.
|
|
||||||
/// Authenticates GET requests using the Authenticator.
|
/// Authenticates GET requests using the Authenticator.
|
||||||
pub fn get(e: *Endpoint, r: zap.Request) void {
|
pub fn get(self: *Self, r: zap.Request) void {
|
||||||
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
|
switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
switch (authEp.authenticator.authenticateRequest(&r)) {
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthFailed => {
|
.AuthOK => self.ep.*.get(r),
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
|
||||||
unauthorized(authEp.ep, r);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
r.setStatus(.unauthorized);
|
|
||||||
r.sendBody("UNAUTHORIZED") catch return;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.AuthOK => authEp.ep.settings.get.?(authEp.ep, r),
|
|
||||||
.Handled => {},
|
.Handled => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// POST: here, the auth_endpoint will be passed in as endpoint.
|
|
||||||
/// Authenticates POST requests using the Authenticator.
|
/// Authenticates POST requests using the Authenticator.
|
||||||
pub fn post(e: *Endpoint, r: zap.Request) void {
|
pub fn post(self: *Self, r: zap.Request) void {
|
||||||
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
|
switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
switch (authEp.authenticator.authenticateRequest(&r)) {
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthFailed => {
|
.AuthOK => self.ep.*.post(r),
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
|
||||||
unauthorized(authEp.ep, r);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
r.setStatus(.unauthorized);
|
|
||||||
r.sendBody("UNAUTHORIZED") catch return;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.AuthOK => authEp.ep.settings.post.?(authEp.ep, r),
|
|
||||||
.Handled => {},
|
.Handled => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PUT: here, the auth_endpoint will be passed in as endpoint.
|
|
||||||
/// Authenticates PUT requests using the Authenticator.
|
/// Authenticates PUT requests using the Authenticator.
|
||||||
pub fn put(e: *Endpoint, r: zap.Request) void {
|
pub fn put(self: *Self, r: zap.Request) void {
|
||||||
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
|
switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
switch (authEp.authenticator.authenticateRequest(&r)) {
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthFailed => {
|
.AuthOK => self.ep.*.put(r),
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
|
||||||
unauthorized(authEp.ep, r);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
r.setStatus(.unauthorized);
|
|
||||||
r.sendBody("UNAUTHORIZED") catch return;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.AuthOK => authEp.ep.settings.put.?(authEp.ep, r),
|
|
||||||
.Handled => {},
|
.Handled => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DELETE: here, the auth_endpoint will be passed in as endpoint.
|
|
||||||
/// Authenticates DELETE requests using the Authenticator.
|
/// Authenticates DELETE requests using the Authenticator.
|
||||||
pub fn delete(e: *Endpoint, r: zap.Request) void {
|
pub fn delete(self: *Self, r: zap.Request) void {
|
||||||
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
|
switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
switch (authEp.authenticator.authenticateRequest(&r)) {
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthFailed => {
|
.AuthOK => self.ep.*.delete(r),
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
|
||||||
unauthorized(authEp.ep, r);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
r.setStatus(.unauthorized);
|
|
||||||
r.sendBody("UNAUTHORIZED") catch return;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.AuthOK => authEp.ep.settings.delete.?(authEp.ep, r),
|
|
||||||
.Handled => {},
|
.Handled => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PATCH: here, the auth_endpoint will be passed in as endpoint.
|
|
||||||
/// Authenticates PATCH requests using the Authenticator.
|
/// Authenticates PATCH requests using the Authenticator.
|
||||||
pub fn patch(e: *Endpoint, r: zap.Request) void {
|
pub fn patch(self: *Self, r: zap.Request) void {
|
||||||
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
|
switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
switch (authEp.authenticator.authenticateRequest(&r)) {
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthFailed => {
|
.AuthOK => self.ep.*.patch(r),
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
|
||||||
unauthorized(authEp.ep, r);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
r.setStatus(.unauthorized);
|
|
||||||
r.sendBody("UNAUTHORIZED") catch return;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.AuthOK => authEp.ep.settings.patch.?(authEp.ep, r),
|
|
||||||
.Handled => {},
|
.Handled => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OPTIONS: here, the auth_endpoint will be passed in as endpoint.
|
|
||||||
/// Authenticates OPTIONS requests using the Authenticator.
|
/// Authenticates OPTIONS requests using the Authenticator.
|
||||||
pub fn options(e: *Endpoint, r: zap.Request) void {
|
pub fn options(self: *Self, r: zap.Request) void {
|
||||||
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
|
switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
switch (authEp.authenticator.authenticateRequest(&r)) {
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthFailed => {
|
.AuthOK => self.ep.*.put(r),
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
|
||||||
unauthorized(authEp.ep, r);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
r.setStatus(.unauthorized);
|
|
||||||
r.sendBody("UNAUTHORIZED") catch return;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.AuthOK => authEp.ep.settings.put.?(authEp.ep, r),
|
|
||||||
.Handled => {},
|
.Handled => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +157,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.ArrayList(*Endpoint) = undefined;
|
var endpoints: std.ArrayListUnmanaged(*EndpointWrapper.Wrapper) = .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
|
||||||
|
@ -260,12 +168,10 @@ pub const Listener = struct {
|
||||||
/// callback in the provided ListenerSettings, this request callback will be
|
/// callback in the provided ListenerSettings, this request callback will be
|
||||||
/// called every time a request arrives that no endpoint matches.
|
/// 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(*Endpoint).init(a);
|
|
||||||
|
|
||||||
// take copy of listener settings before modifying the callback field
|
// take copy of listener settings before modifying the callback field
|
||||||
var ls = l;
|
var ls = l;
|
||||||
|
|
||||||
// override the settings with our internal, actul callback function
|
// override the settings with our internal, actual callback function
|
||||||
// so that "we" will be called on request
|
// so that "we" will be called on request
|
||||||
ls.on_request = Listener.onRequest;
|
ls.on_request = Listener.onRequest;
|
||||||
|
|
||||||
|
@ -281,8 +187,10 @@ pub const Listener = struct {
|
||||||
/// Registered endpoints will not be de-initialized automatically; just removed
|
/// Registered endpoints will not be de-initialized automatically; just removed
|
||||||
/// from the internal map.
|
/// from the internal map.
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
_ = self;
|
for (endpoints.items) |endpoint_wrapper| {
|
||||||
endpoints.deinit();
|
endpoint_wrapper.destroy(self.allocator, endpoint_wrapper);
|
||||||
|
}
|
||||||
|
endpoints.deinit(self.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call this to start listening. After this, no more endpoints can be
|
/// Call this to start listening. After this, no more endpoints can be
|
||||||
|
@ -295,29 +203,31 @@ pub const Listener = struct {
|
||||||
/// NOTE: endpoint paths are matched with startsWith -> so use endpoints with distinctly starting names!!
|
/// 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
|
/// If you try to register an endpoint whose path would shadow an already registered one, you will
|
||||||
/// receive an EndpointPathShadowError.
|
/// receive an EndpointPathShadowError.
|
||||||
pub fn register(self: *Self, e: *Endpoint) !void {
|
pub fn register(self: *Self, e: anytype) !void {
|
||||||
_ = self;
|
|
||||||
for (endpoints.items) |other| {
|
for (endpoints.items) |other| {
|
||||||
if (std.mem.startsWith(
|
if (std.mem.startsWith(
|
||||||
u8,
|
u8,
|
||||||
other.settings.path,
|
other.path,
|
||||||
e.settings.path,
|
e.path,
|
||||||
) or std.mem.startsWith(
|
) or std.mem.startsWith(
|
||||||
u8,
|
u8,
|
||||||
e.settings.path,
|
e.path,
|
||||||
other.settings.path,
|
other.path,
|
||||||
)) {
|
)) {
|
||||||
return EndpointListenerError.EndpointPathShadowError;
|
return EndpointListenerError.EndpointPathShadowError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try endpoints.append(e);
|
const EndpointType = @typeInfo(@TypeOf(e)).pointer.child;
|
||||||
|
const wrapper = try self.allocator.create(EndpointWrapper.Wrap(EndpointType));
|
||||||
|
wrapper.* = EndpointWrapper.init(EndpointType, e);
|
||||||
|
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) |e| {
|
for (endpoints.items) |wrapper| {
|
||||||
if (std.mem.startsWith(u8, p, e.settings.path)) {
|
if (std.mem.startsWith(u8, p, wrapper.path)) {
|
||||||
e.onRequest(r);
|
wrapper.call(wrapper, r);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue