mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 23:24:09 +00:00
removed Self and @This() as much as possible
This commit is contained in:
parent
9eb254d5f8
commit
3aaa7fcc24
15 changed files with 181 additions and 213 deletions
|
@ -3,25 +3,25 @@ const zap = @import("zap");
|
||||||
|
|
||||||
/// A simple endpoint listening on the /stop route that shuts down zap
|
/// 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().
|
/// the main thread usually continues at the instructions after the call to zap.start().
|
||||||
pub const Self = @This();
|
pub const StopEndpoint = @This();
|
||||||
|
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
|
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
|
||||||
|
|
||||||
pub fn init(path: []const u8) Self {
|
pub fn init(path: []const u8) StopEndpoint {
|
||||||
return .{
|
return .{
|
||||||
.path = path,
|
.path = path,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(e: *Self, r: zap.Request) anyerror!void {
|
pub fn get(e: *StopEndpoint, r: zap.Request) anyerror!void {
|
||||||
_ = e;
|
_ = e;
|
||||||
_ = r;
|
_ = r;
|
||||||
zap.stop();
|
zap.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post(_: *Self, _: zap.Request) anyerror!void {}
|
pub fn post(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
||||||
pub fn put(_: *Self, _: zap.Request) anyerror!void {}
|
pub fn put(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
||||||
pub fn delete(_: *Self, _: zap.Request) anyerror!void {}
|
pub fn delete(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
||||||
pub fn patch(_: *Self, _: zap.Request) anyerror!void {}
|
pub fn patch(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
||||||
pub fn options(_: *Self, _: zap.Request) anyerror!void {}
|
pub fn options(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
||||||
|
|
|
@ -5,7 +5,7 @@ users: std.AutoHashMap(usize, InternalUser) = undefined,
|
||||||
lock: std.Thread.Mutex = undefined,
|
lock: std.Thread.Mutex = undefined,
|
||||||
count: usize = 0,
|
count: usize = 0,
|
||||||
|
|
||||||
pub const Self = @This();
|
pub const Users = @This();
|
||||||
|
|
||||||
const InternalUser = struct {
|
const InternalUser = struct {
|
||||||
id: usize = 0,
|
id: usize = 0,
|
||||||
|
@ -21,7 +21,7 @@ pub const User = struct {
|
||||||
last_name: []const u8,
|
last_name: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(a: std.mem.Allocator) Self {
|
pub fn init(a: std.mem.Allocator) Users {
|
||||||
return .{
|
return .{
|
||||||
.alloc = a,
|
.alloc = a,
|
||||||
.users = std.AutoHashMap(usize, InternalUser).init(a),
|
.users = std.AutoHashMap(usize, InternalUser).init(a),
|
||||||
|
@ -29,13 +29,13 @@ pub fn init(a: std.mem.Allocator) Self {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Users) void {
|
||||||
self.users.deinit();
|
self.users.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// the request will be freed (and its mem reused by facilio) when it's
|
// the request will be freed (and its mem reused by facilio) when it's
|
||||||
// completed, so we take copies of the names
|
// completed, so we take copies of the names
|
||||||
pub fn addByName(self: *Self, first: ?[]const u8, last: ?[]const u8) !usize {
|
pub fn addByName(self: *Users, first: ?[]const u8, last: ?[]const u8) !usize {
|
||||||
var user: InternalUser = undefined;
|
var user: InternalUser = undefined;
|
||||||
user.firstnamelen = 0;
|
user.firstnamelen = 0;
|
||||||
user.lastnamelen = 0;
|
user.lastnamelen = 0;
|
||||||
|
@ -64,7 +64,7 @@ pub fn addByName(self: *Self, first: ?[]const u8, last: ?[]const u8) !usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(self: *Self, id: usize) bool {
|
pub fn delete(self: *Users, id: usize) bool {
|
||||||
// We lock only on insertion, deletion, and listing
|
// We lock only on insertion, deletion, and listing
|
||||||
self.lock.lock();
|
self.lock.lock();
|
||||||
defer self.lock.unlock();
|
defer self.lock.unlock();
|
||||||
|
@ -76,7 +76,7 @@ pub fn delete(self: *Self, id: usize) bool {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: *Self, id: usize) ?User {
|
pub fn get(self: *Users, id: usize) ?User {
|
||||||
// we don't care about locking here, as our usage-pattern is unlikely to
|
// we don't care about locking here, as our usage-pattern is unlikely to
|
||||||
// get a user by id that is not known yet
|
// get a user by id that is not known yet
|
||||||
if (self.users.getPtr(id)) |pUser| {
|
if (self.users.getPtr(id)) |pUser| {
|
||||||
|
@ -90,7 +90,7 @@ pub fn get(self: *Self, id: usize) ?User {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(
|
pub fn update(
|
||||||
self: *Self,
|
self: *Users,
|
||||||
id: usize,
|
id: usize,
|
||||||
first: ?[]const u8,
|
first: ?[]const u8,
|
||||||
last: ?[]const u8,
|
last: ?[]const u8,
|
||||||
|
@ -112,7 +112,7 @@ pub fn update(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toJSON(self: *Self) ![]const u8 {
|
pub fn toJSON(self: *Users) ![]const u8 {
|
||||||
self.lock.lock();
|
self.lock.lock();
|
||||||
defer self.lock.unlock();
|
defer self.lock.unlock();
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ pub fn toJSON(self: *Self) ![]const u8 {
|
||||||
//
|
//
|
||||||
// Note: the following code is kept in here because it taught us a lesson
|
// Note: the following code is kept in here because it taught us a lesson
|
||||||
//
|
//
|
||||||
pub fn listWithRaceCondition(self: *Self, out: *std.ArrayList(User)) !void {
|
pub fn listWithRaceCondition(self: *Users, out: *std.ArrayList(User)) !void {
|
||||||
// We lock only on insertion, deletion, and listing
|
// We lock only on insertion, deletion, and listing
|
||||||
//
|
//
|
||||||
// NOTE: race condition:
|
// NOTE: race condition:
|
||||||
|
@ -169,18 +169,14 @@ pub fn listWithRaceCondition(self: *Self, out: *std.ArrayList(User)) !void {
|
||||||
|
|
||||||
const JsonUserIteratorWithRaceCondition = struct {
|
const JsonUserIteratorWithRaceCondition = struct {
|
||||||
it: std.AutoHashMap(usize, InternalUser).ValueIterator = undefined,
|
it: std.AutoHashMap(usize, InternalUser).ValueIterator = undefined,
|
||||||
const This = @This();
|
|
||||||
|
|
||||||
// careful:
|
pub fn init(internal_users: *std.AutoHashMap(usize, InternalUser)) JsonUserIteratorWithRaceCondition {
|
||||||
// - Self refers to the file's struct
|
|
||||||
// - This refers to the JsonUserIterator struct
|
|
||||||
pub fn init(internal_users: *std.AutoHashMap(usize, InternalUser)) This {
|
|
||||||
return .{
|
return .{
|
||||||
.it = internal_users.valueIterator(),
|
.it = internal_users.valueIterator(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(this: *This) ?User {
|
pub fn next(this: *JsonUserIteratorWithRaceCondition) ?User {
|
||||||
if (this.it.next()) |pUser| {
|
if (this.it.next()) |pUser| {
|
||||||
// we get a pointer to the internal user. so it should be safe to
|
// we get a pointer to the internal user. so it should be safe to
|
||||||
// create slices from its first and last name buffers
|
// create slices from its first and last name buffers
|
||||||
|
|
|
@ -5,7 +5,7 @@ const User = Users.User;
|
||||||
|
|
||||||
// an Endpoint
|
// an Endpoint
|
||||||
|
|
||||||
pub const Self = @This();
|
pub const UserWeb = @This();
|
||||||
|
|
||||||
alloc: std.mem.Allocator = undefined,
|
alloc: std.mem.Allocator = undefined,
|
||||||
_users: Users = undefined,
|
_users: Users = undefined,
|
||||||
|
@ -16,7 +16,7 @@ error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
|
||||||
pub fn init(
|
pub fn init(
|
||||||
a: std.mem.Allocator,
|
a: std.mem.Allocator,
|
||||||
user_path: []const u8,
|
user_path: []const u8,
|
||||||
) Self {
|
) UserWeb {
|
||||||
return .{
|
return .{
|
||||||
.alloc = a,
|
.alloc = a,
|
||||||
._users = Users.init(a),
|
._users = Users.init(a),
|
||||||
|
@ -24,15 +24,15 @@ pub fn init(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *UserWeb) void {
|
||||||
self._users.deinit();
|
self._users.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn users(self: *Self) *Users {
|
pub fn users(self: *UserWeb) *Users {
|
||||||
return &self._users;
|
return &self._users;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn userIdFromPath(self: *Self, path: []const u8) ?usize {
|
fn userIdFromPath(self: *UserWeb, path: []const u8) ?usize {
|
||||||
if (path.len >= self.path.len + 2) {
|
if (path.len >= self.path.len + 2) {
|
||||||
if (path[self.path.len] != '/') {
|
if (path[self.path.len] != '/') {
|
||||||
return null;
|
return null;
|
||||||
|
@ -43,8 +43,8 @@ fn userIdFromPath(self: *Self, path: []const u8) ?usize {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put(_: *Self, _: zap.Request) anyerror!void {}
|
pub fn put(_: *UserWeb, _: zap.Request) anyerror!void {}
|
||||||
pub fn get(self: *Self, r: zap.Request) anyerror!void {
|
pub fn get(self: *UserWeb, r: zap.Request) anyerror!void {
|
||||||
if (r.path) |path| {
|
if (r.path) |path| {
|
||||||
// /users
|
// /users
|
||||||
if (path.len == self.path.len) {
|
if (path.len == self.path.len) {
|
||||||
|
@ -60,7 +60,7 @@ pub fn get(self: *Self, r: zap.Request) anyerror!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn listUsers(self: *Self, r: zap.Request) !void {
|
fn listUsers(self: *UserWeb, r: zap.Request) !void {
|
||||||
if (self._users.toJSON()) |json| {
|
if (self._users.toJSON()) |json| {
|
||||||
defer self.alloc.free(json);
|
defer self.alloc.free(json);
|
||||||
try r.sendJson(json);
|
try r.sendJson(json);
|
||||||
|
@ -69,7 +69,7 @@ fn listUsers(self: *Self, r: zap.Request) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post(self: *Self, r: zap.Request) anyerror!void {
|
pub fn post(self: *UserWeb, r: zap.Request) anyerror!void {
|
||||||
if (r.body) |body| {
|
if (r.body) |body| {
|
||||||
const maybe_user: ?std.json.Parsed(User) = std.json.parseFromSlice(User, self.alloc, body, .{}) catch null;
|
const maybe_user: ?std.json.Parsed(User) = std.json.parseFromSlice(User, self.alloc, body, .{}) catch null;
|
||||||
if (maybe_user) |u| {
|
if (maybe_user) |u| {
|
||||||
|
@ -86,7 +86,7 @@ pub fn post(self: *Self, r: zap.Request) anyerror!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn patch(self: *Self, r: zap.Request) anyerror!void {
|
pub fn patch(self: *UserWeb, r: zap.Request) anyerror!void {
|
||||||
if (r.path) |path| {
|
if (r.path) |path| {
|
||||||
if (self.userIdFromPath(path)) |id| {
|
if (self.userIdFromPath(path)) |id| {
|
||||||
if (self._users.get(id)) |_| {
|
if (self._users.get(id)) |_| {
|
||||||
|
@ -109,7 +109,7 @@ pub fn patch(self: *Self, r: zap.Request) anyerror!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(self: *Self, r: zap.Request) anyerror!void {
|
pub fn delete(self: *UserWeb, r: zap.Request) anyerror!void {
|
||||||
if (r.path) |path| {
|
if (r.path) |path| {
|
||||||
if (self.userIdFromPath(path)) |id| {
|
if (self.userIdFromPath(path)) |id| {
|
||||||
var jsonbuf: [128]u8 = undefined;
|
var jsonbuf: [128]u8 = undefined;
|
||||||
|
@ -124,7 +124,7 @@ pub fn delete(self: *Self, r: zap.Request) anyerror!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn options(_: *Self, r: zap.Request) anyerror!void {
|
pub fn options(_: *UserWeb, r: zap.Request) anyerror!void {
|
||||||
try r.setHeader("Access-Control-Allow-Origin", "*");
|
try r.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
try r.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
try r.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
||||||
r.setStatus(zap.http.StatusCode.no_content);
|
r.setStatus(zap.http.StatusCode.no_content);
|
||||||
|
|
|
@ -6,8 +6,6 @@ const SharedAllocator = struct {
|
||||||
// static
|
// static
|
||||||
var allocator: std.mem.Allocator = undefined;
|
var allocator: std.mem.Allocator = undefined;
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
// just a convenience function
|
// just a convenience function
|
||||||
pub fn init(a: std.mem.Allocator) void {
|
pub fn init(a: std.mem.Allocator) void {
|
||||||
allocator = a;
|
allocator = a;
|
||||||
|
@ -43,8 +41,6 @@ const Handler = zap.Middleware.Handler(Context);
|
||||||
const UserMiddleWare = struct {
|
const UserMiddleWare = struct {
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
// Just some arbitrary struct we want in the per-request context
|
// Just some arbitrary struct we want in the per-request context
|
||||||
// note: it MUST have all default values!!!
|
// note: it MUST have all default values!!!
|
||||||
// note: it MUST have all default values!!!
|
// note: it MUST have all default values!!!
|
||||||
|
@ -57,22 +53,22 @@ const UserMiddleWare = struct {
|
||||||
email: []const u8 = undefined,
|
email: []const u8 = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(other: ?*Handler) Self {
|
pub fn init(other: ?*Handler) UserMiddleWare {
|
||||||
return .{
|
return .{
|
||||||
.handler = Handler.init(onRequest, other),
|
.handler = Handler.init(onRequest, other),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need the handler as a common interface to chain stuff
|
// we need the handler as a common interface to chain stuff
|
||||||
pub fn getHandler(self: *Self) *Handler {
|
pub fn getHandler(self: *UserMiddleWare) *Handler {
|
||||||
return &self.handler;
|
return &self.handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// note that the first parameter is of type *Handler, not *Self !!!
|
// note that the first parameter is of type *Handler, not *UserMiddleWare !!!
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||||
|
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
const self: *Self = @fieldParentPtr("handler", handler);
|
const self: *UserMiddleWare = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
// do our work: fill in the user field of the context
|
// do our work: fill in the user field of the context
|
||||||
|
@ -92,8 +88,6 @@ const UserMiddleWare = struct {
|
||||||
const SessionMiddleWare = struct {
|
const SessionMiddleWare = struct {
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
// Just some arbitrary struct we want in the per-request context
|
// Just some arbitrary struct we want in the per-request context
|
||||||
// note: it MUST have all default values!!!
|
// note: it MUST have all default values!!!
|
||||||
const Session = struct {
|
const Session = struct {
|
||||||
|
@ -101,21 +95,21 @@ const SessionMiddleWare = struct {
|
||||||
token: []const u8 = undefined,
|
token: []const u8 = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(other: ?*Handler) Self {
|
pub fn init(other: ?*Handler) SessionMiddleWare {
|
||||||
return .{
|
return .{
|
||||||
.handler = Handler.init(onRequest, other),
|
.handler = Handler.init(onRequest, other),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need the handler as a common interface to chain stuff
|
// we need the handler as a common interface to chain stuff
|
||||||
pub fn getHandler(self: *Self) *Handler {
|
pub fn getHandler(self: *SessionMiddleWare) *Handler {
|
||||||
return &self.handler;
|
return &self.handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// note that the first parameter is of type *Handler, not *Self !!!
|
// note that the first parameter is of type *Handler, not *SessionMiddleWare !!!
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
const self: *Self = @fieldParentPtr("handler", handler);
|
const self: *SessionMiddleWare = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
context.session = Session{
|
context.session = Session{
|
||||||
|
@ -134,24 +128,22 @@ const SessionMiddleWare = struct {
|
||||||
const HtmlMiddleWare = struct {
|
const HtmlMiddleWare = struct {
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
|
|
||||||
const Self = @This();
|
pub fn init(other: ?*Handler) HtmlMiddleWare {
|
||||||
|
|
||||||
pub fn init(other: ?*Handler) Self {
|
|
||||||
return .{
|
return .{
|
||||||
.handler = Handler.init(onRequest, other),
|
.handler = Handler.init(onRequest, other),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need the handler as a common interface to chain stuff
|
// we need the handler as a common interface to chain stuff
|
||||||
pub fn getHandler(self: *Self) *Handler {
|
pub fn getHandler(self: *HtmlMiddleWare) *Handler {
|
||||||
return &self.handler;
|
return &self.handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// note that the first parameter is of type *Handler, not *Self !!!
|
// note that the first parameter is of type *Handler, not *HtmlMiddleWare !!!
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||||
|
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
const self: *Self = @fieldParentPtr("handler", handler);
|
const self: *HtmlMiddleWare = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
std.debug.print("\n\nHtmlMiddleware: handling request with context: {any}\n\n", .{context});
|
std.debug.print("\n\nHtmlMiddleware: handling request with context: {any}\n\n", .{context});
|
||||||
|
|
|
@ -6,8 +6,6 @@ const SharedAllocator = struct {
|
||||||
// static
|
// static
|
||||||
var allocator: std.mem.Allocator = undefined;
|
var allocator: std.mem.Allocator = undefined;
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
// just a convenience function
|
// just a convenience function
|
||||||
pub fn init(a: std.mem.Allocator) void {
|
pub fn init(a: std.mem.Allocator) void {
|
||||||
allocator = a;
|
allocator = a;
|
||||||
|
@ -35,8 +33,6 @@ const Handler = zap.Middleware.Handler(Context);
|
||||||
const UserMiddleWare = struct {
|
const UserMiddleWare = struct {
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
// Just some arbitrary struct we want in the per-request context
|
// Just some arbitrary struct we want in the per-request context
|
||||||
// This is so that it can be constructed via .{}
|
// This is so that it can be constructed via .{}
|
||||||
// as we can't expect the listener to know how to initialize our context structs
|
// as we can't expect the listener to know how to initialize our context structs
|
||||||
|
@ -45,22 +41,22 @@ const UserMiddleWare = struct {
|
||||||
email: []const u8 = undefined,
|
email: []const u8 = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(other: ?*Handler) Self {
|
pub fn init(other: ?*Handler) UserMiddleWare {
|
||||||
return .{
|
return .{
|
||||||
.handler = Handler.init(onRequest, other),
|
.handler = Handler.init(onRequest, other),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need the handler as a common interface to chain stuff
|
// we need the handler as a common interface to chain stuff
|
||||||
pub fn getHandler(self: *Self) *Handler {
|
pub fn getHandler(self: *UserMiddleWare) *Handler {
|
||||||
return &self.handler;
|
return &self.handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// note that the first parameter is of type *Handler, not *Self !!!
|
// note that the first parameter is of type *Handler, not *UserMiddleWare !!!
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||||
|
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
const self: *Self = @fieldParentPtr("handler", handler);
|
const self: *UserMiddleWare = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
// do our work: fill in the user field of the context
|
// do our work: fill in the user field of the context
|
||||||
|
@ -82,8 +78,6 @@ const UserMiddleWare = struct {
|
||||||
const SessionMiddleWare = struct {
|
const SessionMiddleWare = struct {
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
// Just some arbitrary struct we want in the per-request context
|
// Just some arbitrary struct we want in the per-request context
|
||||||
// note: it MUST have all default values!!!
|
// note: it MUST have all default values!!!
|
||||||
const Session = struct {
|
const Session = struct {
|
||||||
|
@ -91,21 +85,21 @@ const SessionMiddleWare = struct {
|
||||||
token: []const u8 = undefined,
|
token: []const u8 = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(other: ?*Handler) Self {
|
pub fn init(other: ?*Handler) SessionMiddleWare {
|
||||||
return .{
|
return .{
|
||||||
.handler = Handler.init(onRequest, other),
|
.handler = Handler.init(onRequest, other),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need the handler as a common interface to chain stuff
|
// we need the handler as a common interface to chain stuff
|
||||||
pub fn getHandler(self: *Self) *Handler {
|
pub fn getHandler(self: *SessionMiddleWare) *Handler {
|
||||||
return &self.handler;
|
return &self.handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// note that the first parameter is of type *Handler, not *Self !!!
|
// note that the first parameter is of type *Handler, not *SessionMiddleWare !!!
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) !bool {
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
const self: *Self = @fieldParentPtr("handler", handler);
|
const self: *SessionMiddleWare = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
context.session = Session{
|
context.session = Session{
|
||||||
|
@ -136,11 +130,9 @@ const SessionMiddleWare = struct {
|
||||||
// `breakOnFinish` parameter.
|
// `breakOnFinish` parameter.
|
||||||
//
|
//
|
||||||
const HtmlEndpoint = struct {
|
const HtmlEndpoint = struct {
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
path: []const u8 = "(undefined)",
|
path: []const u8 = "(undefined)",
|
||||||
|
|
||||||
pub fn init() Self {
|
pub fn init() HtmlEndpoint {
|
||||||
return .{
|
return .{
|
||||||
.path = "/doesn't+matter",
|
.path = "/doesn't+matter",
|
||||||
};
|
};
|
||||||
|
@ -152,7 +144,7 @@ const HtmlEndpoint = struct {
|
||||||
pub fn patch(_: *HtmlEndpoint, _: zap.Request) !void {}
|
pub fn patch(_: *HtmlEndpoint, _: zap.Request) !void {}
|
||||||
pub fn options(_: *HtmlEndpoint, _: zap.Request) !void {}
|
pub fn options(_: *HtmlEndpoint, _: zap.Request) !void {}
|
||||||
|
|
||||||
pub fn get(_: *Self, r: zap.Request) !void {
|
pub fn get(_: *HtmlEndpoint, r: zap.Request) !void {
|
||||||
var buf: [1024]u8 = undefined;
|
var buf: [1024]u8 = undefined;
|
||||||
var userFound: bool = false;
|
var userFound: bool = false;
|
||||||
var sessionFound: bool = false;
|
var sessionFound: bool = false;
|
||||||
|
|
|
@ -14,13 +14,11 @@ fn on_request_verbose(r: zap.Request) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const SomePackage = struct {
|
pub const SomePackage = struct {
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
a: i8,
|
a: i8,
|
||||||
b: i8,
|
b: i8,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, a: i8, b: i8) Self {
|
pub fn init(allocator: Allocator, a: i8, b: i8) SomePackage {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.a = a,
|
.a = a,
|
||||||
|
@ -28,7 +26,7 @@ pub const SomePackage = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getA(self: *Self, req: zap.Request) !void {
|
pub fn getA(self: *SomePackage, req: zap.Request) !void {
|
||||||
std.log.warn("get_a_requested", .{});
|
std.log.warn("get_a_requested", .{});
|
||||||
|
|
||||||
const string = std.fmt.allocPrint(
|
const string = std.fmt.allocPrint(
|
||||||
|
@ -41,7 +39,7 @@ pub const SomePackage = struct {
|
||||||
req.sendBody(string) catch return;
|
req.sendBody(string) catch return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getB(self: *Self, req: zap.Request) !void {
|
pub fn getB(self: *SomePackage, req: zap.Request) !void {
|
||||||
std.log.warn("get_b_requested", .{});
|
std.log.warn("get_b_requested", .{});
|
||||||
|
|
||||||
const string = std.fmt.allocPrint(
|
const string = std.fmt.allocPrint(
|
||||||
|
@ -54,7 +52,7 @@ pub const SomePackage = struct {
|
||||||
req.sendBody(string) catch return;
|
req.sendBody(string) catch return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn incrementA(self: *Self, req: zap.Request) !void {
|
pub fn incrementA(self: *SomePackage, req: zap.Request) !void {
|
||||||
std.log.warn("increment_a_requested", .{});
|
std.log.warn("increment_a_requested", .{});
|
||||||
|
|
||||||
self.a += 1;
|
self.a += 1;
|
||||||
|
|
|
@ -20,13 +20,11 @@ const ContextManager = struct {
|
||||||
lock: std.Thread.Mutex = .{},
|
lock: std.Thread.Mutex = .{},
|
||||||
contexts: ContextList = undefined,
|
contexts: ContextList = undefined,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
channelName: []const u8,
|
channelName: []const u8,
|
||||||
usernamePrefix: []const u8,
|
usernamePrefix: []const u8,
|
||||||
) Self {
|
) ContextManager {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.channel = channelName,
|
.channel = channelName,
|
||||||
|
@ -35,14 +33,14 @@ const ContextManager = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *ContextManager) void {
|
||||||
for (self.contexts.items) |ctx| {
|
for (self.contexts.items) |ctx| {
|
||||||
self.allocator.free(ctx.userName);
|
self.allocator.free(ctx.userName);
|
||||||
}
|
}
|
||||||
self.contexts.deinit();
|
self.contexts.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newContext(self: *Self) !*Context {
|
pub fn newContext(self: *ContextManager) !*Context {
|
||||||
self.lock.lock();
|
self.lock.lock();
|
||||||
defer self.lock.unlock();
|
defer self.lock.unlock();
|
||||||
|
|
||||||
|
|
|
@ -37,11 +37,11 @@
|
||||||
//! };
|
//! };
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! pub fn post(_: *Self, _: zap.Request) void {}
|
//! pub fn post(_: *StopEndpoint, _: zap.Request) void {}
|
||||||
//! pub fn put(_: *Self, _: zap.Request) void {}
|
//! pub fn put(_: *StopEndpoint, _: zap.Request) void {}
|
||||||
//! pub fn delete(_: *Self, _: zap.Request) void {}
|
//! pub fn delete(_: *StopEndpoint, _: zap.Request) void {}
|
||||||
//! pub fn patch(_: *Self, _: zap.Request) void {}
|
//! pub fn patch(_: *StopEndpoint, _: zap.Request) void {}
|
||||||
//! pub fn options(_: *Self, _: zap.Request) void {}
|
//! pub fn options(_: *StopEndpoint, _: zap.Request) void {}
|
||||||
//!
|
//!
|
||||||
//! pub fn get(self: *StopEndpoint, r: zap.Request) void {
|
//! pub fn get(self: *StopEndpoint, r: zap.Request) void {
|
||||||
//! _ = self;
|
//! _ = self;
|
||||||
|
@ -117,24 +117,24 @@ pub const Wrapper = struct {
|
||||||
wrapped: *T,
|
wrapped: *T,
|
||||||
wrapper: Internal,
|
wrapper: Internal,
|
||||||
|
|
||||||
const Self = @This();
|
const Envelope = @This();
|
||||||
|
|
||||||
pub fn unwrap(wrapper: *Internal) *Self {
|
pub fn unwrap(wrapper: *Internal) *Envelope {
|
||||||
const self: *Self = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
const self: *Envelope = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(allocator: std.mem.Allocator, wrapper: *Internal) void {
|
pub fn destroy(allocator: std.mem.Allocator, wrapper: *Internal) void {
|
||||||
const self: *Self = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
const self: *Envelope = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
||||||
allocator.destroy(self);
|
allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn onRequestWrapped(wrapper: *Internal, r: zap.Request) !void {
|
pub fn onRequestWrapped(wrapper: *Internal, r: zap.Request) !void {
|
||||||
var self: *Self = Self.unwrap(wrapper);
|
var self: *Envelope = Envelope.unwrap(wrapper);
|
||||||
try self.onRequest(r);
|
try self.onRequest(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn onRequest(self: *Self, r: zap.Request) !void {
|
pub fn onRequest(self: *Envelope, r: zap.Request) !void {
|
||||||
const ret = switch (r.methodAsEnum()) {
|
const ret = switch (r.methodAsEnum()) {
|
||||||
.GET => self.wrapped.*.get(r),
|
.GET => self.wrapped.*.get(r),
|
||||||
.POST => self.wrapped.*.post(r),
|
.POST => self.wrapped.*.post(r),
|
||||||
|
@ -150,7 +150,7 @@ pub const Wrapper = struct {
|
||||||
switch (self.wrapped.*.error_strategy) {
|
switch (self.wrapped.*.error_strategy) {
|
||||||
.raise => return err,
|
.raise => return err,
|
||||||
.log_to_response => return r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505),
|
.log_to_response => return r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505),
|
||||||
.log_to_console => zap.debug("Error in {} {s} : {}", .{ Self, r.method orelse "(no method)", err }),
|
.log_to_console => zap.debug("Error in {} {s} : {}", .{ Envelope, r.method orelse "(no method)", err }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,12 +176,12 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
||||||
ep: *EndpointType,
|
ep: *EndpointType,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
error_strategy: ErrorStrategy,
|
error_strategy: ErrorStrategy,
|
||||||
const Self = @This();
|
const AuthenticatingEndpoint = @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: *EndpointType, authenticator: *Authenticator) Self {
|
pub fn init(e: *EndpointType, authenticator: *Authenticator) AuthenticatingEndpoint {
|
||||||
return .{
|
return .{
|
||||||
.authenticator = authenticator,
|
.authenticator = authenticator,
|
||||||
.ep = e,
|
.ep = e,
|
||||||
|
@ -191,7 +191,7 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authenticates GET requests using the Authenticator.
|
/// Authenticates GET requests using the Authenticator.
|
||||||
pub fn get(self: *Self, r: zap.Request) anyerror!void {
|
pub fn get(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
|
||||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthOK => self.ep.*.get(r),
|
.AuthOK => self.ep.*.get(r),
|
||||||
|
@ -200,7 +200,7 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authenticates POST requests using the Authenticator.
|
/// Authenticates POST requests using the Authenticator.
|
||||||
pub fn post(self: *Self, r: zap.Request) anyerror!void {
|
pub fn post(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
|
||||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthOK => self.ep.*.post(r),
|
.AuthOK => self.ep.*.post(r),
|
||||||
|
@ -209,7 +209,7 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authenticates PUT requests using the Authenticator.
|
/// Authenticates PUT requests using the Authenticator.
|
||||||
pub fn put(self: *Self, r: zap.Request) anyerror!void {
|
pub fn put(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
|
||||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthOK => self.ep.*.put(r),
|
.AuthOK => self.ep.*.put(r),
|
||||||
|
@ -218,7 +218,7 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authenticates DELETE requests using the Authenticator.
|
/// Authenticates DELETE requests using the Authenticator.
|
||||||
pub fn delete(self: *Self, r: zap.Request) anyerror!void {
|
pub fn delete(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
|
||||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthOK => self.ep.*.delete(r),
|
.AuthOK => self.ep.*.delete(r),
|
||||||
|
@ -227,7 +227,7 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authenticates PATCH requests using the Authenticator.
|
/// Authenticates PATCH requests using the Authenticator.
|
||||||
pub fn patch(self: *Self, r: zap.Request) anyerror!void {
|
pub fn patch(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
|
||||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthOK => self.ep.*.patch(r),
|
.AuthOK => self.ep.*.patch(r),
|
||||||
|
@ -236,7 +236,7 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authenticates OPTIONS requests using the Authenticator.
|
/// Authenticates OPTIONS requests using the Authenticator.
|
||||||
pub fn options(self: *Self, r: zap.Request) anyerror!void {
|
pub fn options(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
|
||||||
try switch (self.authenticator.authenticateRequest(&r)) {
|
try switch (self.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => return self.ep.*.unauthorized(r),
|
.AuthFailed => return self.ep.*.unauthorized(r),
|
||||||
.AuthOK => self.ep.*.put(r),
|
.AuthOK => self.ep.*.put(r),
|
||||||
|
@ -261,8 +261,6 @@ pub const Listener = struct {
|
||||||
listener: HttpListener,
|
listener: HttpListener,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
/// Internal static struct of member endpoints
|
/// Internal static struct of member endpoints
|
||||||
var endpoints: std.ArrayListUnmanaged(*Wrapper.Internal) = .empty;
|
var endpoints: std.ArrayListUnmanaged(*Wrapper.Internal) = .empty;
|
||||||
|
|
||||||
|
@ -274,7 +272,7 @@ pub const Listener = struct {
|
||||||
/// Initialize a new endpoint listener. Note, if you pass an `on_request`
|
/// Initialize a new endpoint listener. Note, if you pass an `on_request`
|
||||||
/// 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) Listener {
|
||||||
// reset the global in case init is called multiple times, as is the
|
// reset the global in case init is called multiple times, as is the
|
||||||
// case in the authentication tests
|
// case in the authentication tests
|
||||||
endpoints = .empty;
|
endpoints = .empty;
|
||||||
|
@ -297,7 +295,7 @@ pub const Listener = struct {
|
||||||
/// De-init the listener and free its resources.
|
/// De-init the listener and free its resources.
|
||||||
/// 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: *Listener) void {
|
||||||
for (endpoints.items) |endpoint_wrapper| {
|
for (endpoints.items) |endpoint_wrapper| {
|
||||||
endpoint_wrapper.destroy(self.allocator, endpoint_wrapper);
|
endpoint_wrapper.destroy(self.allocator, endpoint_wrapper);
|
||||||
}
|
}
|
||||||
|
@ -306,7 +304,7 @@ pub const Listener = struct {
|
||||||
|
|
||||||
/// Call this to start listening. After this, no more endpoints can be
|
/// Call this to start listening. After this, no more endpoints can be
|
||||||
/// registered.
|
/// registered.
|
||||||
pub fn listen(self: *Self) !void {
|
pub fn listen(self: *Listener) !void {
|
||||||
try self.listener.listen();
|
try self.listener.listen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +312,7 @@ 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: anytype) !void {
|
pub fn register(self: *Listener, e: anytype) !void {
|
||||||
for (endpoints.items) |other| {
|
for (endpoints.items) |other| {
|
||||||
if (std.mem.startsWith(
|
if (std.mem.startsWith(
|
||||||
u8,
|
u8,
|
||||||
|
|
|
@ -86,14 +86,14 @@ pub fn Basic(comptime Lookup: type, comptime kind: BasicAuthStrategy) type {
|
||||||
realm: ?[]const u8,
|
realm: ?[]const u8,
|
||||||
lookup: *Lookup,
|
lookup: *Lookup,
|
||||||
|
|
||||||
const Self = @This();
|
const BasicAuth = @This();
|
||||||
|
|
||||||
/// Creates a BasicAuth. `lookup` must implement `.get([]const u8) -> []const u8`
|
/// Creates a BasicAuth. `lookup` must implement `.get([]const u8) -> []const u8`
|
||||||
/// different implementations can
|
/// different implementations can
|
||||||
/// - either decode, lookup and compare passwords
|
/// - either decode, lookup and compare passwords
|
||||||
/// - or just check for existence of the base64-encoded user:pass combination
|
/// - or just check for existence of the base64-encoded user:pass combination
|
||||||
/// if realm is provided (not null), a copy of it is taken -> call deinit() to clean up
|
/// if realm is provided (not null), a copy of it is taken -> call deinit() to clean up
|
||||||
pub fn init(allocator: std.mem.Allocator, lookup: *Lookup, realm: ?[]const u8) !Self {
|
pub fn init(allocator: std.mem.Allocator, lookup: *Lookup, realm: ?[]const u8) !BasicAuth {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.lookup = lookup,
|
.lookup = lookup,
|
||||||
|
@ -102,7 +102,7 @@ pub fn Basic(comptime Lookup: type, comptime kind: BasicAuthStrategy) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deinit the authenticator.
|
/// Deinit the authenticator.
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *BasicAuth) void {
|
||||||
if (self.realm) |the_realm| {
|
if (self.realm) |the_realm| {
|
||||||
self.allocator.free(the_realm);
|
self.allocator.free(the_realm);
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ pub fn Basic(comptime Lookup: type, comptime kind: BasicAuthStrategy) type {
|
||||||
|
|
||||||
/// Use this to decode the auth_header into user:pass, lookup pass in lookup.
|
/// Use this to decode the auth_header into user:pass, lookup pass in lookup.
|
||||||
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
||||||
pub fn authenticateUserPass(self: *Self, auth_header: []const u8) AuthResult {
|
pub fn authenticateUserPass(self: *BasicAuth, auth_header: []const u8) AuthResult {
|
||||||
zap.debug("AuthenticateUserPass\n", .{});
|
zap.debug("AuthenticateUserPass\n", .{});
|
||||||
const encoded = auth_header[AuthScheme.Basic.str().len..];
|
const encoded = auth_header[AuthScheme.Basic.str().len..];
|
||||||
const decoder = std.base64.standard.Decoder;
|
const decoder = std.base64.standard.Decoder;
|
||||||
|
@ -173,14 +173,14 @@ pub fn Basic(comptime Lookup: type, comptime kind: BasicAuthStrategy) type {
|
||||||
|
|
||||||
/// Use this to just look up if the base64-encoded auth_header exists in lookup.
|
/// Use this to just look up if the base64-encoded auth_header exists in lookup.
|
||||||
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
||||||
pub fn authenticateToken68(self: *Self, auth_header: []const u8) AuthResult {
|
pub fn authenticateToken68(self: *BasicAuth, auth_header: []const u8) AuthResult {
|
||||||
const token = auth_header[AuthScheme.Basic.str().len..];
|
const token = auth_header[AuthScheme.Basic.str().len..];
|
||||||
return if (self.lookup.*.contains(token)) .AuthOK else .AuthFailed;
|
return if (self.lookup.*.contains(token)) .AuthOK else .AuthFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// dispatch based on kind (.UserPass / .Token689) and try to authenticate based on the header.
|
/// dispatch based on kind (.UserPass / .Token689) and try to authenticate based on the header.
|
||||||
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
||||||
pub fn authenticate(self: *Self, auth_header: []const u8) AuthResult {
|
pub fn authenticate(self: *BasicAuth, auth_header: []const u8) AuthResult {
|
||||||
zap.debug("AUTHENTICATE\n", .{});
|
zap.debug("AUTHENTICATE\n", .{});
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
.UserPass => return self.authenticateUserPass(auth_header),
|
.UserPass => return self.authenticateUserPass(auth_header),
|
||||||
|
@ -192,7 +192,7 @@ pub fn Basic(comptime Lookup: type, comptime kind: BasicAuthStrategy) type {
|
||||||
///
|
///
|
||||||
/// Tries to extract the authentication header and perform the authentication.
|
/// Tries to extract the authentication header and perform the authentication.
|
||||||
/// If no authentication header is found, an authorization header is tried.
|
/// If no authentication header is found, an authorization header is tried.
|
||||||
pub fn authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
|
pub fn authenticateRequest(self: *BasicAuth, 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", .{});
|
||||||
|
@ -225,12 +225,10 @@ pub const BearerSingle = struct {
|
||||||
token: []const u8,
|
token: []const u8,
|
||||||
realm: ?[]const u8,
|
realm: ?[]const u8,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
/// Creates a Single-Token Bearer Authenticator.
|
/// Creates a Single-Token Bearer Authenticator.
|
||||||
/// Takes a copy of the token.
|
/// Takes a copy of the token.
|
||||||
/// If realm is provided (not null), a copy is taken call deinit() to clean up.
|
/// If realm is provided (not null), a copy is taken call deinit() to clean up.
|
||||||
pub fn init(allocator: std.mem.Allocator, token: []const u8, realm: ?[]const u8) !Self {
|
pub fn init(allocator: std.mem.Allocator, token: []const u8, realm: ?[]const u8) !BearerSingle {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.token = try allocator.dupe(u8, token),
|
.token = try allocator.dupe(u8, token),
|
||||||
|
@ -240,7 +238,7 @@ pub const BearerSingle = struct {
|
||||||
|
|
||||||
/// Try to authenticate based on the header.
|
/// Try to authenticate based on the header.
|
||||||
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
||||||
pub fn authenticate(self: *Self, auth_header: []const u8) AuthResult {
|
pub fn authenticate(self: *BearerSingle, auth_header: []const u8) AuthResult {
|
||||||
if (checkAuthHeader(.Bearer, auth_header) == false) {
|
if (checkAuthHeader(.Bearer, auth_header) == false) {
|
||||||
return .AuthFailed;
|
return .AuthFailed;
|
||||||
}
|
}
|
||||||
|
@ -251,7 +249,7 @@ pub const BearerSingle = struct {
|
||||||
/// The zap authentication request handler.
|
/// The zap authentication request handler.
|
||||||
///
|
///
|
||||||
/// Tries to extract the authentication header and perform the authentication.
|
/// Tries to extract the authentication header and perform the authentication.
|
||||||
pub fn authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
|
pub fn authenticateRequest(self: *BearerSingle, 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);
|
||||||
}
|
}
|
||||||
|
@ -259,7 +257,7 @@ pub const BearerSingle = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deinits the authenticator.
|
/// Deinits the authenticator.
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *BearerSingle) void {
|
||||||
if (self.realm) |the_realm| {
|
if (self.realm) |the_realm| {
|
||||||
self.allocator.free(the_realm);
|
self.allocator.free(the_realm);
|
||||||
}
|
}
|
||||||
|
@ -283,12 +281,12 @@ pub fn BearerMulti(comptime Lookup: type) type {
|
||||||
lookup: *Lookup,
|
lookup: *Lookup,
|
||||||
realm: ?[]const u8,
|
realm: ?[]const u8,
|
||||||
|
|
||||||
const Self = @This();
|
const BearerMultiAuth = @This();
|
||||||
|
|
||||||
/// Creates a Multi Token Bearer Authenticator. `lookup` must implement
|
/// Creates a Multi Token Bearer Authenticator. `lookup` must implement
|
||||||
/// `.get([]const u8) -> []const u8` to look up tokens.
|
/// `.get([]const u8) -> []const u8` to look up tokens.
|
||||||
/// If realm is provided (not null), a copy of it is taken -> call deinit() to clean up.
|
/// If realm is provided (not null), a copy of it is taken -> call deinit() to clean up.
|
||||||
pub fn init(allocator: std.mem.Allocator, lookup: *Lookup, realm: ?[]const u8) !Self {
|
pub fn init(allocator: std.mem.Allocator, lookup: *Lookup, realm: ?[]const u8) !BearerMultiAuth {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.lookup = lookup,
|
.lookup = lookup,
|
||||||
|
@ -298,7 +296,7 @@ pub fn BearerMulti(comptime Lookup: type) type {
|
||||||
|
|
||||||
/// Deinit the authenticator. Only required if a realm was provided at
|
/// Deinit the authenticator. Only required if a realm was provided at
|
||||||
/// init() time.
|
/// init() time.
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *BearerMultiAuth) void {
|
||||||
if (self.realm) |the_realm| {
|
if (self.realm) |the_realm| {
|
||||||
self.allocator.free(the_realm);
|
self.allocator.free(the_realm);
|
||||||
}
|
}
|
||||||
|
@ -306,7 +304,7 @@ pub fn BearerMulti(comptime Lookup: type) type {
|
||||||
|
|
||||||
/// Try to authenticate based on the header.
|
/// Try to authenticate based on the header.
|
||||||
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
/// Note: usually, you don't want to use this; you'd go for `authenticateRequest()`.
|
||||||
pub fn authenticate(self: *Self, auth_header: []const u8) AuthResult {
|
pub fn authenticate(self: *BearerMultiAuth, auth_header: []const u8) AuthResult {
|
||||||
if (checkAuthHeader(.Bearer, auth_header) == false) {
|
if (checkAuthHeader(.Bearer, auth_header) == false) {
|
||||||
return .AuthFailed;
|
return .AuthFailed;
|
||||||
}
|
}
|
||||||
|
@ -317,7 +315,7 @@ pub fn BearerMulti(comptime Lookup: type) type {
|
||||||
/// The zap authentication request handler.
|
/// The zap authentication request handler.
|
||||||
///
|
///
|
||||||
/// Tries to extract the authentication header and perform the authentication.
|
/// Tries to extract the authentication header and perform the authentication.
|
||||||
pub fn authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
|
pub fn authenticateRequest(self: *BearerMultiAuth, 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);
|
||||||
}
|
}
|
||||||
|
@ -388,7 +386,7 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
|
||||||
passwordLookupLock: std.Thread.Mutex = .{},
|
passwordLookupLock: std.Thread.Mutex = .{},
|
||||||
tokenLookupLock: std.Thread.Mutex = .{},
|
tokenLookupLock: std.Thread.Mutex = .{},
|
||||||
|
|
||||||
const Self = @This();
|
const UserPassSessionAuth = @This();
|
||||||
const SessionTokenMap = std.StringHashMap(void);
|
const SessionTokenMap = std.StringHashMap(void);
|
||||||
const Hash = std.crypto.hash.sha2.Sha256;
|
const Hash = std.crypto.hash.sha2.Sha256;
|
||||||
|
|
||||||
|
@ -400,8 +398,8 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
lookup: *Lookup,
|
lookup: *Lookup,
|
||||||
args: UserPassSessionArgs,
|
args: UserPassSessionArgs,
|
||||||
) !Self {
|
) !UserPassSessionAuth {
|
||||||
const ret: Self = .{
|
const ret: UserPassSessionAuth = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.settings = .{
|
.settings = .{
|
||||||
.usernameParam = try allocator.dupe(u8, args.usernameParam),
|
.usernameParam = try allocator.dupe(u8, args.usernameParam),
|
||||||
|
@ -419,7 +417,7 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
|
||||||
}
|
}
|
||||||
|
|
||||||
/// De-init this authenticator.
|
/// De-init this authenticator.
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *UserPassSessionAuth) void {
|
||||||
self.allocator.free(self.settings.usernameParam);
|
self.allocator.free(self.settings.usernameParam);
|
||||||
self.allocator.free(self.settings.passwordParam);
|
self.allocator.free(self.settings.passwordParam);
|
||||||
self.allocator.free(self.settings.loginPage);
|
self.allocator.free(self.settings.loginPage);
|
||||||
|
@ -434,7 +432,7 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.Request) void {
|
pub fn logout(self: *UserPassSessionAuth, r: *const zap.Request) void {
|
||||||
// we erase the list of valid tokens server-side (later) and set the
|
// we erase the list of valid tokens server-side (later) and set the
|
||||||
// cookie to "invalid" on the client side.
|
// cookie to "invalid" on the client side.
|
||||||
if (r.setCookie(.{
|
if (r.setCookie(.{
|
||||||
|
@ -469,7 +467,7 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _internal_authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
|
fn _internal_authenticateRequest(self: *UserPassSessionAuth, 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)) {
|
||||||
|
@ -562,7 +560,7 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
|
||||||
/// The zap authentication request handler.
|
/// The zap authentication request handler.
|
||||||
///
|
///
|
||||||
/// See above for how it works.
|
/// See above for how it works.
|
||||||
pub fn authenticateRequest(self: *Self, r: *const zap.Request) AuthResult {
|
pub fn authenticateRequest(self: *UserPassSessionAuth, 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
|
||||||
|
@ -582,11 +580,11 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redirect(self: *Self, r: *const zap.Request) !void {
|
fn redirect(self: *UserPassSessionAuth, r: *const zap.Request) !void {
|
||||||
try r.redirectTo(self.settings.loginPage, self.settings.redirectCode);
|
try r.redirectTo(self.settings.loginPage, self.settings.redirectCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createSessionToken(self: *Self, username: []const u8, password: []const u8) ![]const u8 {
|
fn createSessionToken(self: *UserPassSessionAuth, username: []const u8, password: []const u8) ![]const u8 {
|
||||||
var hasher = Hash.init(.{});
|
var hasher = Hash.init(.{});
|
||||||
hasher.update(username);
|
hasher.update(username);
|
||||||
hasher.update(password);
|
hasher.update(password);
|
||||||
|
@ -602,7 +600,7 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
|
||||||
return token_str;
|
return token_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createAndStoreSessionToken(self: *Self, username: []const u8, password: []const u8) ![]const u8 {
|
fn createAndStoreSessionToken(self: *UserPassSessionAuth, username: []const u8, password: []const u8) ![]const u8 {
|
||||||
const token = try self.createSessionToken(username, password);
|
const token = try self.createSessionToken(username, password);
|
||||||
self.tokenLookupLock.lock();
|
self.tokenLookupLock.lock();
|
||||||
defer self.tokenLookupLock.unlock();
|
defer self.tokenLookupLock.unlock();
|
||||||
|
|
|
@ -5,15 +5,15 @@ const std = @import("std");
|
||||||
debugOn: bool,
|
debugOn: bool,
|
||||||
|
|
||||||
/// Access to facil.io's logging facilities
|
/// Access to facil.io's logging facilities
|
||||||
const Self = @This();
|
const Log = @This();
|
||||||
|
|
||||||
pub fn init(comptime debug: bool) Self {
|
pub fn init(comptime debug: bool) Log {
|
||||||
return .{
|
return .{
|
||||||
.debugOn = debug,
|
.debugOn = debug,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log(self: *const Self, comptime fmt: []const u8, args: anytype) void {
|
pub fn log(self: *const Log, comptime fmt: []const u8, args: anytype) void {
|
||||||
if (self.debugOn) {
|
if (self.debugOn) {
|
||||||
std.debug.print("[zap] - " ++ fmt, args);
|
std.debug.print("[zap] - " ++ fmt, args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
||||||
const fio = @import("fio.zig");
|
const fio = @import("fio.zig");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
|
||||||
const Self = @This();
|
const Mustache = @This();
|
||||||
|
|
||||||
const struct_mustache_s = opaque {};
|
const struct_mustache_s = opaque {};
|
||||||
const mustache_s = struct_mustache_s;
|
const mustache_s = struct_mustache_s;
|
||||||
|
@ -51,7 +51,7 @@ pub const Error = error{
|
||||||
|
|
||||||
/// Create a new `Mustache` instance; `deinit()` should be called to free
|
/// Create a new `Mustache` instance; `deinit()` should be called to free
|
||||||
/// the object after usage.
|
/// the object after usage.
|
||||||
pub fn init(load_args: LoadArgs) Error!Self {
|
pub fn init(load_args: LoadArgs) Error!Mustache {
|
||||||
var err: mustache_error_en = undefined;
|
var err: mustache_error_en = undefined;
|
||||||
|
|
||||||
const args: MustacheLoadArgsFio = .{
|
const args: MustacheLoadArgsFio = .{
|
||||||
|
@ -72,7 +72,7 @@ pub fn init(load_args: LoadArgs) Error!Self {
|
||||||
|
|
||||||
const ret = fiobj_mustache_new(args);
|
const ret = fiobj_mustache_new(args);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
0 => return Self{
|
0 => return Mustache{
|
||||||
.handle = ret.?,
|
.handle = ret.?,
|
||||||
},
|
},
|
||||||
1 => return Error.MUSTACHE_ERR_TOO_DEEP,
|
1 => return Error.MUSTACHE_ERR_TOO_DEEP,
|
||||||
|
@ -93,18 +93,18 @@ pub fn init(load_args: LoadArgs) Error!Self {
|
||||||
|
|
||||||
/// Convenience function to create a new `Mustache` instance with in-memory data loaded;
|
/// Convenience function to create a new `Mustache` instance with in-memory data loaded;
|
||||||
/// `deinit()` should be called to free the object after usage..
|
/// `deinit()` should be called to free the object after usage..
|
||||||
pub fn fromData(data: []const u8) Error!Self {
|
pub fn fromData(data: []const u8) Error!Mustache {
|
||||||
return Self.init(.{ .data = data });
|
return Mustache.init(.{ .data = data });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function to create a new `Mustache` instance with file-based data loaded;
|
/// Convenience function to create a new `Mustache` instance with file-based data loaded;
|
||||||
/// `deinit()` should be called to free the object after usage..
|
/// `deinit()` should be called to free the object after usage..
|
||||||
pub fn fromFile(filename: []const u8) Error!Self {
|
pub fn fromFile(filename: []const u8) Error!Mustache {
|
||||||
return Self.init(.{ .filename = filename });
|
return Mustache.init(.{ .filename = filename });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Free the data backing a `Mustache` instance.
|
/// Free the data backing a `Mustache` instance.
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Mustache) void {
|
||||||
fiobj_mustache_free(self.handle);
|
fiobj_mustache_free(self.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ pub const BuildResult = struct {
|
||||||
// TODO: The build may be slow because it needs to convert zig types to facil.io
|
// TODO: The build may be slow because it needs to convert zig types to facil.io
|
||||||
// types. However, this needs to be investigated into.
|
// types. However, this needs to be investigated into.
|
||||||
// See `fiobjectify` for more information.
|
// See `fiobjectify` for more information.
|
||||||
pub fn build(self: *Self, data: anytype) BuildResult {
|
pub fn build(self: *Mustache, data: anytype) BuildResult {
|
||||||
const T = @TypeOf(data);
|
const T = @TypeOf(data);
|
||||||
if (@typeInfo(T) != .@"struct") {
|
if (@typeInfo(T) != .@"struct") {
|
||||||
@compileError("No struct: '" ++ @typeName(T) ++ "'");
|
@compileError("No struct: '" ++ @typeName(T) ++ "'");
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub const HttpParamStrKV = struct {
|
||||||
pub const HttpParamStrKVList = struct {
|
pub const HttpParamStrKVList = struct {
|
||||||
items: []HttpParamStrKV,
|
items: []HttpParamStrKV,
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
pub fn deinit(self: *@This()) void {
|
pub fn deinit(self: *HttpParamStrKVList) void {
|
||||||
for (self.items) |item| {
|
for (self.items) |item| {
|
||||||
self.allocator.free(item.key);
|
self.allocator.free(item.key);
|
||||||
self.allocator.free(item.value);
|
self.allocator.free(item.value);
|
||||||
|
@ -43,7 +43,7 @@ pub const HttpParamStrKVList = struct {
|
||||||
pub const HttpParamKVList = struct {
|
pub const HttpParamKVList = struct {
|
||||||
items: []HttpParamKV,
|
items: []HttpParamKV,
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
pub fn deinit(self: *const @This()) void {
|
pub fn deinit(self: *const HttpParamKVList) void {
|
||||||
for (self.items) |item| {
|
for (self.items) |item| {
|
||||||
self.allocator.free(item.key);
|
self.allocator.free(item.key);
|
||||||
if (item.value) |v| {
|
if (item.value) |v| {
|
||||||
|
@ -109,7 +109,7 @@ pub const HttpParamBinaryFile = struct {
|
||||||
filename: ?[]const u8 = null,
|
filename: ?[]const u8 = null,
|
||||||
|
|
||||||
/// format function for printing file upload data
|
/// format function for printing file upload data
|
||||||
pub fn format(value: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
pub fn format(value: HttpParamBinaryFile, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
const d = value.data orelse "\\0";
|
const d = value.data orelse "\\0";
|
||||||
const m = value.mimetype orelse "null";
|
const m = value.mimetype orelse "null";
|
||||||
const f = value.filename orelse "null";
|
const f = value.filename orelse "null";
|
||||||
|
@ -286,30 +286,30 @@ pub const UserContext = struct {
|
||||||
user_context: ?*anyopaque = null,
|
user_context: ?*anyopaque = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Self = @This();
|
const Request = @This();
|
||||||
|
|
||||||
/// mark the current request as finished. Important for middleware-style
|
/// mark the current request as finished. Important for middleware-style
|
||||||
/// request handler chaining. Called when sending a body, redirecting, etc.
|
/// request handler chaining. Called when sending a body, redirecting, etc.
|
||||||
pub fn markAsFinished(self: *const Self, finished: bool) void {
|
pub fn markAsFinished(self: *const Request, finished: bool) void {
|
||||||
// we might be a copy
|
// we might be a copy
|
||||||
self._is_finished.* = finished;
|
self._is_finished.* = finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// tell whether request processing has finished. (e.g. response sent,
|
/// tell whether request processing has finished. (e.g. response sent,
|
||||||
/// redirected, ...)
|
/// redirected, ...)
|
||||||
pub fn isFinished(self: *const Self) bool {
|
pub fn isFinished(self: *const Request) bool {
|
||||||
// we might be a copy
|
// we might be a copy
|
||||||
return self._is_finished.*;
|
return self._is_finished.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// if you absolutely must, you can set any context on the request here
|
/// if you absolutely must, you can set any context on the request here
|
||||||
// (note, this line is linked to from the readme) -- TODO: sync
|
// (note, this line is linked to from the readme) -- TODO: sync
|
||||||
pub fn setUserContext(self: *const Self, context: *anyopaque) void {
|
pub fn setUserContext(self: *const Request, context: *anyopaque) void {
|
||||||
self._user_context.*.user_context = context;
|
self._user_context.*.user_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the associated user context of the request.
|
/// get the associated user context of the request.
|
||||||
pub fn getUserContext(self: *const Self, comptime Context: type) ?*Context {
|
pub fn getUserContext(self: *const Request, comptime Context: type) ?*Context {
|
||||||
if (self._user_context.*.user_context) |ptr| {
|
if (self._user_context.*.user_context) |ptr| {
|
||||||
return @as(*Context, @ptrCast(@alignCast(ptr)));
|
return @as(*Context, @ptrCast(@alignCast(ptr)));
|
||||||
} else {
|
} else {
|
||||||
|
@ -322,7 +322,7 @@ pub fn getUserContext(self: *const Self, comptime Context: type) ?*Context {
|
||||||
/// const err = zap.HttpError; // this is to show that `err` is an Error
|
/// const err = zap.HttpError; // this is to show that `err` is an Error
|
||||||
/// r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505);
|
/// r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn sendError(self: *const Self, err: anyerror, err_trace: ?std.builtin.StackTrace, errorcode_num: usize) void {
|
pub fn sendError(self: *const Request, err: anyerror, err_trace: ?std.builtin.StackTrace, errorcode_num: usize) void {
|
||||||
// TODO: query accept headers
|
// TODO: query accept headers
|
||||||
if (self._internal_sendError(err, err_trace, errorcode_num)) {
|
if (self._internal_sendError(err, err_trace, errorcode_num)) {
|
||||||
return;
|
return;
|
||||||
|
@ -332,7 +332,7 @@ pub fn sendError(self: *const Self, err: anyerror, err_trace: ?std.builtin.Stack
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used internally. Probably does not need to be public.
|
/// Used internally. Probably does not need to be public.
|
||||||
pub fn _internal_sendError(self: *const Self, err: anyerror, err_trace: ?std.builtin.StackTrace, errorcode_num: usize) !void {
|
pub fn _internal_sendError(self: *const Request, err: anyerror, err_trace: ?std.builtin.StackTrace, errorcode_num: usize) !void {
|
||||||
// TODO: query accept headers
|
// TODO: query accept headers
|
||||||
// TODO: let's hope 20k is enough. Maybe just really allocate here
|
// TODO: let's hope 20k is enough. Maybe just really allocate here
|
||||||
self.h.*.status = errorcode_num;
|
self.h.*.status = errorcode_num;
|
||||||
|
@ -352,7 +352,7 @@ pub fn _internal_sendError(self: *const Self, err: anyerror, err_trace: ?std.bui
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send body.
|
/// Send body.
|
||||||
pub fn sendBody(self: *const Self, body: []const u8) HttpError!void {
|
pub fn sendBody(self: *const Request, body: []const u8) HttpError!void {
|
||||||
const ret = fio.http_send_body(self.h, @as(
|
const ret = fio.http_send_body(self.h, @as(
|
||||||
*anyopaque,
|
*anyopaque,
|
||||||
@ptrFromInt(@intFromPtr(body.ptr)),
|
@ptrFromInt(@intFromPtr(body.ptr)),
|
||||||
|
@ -363,7 +363,7 @@ pub fn sendBody(self: *const Self, body: []const u8) HttpError!void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set content type and send json buffer.
|
/// Set content type and send json buffer.
|
||||||
pub fn sendJson(self: *const Self, json: []const u8) HttpError!void {
|
pub fn sendJson(self: *const Request, json: []const u8) HttpError!void {
|
||||||
if (self.setContentType(.JSON)) {
|
if (self.setContentType(.JSON)) {
|
||||||
if (fio.http_send_body(self.h, @as(
|
if (fio.http_send_body(self.h, @as(
|
||||||
*anyopaque,
|
*anyopaque,
|
||||||
|
@ -374,7 +374,7 @@ pub fn sendJson(self: *const Self, json: []const u8) HttpError!void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set content type.
|
/// Set content type.
|
||||||
pub fn setContentType(self: *const Self, c: ContentType) HttpError!void {
|
pub fn setContentType(self: *const Request, c: ContentType) HttpError!void {
|
||||||
const s = switch (c) {
|
const s = switch (c) {
|
||||||
.TEXT => "text/plain",
|
.TEXT => "text/plain",
|
||||||
.JSON => "application/json",
|
.JSON => "application/json",
|
||||||
|
@ -385,7 +385,7 @@ pub fn setContentType(self: *const Self, c: ContentType) HttpError!void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// redirect to path with status code 302 by default
|
/// redirect to path with status code 302 by default
|
||||||
pub fn redirectTo(self: *const Self, path: []const u8, code: ?http.StatusCode) HttpError!void {
|
pub fn redirectTo(self: *const Request, path: []const u8, code: ?http.StatusCode) HttpError!void {
|
||||||
self.setStatus(if (code) |status| status else .found);
|
self.setStatus(if (code) |status| status else .found);
|
||||||
try self.setHeader("Location", path);
|
try self.setHeader("Location", path);
|
||||||
try self.sendBody("moved");
|
try self.sendBody("moved");
|
||||||
|
@ -394,7 +394,7 @@ pub fn redirectTo(self: *const Self, path: []const u8, code: ?http.StatusCode) H
|
||||||
|
|
||||||
/// shows how to use the logger
|
/// shows how to use the logger
|
||||||
pub fn setContentTypeWithLogger(
|
pub fn setContentTypeWithLogger(
|
||||||
self: *const Self,
|
self: *const Request,
|
||||||
c: ContentType,
|
c: ContentType,
|
||||||
logger: *const Log,
|
logger: *const Log,
|
||||||
) HttpError!void {
|
) HttpError!void {
|
||||||
|
@ -408,7 +408,7 @@ pub fn setContentTypeWithLogger(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to determine the content type by file extension of request path, and sets it.
|
/// Tries to determine the content type by file extension of request path, and sets it.
|
||||||
pub fn setContentTypeFromPath(self: *const Self) !void {
|
pub fn setContentTypeFromPath(self: *const Request) !void {
|
||||||
const t = fio.http_mimetype_find2(self.h.*.path);
|
const t = fio.http_mimetype_find2(self.h.*.path);
|
||||||
if (fio.is_invalid(t) == 1) return error.HttpSetContentType;
|
if (fio.is_invalid(t) == 1) return error.HttpSetContentType;
|
||||||
const ret = fio.fiobj_hash_set(
|
const ret = fio.fiobj_hash_set(
|
||||||
|
@ -422,7 +422,7 @@ pub fn setContentTypeFromPath(self: *const Self) !void {
|
||||||
/// Tries to determine the content type by filename extension, and sets it.
|
/// Tries to determine the content type by filename extension, and sets it.
|
||||||
/// If the extension cannot be determined, NoExtensionInFilename error is
|
/// If the extension cannot be determined, NoExtensionInFilename error is
|
||||||
/// returned.
|
/// returned.
|
||||||
pub fn setContentTypeFromFilename(self: *const Self, filename: []const u8) !void {
|
pub fn setContentTypeFromFilename(self: *const Request, filename: []const u8) !void {
|
||||||
const ext = std.fs.path.extension(filename);
|
const ext = std.fs.path.extension(filename);
|
||||||
|
|
||||||
if (ext.len > 1) {
|
if (ext.len > 1) {
|
||||||
|
@ -442,7 +442,7 @@ pub fn setContentTypeFromFilename(self: *const Self, filename: []const u8) !void
|
||||||
/// NOTE that header-names are lowerased automatically while parsing the request.
|
/// NOTE that header-names are lowerased automatically while parsing the request.
|
||||||
/// so please only use lowercase keys!
|
/// so please only use lowercase keys!
|
||||||
/// Returned mem is temp. Do not free it.
|
/// Returned mem is temp. Do not free it.
|
||||||
pub fn getHeader(self: *const Self, name: []const u8) ?[]const u8 {
|
pub fn getHeader(self: *const Request, name: []const u8) ?[]const u8 {
|
||||||
const hname = fio.fiobj_str_new(util.toCharPtr(name), name.len);
|
const hname = fio.fiobj_str_new(util.toCharPtr(name), name.len);
|
||||||
defer fio.fiobj_free_wrapped(hname);
|
defer fio.fiobj_free_wrapped(hname);
|
||||||
// fio2str is OK since headers are always strings -> slice is returned
|
// fio2str is OK since headers are always strings -> slice is returned
|
||||||
|
@ -485,7 +485,7 @@ pub const HttpHeaderCommon = enum(usize) {
|
||||||
|
|
||||||
/// Returns the header value of a given common header key. Returned memory
|
/// Returns the header value of a given common header key. Returned memory
|
||||||
/// should not be freed.
|
/// should not be freed.
|
||||||
pub fn getHeaderCommon(self: *const Self, which: HttpHeaderCommon) ?[]const u8 {
|
pub fn getHeaderCommon(self: *const Request, which: HttpHeaderCommon) ?[]const u8 {
|
||||||
const field = switch (which) {
|
const field = switch (which) {
|
||||||
.accept => fio.HTTP_HEADER_ACCEPT,
|
.accept => fio.HTTP_HEADER_ACCEPT,
|
||||||
.cache_control => fio.HTTP_HEADER_CACHE_CONTROL,
|
.cache_control => fio.HTTP_HEADER_CACHE_CONTROL,
|
||||||
|
@ -510,7 +510,7 @@ pub fn getHeaderCommon(self: *const Self, which: HttpHeaderCommon) ?[]const u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set header.
|
/// Set header.
|
||||||
pub fn setHeader(self: *const Self, name: []const u8, value: []const u8) HttpError!void {
|
pub fn setHeader(self: *const Request, name: []const u8, value: []const u8) HttpError!void {
|
||||||
const hname: fio.fio_str_info_s = .{
|
const hname: fio.fio_str_info_s = .{
|
||||||
.data = util.toCharPtr(name),
|
.data = util.toCharPtr(name),
|
||||||
.len = name.len,
|
.len = name.len,
|
||||||
|
@ -538,12 +538,12 @@ pub fn setHeader(self: *const Self, name: []const u8, value: []const u8) HttpErr
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set status by numeric value.
|
/// Set status by numeric value.
|
||||||
pub fn setStatusNumeric(self: *const Self, status: usize) void {
|
pub fn setStatusNumeric(self: *const Request, status: usize) void {
|
||||||
self.h.*.status = status;
|
self.h.*.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set status by enum.
|
/// Set status by enum.
|
||||||
pub fn setStatus(self: *const Self, status: http.StatusCode) void {
|
pub fn setStatus(self: *const Request, status: http.StatusCode) void {
|
||||||
self.h.*.status = @as(usize, @intCast(@intFromEnum(status)));
|
self.h.*.status = @as(usize, @intCast(@intFromEnum(status)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ pub fn setStatus(self: *const Self, status: http.StatusCode) void {
|
||||||
///
|
///
|
||||||
/// Important: sets last-modified and cache-control headers with a max-age value of 1 hour!
|
/// Important: sets last-modified and cache-control headers with a max-age value of 1 hour!
|
||||||
/// You can override that by setting those headers yourself, e.g.: setHeader("Cache-Control", "no-cache")
|
/// You can override that by setting those headers yourself, e.g.: setHeader("Cache-Control", "no-cache")
|
||||||
pub fn sendFile(self: *const Self, file_path: []const u8) !void {
|
pub fn sendFile(self: *const Request, file_path: []const u8) !void {
|
||||||
if (fio.http_sendfile2(self.h, util.toCharPtr(file_path), file_path.len, null, 0) != 0)
|
if (fio.http_sendfile2(self.h, util.toCharPtr(file_path), file_path.len, null, 0) != 0)
|
||||||
return error.SendFile;
|
return error.SendFile;
|
||||||
self.markAsFinished(true);
|
self.markAsFinished(true);
|
||||||
|
@ -572,7 +572,7 @@ pub fn sendFile(self: *const Self, file_path: []const u8) !void {
|
||||||
/// - application/x-www-form-urlencoded
|
/// - application/x-www-form-urlencoded
|
||||||
/// - application/json
|
/// - application/json
|
||||||
/// - multipart/form-data
|
/// - multipart/form-data
|
||||||
pub fn parseBody(self: *const Self) HttpError!void {
|
pub fn parseBody(self: *const Request) HttpError!void {
|
||||||
if (fio.http_parse_body(self.h) == -1) return error.HttpParseBody;
|
if (fio.http_parse_body(self.h) == -1) return error.HttpParseBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,12 +581,12 @@ pub fn parseBody(self: *const Self) HttpError!void {
|
||||||
/// object that doesn't have a hash map at its root.
|
/// object that doesn't have a hash map at its root.
|
||||||
///
|
///
|
||||||
/// Result is accessible via parametersToOwnedSlice(), parametersToOwnedStrSlice()
|
/// Result is accessible via parametersToOwnedSlice(), parametersToOwnedStrSlice()
|
||||||
pub fn parseQuery(self: *const Self) void {
|
pub fn parseQuery(self: *const Request) void {
|
||||||
fio.http_parse_query(self.h);
|
fio.http_parse_query(self.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse received cookie headers
|
/// Parse received cookie headers
|
||||||
pub fn parseCookies(self: *const Self, url_encoded: bool) void {
|
pub fn parseCookies(self: *const Request, url_encoded: bool) void {
|
||||||
fio.http_parse_cookies(self.h, if (url_encoded) 1 else 0);
|
fio.http_parse_cookies(self.h, if (url_encoded) 1 else 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,7 +617,7 @@ pub const AcceptItem = struct {
|
||||||
const AcceptHeaderList = std.ArrayList(AcceptItem);
|
const AcceptHeaderList = std.ArrayList(AcceptItem);
|
||||||
|
|
||||||
/// Parses `Accept:` http header into `list`, ordered from highest q factor to lowest
|
/// Parses `Accept:` http header into `list`, ordered from highest q factor to lowest
|
||||||
pub fn parseAcceptHeaders(self: *const Self, allocator: Allocator) !AcceptHeaderList {
|
pub fn parseAcceptHeaders(self: *const Request, allocator: Allocator) !AcceptHeaderList {
|
||||||
const accept_str = self.getHeaderCommon(.accept) orelse return error.NoAcceptHeader;
|
const accept_str = self.getHeaderCommon(.accept) orelse return error.NoAcceptHeader;
|
||||||
|
|
||||||
const comma_count = std.mem.count(u8, accept_str, ",");
|
const comma_count = std.mem.count(u8, accept_str, ",");
|
||||||
|
@ -663,7 +663,7 @@ pub fn parseAcceptHeaders(self: *const Self, allocator: Allocator) !AcceptHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a response cookie
|
/// Set a response cookie
|
||||||
pub fn setCookie(self: *const Self, args: CookieArgs) HttpError!void {
|
pub fn setCookie(self: *const Request, args: CookieArgs) HttpError!void {
|
||||||
const c: fio.http_cookie_args_s = .{
|
const c: fio.http_cookie_args_s = .{
|
||||||
.name = util.toCharPtr(args.name),
|
.name = util.toCharPtr(args.name),
|
||||||
.name_len = @as(isize, @intCast(args.name.len)),
|
.name_len = @as(isize, @intCast(args.name.len)),
|
||||||
|
@ -692,7 +692,7 @@ pub fn setCookie(self: *const Self, args: CookieArgs) HttpError!void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns named cookie. Works like getParamStr().
|
/// Returns named cookie. Works like getParamStr().
|
||||||
pub fn getCookieStr(self: *const Self, a: Allocator, name: []const u8) !?[]const u8 {
|
pub fn getCookieStr(self: *const Request, a: Allocator, name: []const u8) !?[]const u8 {
|
||||||
if (self.h.*.cookies == 0) return null;
|
if (self.h.*.cookies == 0) return null;
|
||||||
const key = fio.fiobj_str_new(name.ptr, name.len);
|
const key = fio.fiobj_str_new(name.ptr, name.len);
|
||||||
defer fio.fiobj_free_wrapped(key);
|
defer fio.fiobj_free_wrapped(key);
|
||||||
|
@ -708,7 +708,7 @@ pub fn getCookieStr(self: *const Self, a: Allocator, name: []const u8) !?[]const
|
||||||
/// Returns the number of cookies after parsing.
|
/// Returns the number of cookies after parsing.
|
||||||
///
|
///
|
||||||
/// Parse with parseCookies()
|
/// Parse with parseCookies()
|
||||||
pub fn getCookiesCount(self: *const Self) isize {
|
pub fn getCookiesCount(self: *const Request) isize {
|
||||||
if (self.h.*.cookies == 0) return 0;
|
if (self.h.*.cookies == 0) return 0;
|
||||||
return fio.fiobj_obj2num(self.h.*.cookies);
|
return fio.fiobj_obj2num(self.h.*.cookies);
|
||||||
}
|
}
|
||||||
|
@ -716,7 +716,7 @@ pub fn getCookiesCount(self: *const Self) isize {
|
||||||
/// Returns the number of parameters after parsing.
|
/// Returns the number of parameters after parsing.
|
||||||
///
|
///
|
||||||
/// Parse with parseBody() and / or parseQuery()
|
/// Parse with parseBody() and / or parseQuery()
|
||||||
pub fn getParamCount(self: *const Self) isize {
|
pub fn getParamCount(self: *const Request) isize {
|
||||||
if (self.h.*.params == 0) return 0;
|
if (self.h.*.params == 0) return 0;
|
||||||
return fio.fiobj_obj2num(self.h.*.params);
|
return fio.fiobj_obj2num(self.h.*.params);
|
||||||
}
|
}
|
||||||
|
@ -727,7 +727,7 @@ const CallbackContext_KV = struct {
|
||||||
last_error: ?anyerror = null,
|
last_error: ?anyerror = null,
|
||||||
|
|
||||||
pub fn callback(fiobj_value: fio.FIOBJ, context_: ?*anyopaque) callconv(.C) c_int {
|
pub fn callback(fiobj_value: fio.FIOBJ, context_: ?*anyopaque) callconv(.C) c_int {
|
||||||
const ctx: *@This() = @as(*@This(), @ptrCast(@alignCast(context_)));
|
const ctx: *CallbackContext_KV = @as(*CallbackContext_KV, @ptrCast(@alignCast(context_)));
|
||||||
// this is thread-safe, guaranteed by fio
|
// this is thread-safe, guaranteed by fio
|
||||||
const fiobj_key: fio.FIOBJ = fio.fiobj_hash_key_in_loop();
|
const fiobj_key: fio.FIOBJ = fio.fiobj_hash_key_in_loop();
|
||||||
ctx.params.append(.{
|
ctx.params.append(.{
|
||||||
|
@ -756,7 +756,7 @@ const CallbackContext_StrKV = struct {
|
||||||
last_error: ?anyerror = null,
|
last_error: ?anyerror = null,
|
||||||
|
|
||||||
pub fn callback(fiobj_value: fio.FIOBJ, context_: ?*anyopaque) callconv(.C) c_int {
|
pub fn callback(fiobj_value: fio.FIOBJ, context_: ?*anyopaque) callconv(.C) c_int {
|
||||||
const ctx: *@This() = @as(*@This(), @ptrCast(@alignCast(context_)));
|
const ctx: *CallbackContext_StrKV = @as(*CallbackContext_StrKV, @ptrCast(@alignCast(context_)));
|
||||||
// this is thread-safe, guaranteed by fio
|
// this is thread-safe, guaranteed by fio
|
||||||
const fiobj_key: fio.FIOBJ = fio.fiobj_hash_key_in_loop();
|
const fiobj_key: fio.FIOBJ = fio.fiobj_hash_key_in_loop();
|
||||||
ctx.params.append(.{
|
ctx.params.append(.{
|
||||||
|
@ -780,7 +780,7 @@ const CallbackContext_StrKV = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Same as parametersToOwnedStrList() but for cookies
|
/// Same as parametersToOwnedStrList() but for cookies
|
||||||
pub fn cookiesToOwnedStrList(self: *const Self, a: Allocator) anyerror!HttpParamStrKVList {
|
pub fn cookiesToOwnedStrList(self: *const Request, a: Allocator) anyerror!HttpParamStrKVList {
|
||||||
var params = try std.ArrayList(HttpParamStrKV).initCapacity(a, @as(usize, @intCast(self.getCookiesCount())));
|
var params = try std.ArrayList(HttpParamStrKV).initCapacity(a, @as(usize, @intCast(self.getCookiesCount())));
|
||||||
var context: CallbackContext_StrKV = .{
|
var context: CallbackContext_StrKV = .{
|
||||||
.params = ¶ms,
|
.params = ¶ms,
|
||||||
|
@ -794,7 +794,7 @@ pub fn cookiesToOwnedStrList(self: *const Self, a: Allocator) anyerror!HttpParam
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as parametersToOwnedList() but for cookies
|
/// Same as parametersToOwnedList() but for cookies
|
||||||
pub fn cookiesToOwnedList(self: *const Self, a: Allocator) !HttpParamKVList {
|
pub fn cookiesToOwnedList(self: *const Request, a: Allocator) !HttpParamKVList {
|
||||||
var params = try std.ArrayList(HttpParamKV).initCapacity(a, @as(usize, @intCast(self.getCookiesCount())));
|
var params = try std.ArrayList(HttpParamKV).initCapacity(a, @as(usize, @intCast(self.getCookiesCount())));
|
||||||
var context: CallbackContext_KV = .{ .params = ¶ms, .allocator = a };
|
var context: CallbackContext_KV = .{ .params = ¶ms, .allocator = a };
|
||||||
const howmany = fio.fiobj_each1(self.h.*.cookies, 0, CallbackContext_KV.callback, &context);
|
const howmany = fio.fiobj_each1(self.h.*.cookies, 0, CallbackContext_KV.callback, &context);
|
||||||
|
@ -817,7 +817,7 @@ pub fn cookiesToOwnedList(self: *const Self, a: Allocator) !HttpParamKVList {
|
||||||
///
|
///
|
||||||
/// Requires parseBody() and/or parseQuery() have been called.
|
/// Requires parseBody() and/or parseQuery() have been called.
|
||||||
/// Returned list needs to be deinited.
|
/// Returned list needs to be deinited.
|
||||||
pub fn parametersToOwnedStrList(self: *const Self, a: Allocator) anyerror!HttpParamStrKVList {
|
pub fn parametersToOwnedStrList(self: *const Request, a: Allocator) anyerror!HttpParamStrKVList {
|
||||||
var params = try std.ArrayList(HttpParamStrKV).initCapacity(a, @as(usize, @intCast(self.getParamCount())));
|
var params = try std.ArrayList(HttpParamStrKV).initCapacity(a, @as(usize, @intCast(self.getParamCount())));
|
||||||
|
|
||||||
var context: CallbackContext_StrKV = .{
|
var context: CallbackContext_StrKV = .{
|
||||||
|
@ -845,7 +845,7 @@ pub fn parametersToOwnedStrList(self: *const Self, a: Allocator) anyerror!HttpPa
|
||||||
///
|
///
|
||||||
/// Requires parseBody() and/or parseQuery() have been called.
|
/// Requires parseBody() and/or parseQuery() have been called.
|
||||||
/// Returned slice needs to be freed.
|
/// Returned slice needs to be freed.
|
||||||
pub fn parametersToOwnedList(self: *const Self, a: Allocator) !HttpParamKVList {
|
pub fn parametersToOwnedList(self: *const Request, a: Allocator) !HttpParamKVList {
|
||||||
var params = try std.ArrayList(HttpParamKV).initCapacity(a, @as(usize, @intCast(self.getParamCount())));
|
var params = try std.ArrayList(HttpParamKV).initCapacity(a, @as(usize, @intCast(self.getParamCount())));
|
||||||
|
|
||||||
var context: CallbackContext_KV = .{ .params = ¶ms, .allocator = a };
|
var context: CallbackContext_KV = .{ .params = ¶ms, .allocator = a };
|
||||||
|
@ -870,7 +870,7 @@ pub fn parametersToOwnedList(self: *const Self, a: Allocator) !HttpParamKVList {
|
||||||
///
|
///
|
||||||
/// Requires parseBody() and/or parseQuery() have been called.
|
/// Requires parseBody() and/or parseQuery() have been called.
|
||||||
/// The returned string needs to be deallocated.
|
/// The returned string needs to be deallocated.
|
||||||
pub fn getParamStr(self: *const Self, a: Allocator, name: []const u8) !?[]const u8 {
|
pub fn getParamStr(self: *const Request, a: Allocator, name: []const u8) !?[]const u8 {
|
||||||
if (self.h.*.params == 0) return null;
|
if (self.h.*.params == 0) return null;
|
||||||
const key = fio.fiobj_str_new(name.ptr, name.len);
|
const key = fio.fiobj_str_new(name.ptr, name.len);
|
||||||
defer fio.fiobj_free_wrapped(key);
|
defer fio.fiobj_free_wrapped(key);
|
||||||
|
@ -885,7 +885,7 @@ pub fn getParamStr(self: *const Self, a: Allocator, name: []const u8) !?[]const
|
||||||
/// after the equals sign, non-decoded, and always as character slice.
|
/// after the equals sign, non-decoded, and always as character slice.
|
||||||
/// - no allocation!
|
/// - no allocation!
|
||||||
/// - does not requre parseQuery() or anything to be called in advance
|
/// - does not requre parseQuery() or anything to be called in advance
|
||||||
pub fn getParamSlice(self: *const Self, name: []const u8) ?[]const u8 {
|
pub fn getParamSlice(self: *const Request, name: []const u8) ?[]const u8 {
|
||||||
if (self.query) |query| {
|
if (self.query) |query| {
|
||||||
var amp_it = std.mem.tokenizeScalar(u8, query, '&');
|
var amp_it = std.mem.tokenizeScalar(u8, query, '&');
|
||||||
while (amp_it.next()) |maybe_pair| {
|
while (amp_it.next()) |maybe_pair| {
|
||||||
|
@ -908,13 +908,13 @@ pub const ParameterSlices = struct { name: []const u8, value: []const u8 };
|
||||||
pub const ParamSliceIterator = struct {
|
pub const ParamSliceIterator = struct {
|
||||||
amp_it: std.mem.TokenIterator(u8, .scalar),
|
amp_it: std.mem.TokenIterator(u8, .scalar),
|
||||||
|
|
||||||
pub fn init(query: []const u8) @This() {
|
pub fn init(query: []const u8) ParamSliceIterator {
|
||||||
return .{
|
return .{
|
||||||
.amp_it = std.mem.tokenizeScalar(u8, query, '&'),
|
.amp_it = std.mem.tokenizeScalar(u8, query, '&'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(self: *@This()) ?ParameterSlices {
|
pub fn next(self: *ParamSliceIterator) ?ParameterSlices {
|
||||||
while (self.amp_it.next()) |maybe_pair| {
|
while (self.amp_it.next()) |maybe_pair| {
|
||||||
if (std.mem.indexOfScalar(u8, maybe_pair, '=')) |pos_of_eq| {
|
if (std.mem.indexOfScalar(u8, maybe_pair, '=')) |pos_of_eq| {
|
||||||
const pname = maybe_pair[0..pos_of_eq];
|
const pname = maybe_pair[0..pos_of_eq];
|
||||||
|
@ -931,11 +931,11 @@ pub const ParamSliceIterator = struct {
|
||||||
/// Returns an iterator that yields all query parameters on next() in the
|
/// Returns an iterator that yields all query parameters on next() in the
|
||||||
/// form of a ParameterSlices struct { .name, .value }
|
/// form of a ParameterSlices struct { .name, .value }
|
||||||
/// As with getParamSlice(), the value is not decoded
|
/// As with getParamSlice(), the value is not decoded
|
||||||
pub fn getParamSlices(self: *const Self) ParamSliceIterator {
|
pub fn getParamSlices(self: *const Request) ParamSliceIterator {
|
||||||
const query = self.query orelse "";
|
const query = self.query orelse "";
|
||||||
return ParamSliceIterator.init(query);
|
return ParamSliceIterator.init(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn methodAsEnum(self: *const Self) http.Method {
|
pub fn methodAsEnum(self: *const Request) http.Method {
|
||||||
return http.methodToEnum(self.method);
|
return http.methodToEnum(self.method);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@ const RouterError = error{
|
||||||
EmptyPath,
|
EmptyPath,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Self = @This();
|
const Router = @This();
|
||||||
|
|
||||||
/// This is a singleton
|
/// This is a singleton
|
||||||
var _instance: *Self = undefined;
|
var _instance: *Router = undefined;
|
||||||
|
|
||||||
/// Options to pass to init()
|
/// Options to pass to init()
|
||||||
pub const Options = struct {
|
pub const Options = struct {
|
||||||
|
@ -31,7 +31,7 @@ routes: std.StringHashMap(Callback),
|
||||||
not_found: ?zap.HttpRequestFn,
|
not_found: ?zap.HttpRequestFn,
|
||||||
|
|
||||||
/// Create a new Router
|
/// Create a new Router
|
||||||
pub fn init(allocator: Allocator, options: Options) Self {
|
pub fn init(allocator: Allocator, options: Options) Router {
|
||||||
return .{
|
return .{
|
||||||
.routes = std.StringHashMap(Callback).init(allocator),
|
.routes = std.StringHashMap(Callback).init(allocator),
|
||||||
|
|
||||||
|
@ -40,12 +40,12 @@ pub fn init(allocator: Allocator, options: Options) Self {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deinit the router
|
/// Deinit the router
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Router) void {
|
||||||
self.routes.deinit();
|
self.routes.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call this to add a route with an unbound handler: a handler that is not member of a struct.
|
/// Call this to add a route with an unbound handler: a handler that is not member of a struct.
|
||||||
pub fn handle_func_unbound(self: *Self, path: []const u8, h: zap.HttpRequestFn) !void {
|
pub fn handle_func_unbound(self: *Router, path: []const u8, h: zap.HttpRequestFn) !void {
|
||||||
if (path.len == 0) {
|
if (path.len == 0) {
|
||||||
return RouterError.EmptyPath;
|
return RouterError.EmptyPath;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ pub fn handle_func_unbound(self: *Self, path: []const u8, h: zap.HttpRequestFn)
|
||||||
///
|
///
|
||||||
/// my_router.handle_func("/getA", &handler_instance, HandlerType.getA);
|
/// my_router.handle_func("/getA", &handler_instance, HandlerType.getA);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn handle_func(self: *Self, path: []const u8, instance: *anyopaque, handler: anytype) !void {
|
pub fn handle_func(self: *Router, path: []const u8, instance: *anyopaque, handler: anytype) !void {
|
||||||
// TODO: assert type of instance has handler
|
// TODO: assert type of instance has handler
|
||||||
|
|
||||||
if (path.len == 0) {
|
if (path.len == 0) {
|
||||||
|
@ -89,7 +89,7 @@ pub fn handle_func(self: *Self, path: []const u8, instance: *anyopaque, handler:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the zap request handler function needed for a listener
|
/// Get the zap request handler function needed for a listener
|
||||||
pub fn on_request_handler(self: *Self) zap.HttpRequestFn {
|
pub fn on_request_handler(self: *Router) zap.HttpRequestFn {
|
||||||
_instance = self;
|
_instance = self;
|
||||||
return zap_on_request;
|
return zap_on_request;
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ fn zap_on_request(r: zap.Request) !void {
|
||||||
return serve(_instance, r);
|
return serve(_instance, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serve(self: *Self, r: zap.Request) !void {
|
fn serve(self: *Router, r: zap.Request) !void {
|
||||||
const path = r.path orelse "/";
|
const path = r.path orelse "/";
|
||||||
|
|
||||||
if (self.routes.get(path)) |routeInfo| {
|
if (self.routes.get(path)) |routeInfo| {
|
||||||
|
|
|
@ -42,7 +42,6 @@ test "http parameters" {
|
||||||
params = r.parametersToOwnedList(alloc) catch unreachable;
|
params = r.parametersToOwnedList(alloc) catch unreachable;
|
||||||
|
|
||||||
paramOneStr = r.getParamStr(alloc, "one") catch unreachable;
|
paramOneStr = r.getParamStr(alloc, "one") catch unreachable;
|
||||||
std.debug.print("\n\nparamOneStr = {s} = {*} \n\n", .{ paramOneStr.?, paramOneStr.?.ptr });
|
|
||||||
|
|
||||||
// we need to dupe it here because the request object r will get
|
// we need to dupe it here because the request object r will get
|
||||||
// invalidated at the end of the function but we need to check
|
// invalidated at the end of the function but we need to check
|
||||||
|
|
19
src/zap.zig
19
src/zap.zig
|
@ -170,11 +170,10 @@ pub const HttpListenerSettings = struct {
|
||||||
pub const HttpListener = struct {
|
pub const HttpListener = struct {
|
||||||
settings: HttpListenerSettings,
|
settings: HttpListenerSettings,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
var the_one_and_only_listener: ?*HttpListener = null;
|
var the_one_and_only_listener: ?*HttpListener = null;
|
||||||
|
|
||||||
/// Create a listener
|
/// Create a listener
|
||||||
pub fn init(settings: HttpListenerSettings) Self {
|
pub fn init(settings: HttpListenerSettings) HttpListener {
|
||||||
std.debug.assert(settings.on_request != null);
|
std.debug.assert(settings.on_request != null);
|
||||||
return .{
|
return .{
|
||||||
.settings = settings,
|
.settings = settings,
|
||||||
|
@ -264,7 +263,7 @@ pub const HttpListener = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start listening
|
/// Start listening
|
||||||
pub fn listen(self: *Self) !void {
|
pub fn listen(self: *HttpListener) !void {
|
||||||
var pfolder: [*c]const u8 = null;
|
var pfolder: [*c]const u8 = null;
|
||||||
var pfolder_len: usize = 0;
|
var pfolder_len: usize = 0;
|
||||||
|
|
||||||
|
@ -275,10 +274,10 @@ pub const HttpListener = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const x: fio.http_settings_s = .{
|
const x: fio.http_settings_s = .{
|
||||||
.on_request = if (self.settings.on_request) |_| Self.theOneAndOnlyRequestCallBack else null,
|
.on_request = if (self.settings.on_request) |_| HttpListener.theOneAndOnlyRequestCallBack else null,
|
||||||
.on_upgrade = if (self.settings.on_upgrade) |_| Self.theOneAndOnlyUpgradeCallBack else null,
|
.on_upgrade = if (self.settings.on_upgrade) |_| HttpListener.theOneAndOnlyUpgradeCallBack else null,
|
||||||
.on_response = if (self.settings.on_response) |_| Self.theOneAndOnlyResponseCallBack else null,
|
.on_response = if (self.settings.on_response) |_| HttpListener.theOneAndOnlyResponseCallBack else null,
|
||||||
.on_finish = if (self.settings.on_finish) |_| Self.theOneAndOnlyFinishCallBack else null,
|
.on_finish = if (self.settings.on_finish) |_| HttpListener.theOneAndOnlyFinishCallBack else null,
|
||||||
.udata = null,
|
.udata = null,
|
||||||
.public_folder = pfolder,
|
.public_folder = pfolder,
|
||||||
.public_folder_length = pfolder_len,
|
.public_folder_length = pfolder_len,
|
||||||
|
@ -316,7 +315,7 @@ pub const HttpListener = struct {
|
||||||
// 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
|
||||||
Self.the_one_and_only_listener = self;
|
HttpListener.the_one_and_only_listener = self;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -336,10 +335,8 @@ pub const LowLevel = struct {
|
||||||
keepalive_timeout_s: u8 = 5,
|
keepalive_timeout_s: u8 = 5,
|
||||||
log: bool = false,
|
log: bool = false,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
/// Create settings with defaults
|
/// Create settings with defaults
|
||||||
pub fn init() Self {
|
pub fn init() ListenSettings {
|
||||||
return .{};
|
return .{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue