1
0
Fork 0
mirror of https://github.com/zigzap/zap.git synced 2025-10-21 15:44:10 +00:00
This commit is contained in:
Tadej Gašparovič 2025-09-17 17:27:36 +00:00 committed by GitHub
commit 7d168de031
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 74 additions and 79 deletions

View file

@ -354,12 +354,12 @@ pub fn _internal_sendError(self: *const Request, err: anyerror, err_trace: ?std.
// 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;
var buf: [20 * 1024]u8 = undefined; var buf: [20 * 1024]u8 = undefined;
var writer = std.io.Writer.fixed(&buf); var writer = std.Io.Writer.fixed(&buf);
try writer.print("ERROR: {any}\n\n", .{err}); try writer.print("ERROR: {any}\n\n", .{err});
if (err_trace) |trace| { if (err_trace) |trace| {
const debugInfo = try std.debug.getSelfDebugInfo(); const debugInfo = try std.debug.getSelfDebugInfo();
const ttyConfig: std.io.tty.Config = .no_color; const ttyConfig: std.Io.tty.Config = .no_color;
try std.debug.writeStackTrace(trace, &writer, debugInfo, ttyConfig); try std.debug.writeStackTrace(trace, &writer, debugInfo, ttyConfig);
} }

View file

@ -18,7 +18,7 @@ fn makeRequest(a: std.mem.Allocator, url: []const u8) !void {
var http_client: std.http.Client = .{ .allocator = a }; var http_client: std.http.Client = .{ .allocator = a };
defer http_client.deinit(); defer http_client.deinit();
var response_writer = std.io.Writer.Allocating.init(a); var response_writer = std.Io.Writer.Allocating.init(a);
defer response_writer.deinit(); defer response_writer.deinit();
_ = try http_client.fetch(.{ _ = try http_client.fetch(.{

View file

@ -77,7 +77,7 @@ pub fn stringifyBuf(
value: anytype, value: anytype,
options: std.json.Stringify.Options, options: std.json.Stringify.Options,
) ![]const u8 { ) ![]const u8 {
var w: std.io.Writer = .fixed(buffer); var w: std.Io.Writer = .fixed(buffer);
if (std.json.Stringify.value(value, options, &w)) { if (std.json.Stringify.value(value, options, &w)) {
return w.buffered(); return w.buffered();
} else |err| { // error } else |err| { // error

View file

@ -140,8 +140,8 @@ pub const HttpListenerSettings = struct {
on_response: ?HttpRequestFn = null, on_response: ?HttpRequestFn = null,
on_upgrade: ?HttpUpgradeFn = null, on_upgrade: ?HttpUpgradeFn = null,
on_finish: ?HttpFinishFn = null, on_finish: ?HttpFinishFn = null,
// provide any pointer in there for "user data". it will be passed pack in /// User defined data can be extracted in a request handler using `Request.getUserContext(T)`
// on_finish()'s copy of the struct_http_settings_s /// In `on_finish()` it can be extracted using `HttpListener.getUserContext(T, fio.struct_http_settings_s.udata.?)`
udata: ?*anyopaque = null, udata: ?*anyopaque = null,
public_folder: ?[]const u8 = null, public_folder: ?[]const u8 = null,
max_clients: ?isize = null, max_clients: ?isize = null,
@ -156,21 +156,27 @@ pub const HttpListenerSettings = struct {
/// Http listener /// Http listener
pub const HttpListener = struct { pub const HttpListener = struct {
settings: HttpListenerSettings, settings: HttpListenerSettings,
userData: ?*anyopaque,
var the_one_and_only_listener: ?*HttpListener = null; const Self = @This();
/// Create a listener /// Create a listener
pub fn init(settings: HttpListenerSettings) HttpListener { 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,
.userData = settings.udata,
}; };
} }
// we could make it dynamic by passing a HttpListener via udata pub fn getUserContext(comptime T: type, udata: *anyopaque) ?*T {
const self: *Self = @ptrCast(@alignCast(udata));
return @ptrCast(@alignCast(self.userData));
}
/// Used internally: the listener's facilio request callback /// Used internally: the listener's facilio request callback
pub fn theOneAndOnlyRequestCallBack(r: [*c]fio.http_s) callconv(.c) void { pub fn theOneAndOnlyRequestCallBack(r: [*c]fio.http_s) callconv(.c) void {
if (the_one_and_only_listener) |l| { const self: *Self = @ptrCast(@alignCast(r.*.udata.?));
var req: Request = .{ var req: Request = .{
.path = util.fio2str(r.*.path), .path = util.fio2str(r.*.path),
.query = util.fio2str(r.*.query), .query = util.fio2str(r.*.query),
@ -182,22 +188,21 @@ pub const HttpListener = struct {
}; };
req._is_finished = &req._is_finished_request_global; req._is_finished = &req._is_finished_request_global;
var user_context: Request.UserContext = .{}; var user_context: Request.UserContext = .{ .user_context = self.userData };
req._user_context = &user_context; req._user_context = &user_context;
req.markAsFinished(false); req.markAsFinished(false);
std.debug.assert(l.settings.on_request != null); std.debug.assert(self.settings.on_request != null);
if (l.settings.on_request) |on_request| { if (self.settings.on_request) |on_request| {
on_request(req) catch |err| { on_request(req) catch |err| {
Logging.on_uncaught_error("HttpListener on_request", err); Logging.on_uncaught_error("HttpListener on_request", err);
}; };
} }
} }
}
/// Used internally: the listener's facilio response callback /// Used internally: the listener's facilio response callback
pub fn theOneAndOnlyResponseCallBack(r: [*c]fio.http_s) callconv(.c) void { pub fn theOneAndOnlyResponseCallBack(r: [*c]fio.http_s) callconv(.c) void {
if (the_one_and_only_listener) |l| { const self: *Self = @ptrCast(@alignCast(r.*.udata.?));
var req: Request = .{ var req: Request = .{
.path = util.fio2str(r.*.path), .path = util.fio2str(r.*.path),
.query = util.fio2str(r.*.query), .query = util.fio2str(r.*.query),
@ -209,18 +214,17 @@ pub const HttpListener = struct {
}; };
req._is_finished = &req._is_finished_request_global; req._is_finished = &req._is_finished_request_global;
var user_context: Request.UserContext = .{}; var user_context: Request.UserContext = .{ .user_context = self.userData };
req._user_context = &user_context; req._user_context = &user_context;
l.settings.on_response.?(req) catch |err| { self.settings.on_response.?(req) catch |err| {
Logging.on_uncaught_error("HttpListener on_response", err); Logging.on_uncaught_error("HttpListener on_response", err);
}; };
} }
}
/// Used internally: the listener's facilio upgrade callback /// Used internally: the listener's facilio upgrade callback
pub fn theOneAndOnlyUpgradeCallBack(r: [*c]fio.http_s, target: [*c]u8, target_len: usize) callconv(.c) void { pub fn theOneAndOnlyUpgradeCallBack(r: [*c]fio.http_s, target: [*c]u8, target_len: usize) callconv(.c) void {
if (the_one_and_only_listener) |l| { const self: *Self = @ptrCast(@alignCast(r.*.udata.?));
var req: Request = .{ var req: Request = .{
.path = util.fio2str(r.*.path), .path = util.fio2str(r.*.path),
.query = util.fio2str(r.*.query), .query = util.fio2str(r.*.query),
@ -233,23 +237,21 @@ pub const HttpListener = struct {
const zigtarget: []u8 = target[0..target_len]; const zigtarget: []u8 = target[0..target_len];
req._is_finished = &req._is_finished_request_global; req._is_finished = &req._is_finished_request_global;
var user_context: Request.UserContext = .{}; var user_context: Request.UserContext = .{ .user_context = self.userData };
req._user_context = &user_context; req._user_context = &user_context;
l.settings.on_upgrade.?(req, zigtarget) catch |err| { self.settings.on_upgrade.?(req, zigtarget) catch |err| {
Logging.on_uncaught_error("HttpListener on_upgrade", err); Logging.on_uncaught_error("HttpListener on_upgrade", err);
}; };
} }
}
/// Used internally: the listener's facilio finish callback /// Used internally: the listener's facilio finish callback
pub fn theOneAndOnlyFinishCallBack(s: [*c]fio.struct_http_settings_s) callconv(.c) void { pub fn theOneAndOnlyFinishCallBack(s: [*c]fio.struct_http_settings_s) callconv(.c) void {
if (the_one_and_only_listener) |l| { const self: *Self = @ptrCast(@alignCast(s.*.udata.?));
l.settings.on_finish.?(s) catch |err| { self.settings.on_finish.?(s) catch |err| {
Logging.on_uncaught_error("HttpListener on_finish", err); Logging.on_uncaught_error("HttpListener on_finish", err);
}; };
} }
}
/// Start listening /// Start listening
pub fn listen(self: *HttpListener) !void { pub fn listen(self: *HttpListener) !void {
@ -267,7 +269,7 @@ pub const HttpListener = struct {
.on_upgrade = if (self.settings.on_upgrade) |_| HttpListener.theOneAndOnlyUpgradeCallBack else null, .on_upgrade = if (self.settings.on_upgrade) |_| HttpListener.theOneAndOnlyUpgradeCallBack else null,
.on_response = if (self.settings.on_response) |_| HttpListener.theOneAndOnlyResponseCallBack else null, .on_response = if (self.settings.on_response) |_| HttpListener.theOneAndOnlyResponseCallBack else null,
.on_finish = if (self.settings.on_finish) |_| HttpListener.theOneAndOnlyFinishCallBack else null, .on_finish = if (self.settings.on_finish) |_| HttpListener.theOneAndOnlyFinishCallBack else null,
.udata = null, .udata = self,
.public_folder = pfolder, .public_folder = pfolder,
.public_folder_length = pfolder_len, .public_folder_length = pfolder_len,
.max_header_size = 32 * 1024, .max_header_size = 32 * 1024,
@ -297,14 +299,6 @@ pub const HttpListener = struct {
if (ret == -1) { if (ret == -1) {
return error.ListenError; return error.ListenError;
} }
// set ourselves up to handle requests:
// TODO: do we mind the race condition?
// the HttpRequestFn will check if this is null and not process
// the request if it isn't set. hence, if started under full load, the
// first request(s) might not be serviced, as long as it takes from
// fio.http_listen() to here
HttpListener.the_one_and_only_listener = self;
} }
}; };
@ -323,6 +317,7 @@ pub const LowLevel = struct {
max_clients: isize = 100, max_clients: isize = 100,
keepalive_timeout_s: u8 = 5, keepalive_timeout_s: u8 = 5,
log: bool = false, log: bool = false,
udata: ?*anyopaque = null,
/// Create settings with defaults /// Create settings with defaults
pub fn init() ListenSettings { pub fn init() ListenSettings {
@ -344,7 +339,7 @@ pub const LowLevel = struct {
.on_upgrade = settings.on_upgrade, .on_upgrade = settings.on_upgrade,
.on_response = settings.on_response, .on_response = settings.on_response,
.on_finish = settings.on_finish, .on_finish = settings.on_finish,
.udata = null, .udata = settings.udata,
.public_folder = pfolder, .public_folder = pfolder,
.public_folder_length = pfolder_len, .public_folder_length = pfolder_len,
.max_header_size = settings.max_header_size, .max_header_size = settings.max_header_size,