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

harmonize callback function error handling, zap logging; doc updates

This commit is contained in:
renerocksai 2025-04-01 09:43:03 +02:00
parent e93e45de42
commit 8d187310c7
19 changed files with 222 additions and 183 deletions

View file

@ -7,6 +7,14 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
const Handler = struct { const Handler = struct {
var alloc: std.mem.Allocator = undefined; var alloc: std.mem.Allocator = undefined;
@ -100,7 +108,7 @@ pub fn main() !void {
.public_folder = ".", .public_folder = ".",
}, },
); );
zap.enableDebugLog();
try listener.listen(); try listener.listen();
std.log.info("\n\nURL is http://localhost:3000\n", .{}); std.log.info("\n\nURL is http://localhost:3000\n", .{});
std.log.info("\ncurl -v --request POST -F img=@test012345.bin http://127.0.0.1:3000\n", .{}); std.log.info("\ncurl -v --request POST -F img=@test012345.bin http://127.0.0.1:3000\n", .{});

View file

@ -7,6 +7,14 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
// We send ourselves a request with a cookie // We send ourselves a request with a cookie
fn makeRequest(a: std.mem.Allocator, url: []const u8) !void { fn makeRequest(a: std.mem.Allocator, url: []const u8) !void {
const uri = try std.Uri.parse(url); const uri = try std.Uri.parse(url);
@ -113,7 +121,6 @@ pub fn main() !void {
.max_body_size = 1 * 1024, .max_body_size = 1 * 1024,
}, },
); );
zap.enableDebugLog();
try listener.listen(); try listener.listen();
std.log.info("\n\nTerminate with CTRL+C", .{}); std.log.info("\n\nTerminate with CTRL+C", .{});

View file

@ -7,6 +7,14 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
// We send ourselves a request // We send ourselves a request
fn makeRequest(a: std.mem.Allocator, url: []const u8) !void { fn makeRequest(a: std.mem.Allocator, url: []const u8) !void {
const uri = try std.Uri.parse(url); const uri = try std.Uri.parse(url);
@ -127,7 +135,7 @@ pub fn main() !void {
.max_body_size = 1 * 1024, .max_body_size = 1 * 1024,
}, },
); );
zap.enableDebugLog();
try listener.listen(); try listener.listen();
std.log.info("\n\nTerminate with CTRL+C or by sending query param terminate=true\n", .{}); std.log.info("\n\nTerminate with CTRL+C or by sending query param terminate=true\n", .{});

View file

@ -7,6 +7,14 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
// just a way to share our allocator via callback // just a way to share our allocator via callback
const SharedAllocator = struct { const SharedAllocator = struct {
// static // static
@ -212,7 +220,7 @@ pub fn main() !void {
userHandler.getHandler(), userHandler.getHandler(),
SharedAllocator.getAllocator, SharedAllocator.getAllocator,
); );
zap.enableDebugLog();
listener.listen() catch |err| { listener.listen() catch |err| {
std.debug.print("\nLISTEN ERROR: {any}\n", .{err}); std.debug.print("\nLISTEN ERROR: {any}\n", .{err});
return; return;

View file

@ -7,6 +7,14 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
// just a way to share our allocator via callback // just a way to share our allocator via callback
const SharedAllocator = struct { const SharedAllocator = struct {
// static // static
@ -224,7 +232,7 @@ pub fn main() !void {
userHandler.getHandler(), userHandler.getHandler(),
SharedAllocator.getAllocator, SharedAllocator.getAllocator,
); );
zap.enableDebugLog();
listener.listen() catch |err| { listener.listen() catch |err| {
std.debug.print("\nLISTEN ERROR: {any}\n", .{err}); std.debug.print("\nLISTEN ERROR: {any}\n", .{err});
return; return;

View file

@ -8,6 +8,14 @@ const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
const Mustache = @import("zap").Mustache; const Mustache = @import("zap").Mustache;
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
fn on_request(r: zap.Request) !void { fn on_request(r: zap.Request) !void {
const template = const template =
\\ {{=<< >>=}} \\ {{=<< >>=}}
@ -63,12 +71,9 @@ pub fn main() !void {
}); });
try listener.listen(); try listener.listen();
// zap.enableDebugLog();
// zap.debug("ZAP debug logging is on\n", .{});
// we can also use facilio logging // we can also use facilio logging
// zap.Log.fio_set_log_level(zap.Log.fio_log_level_debug); // zap.Logging.fio_set_log_level(zap.Log.fio_log_level_debug);
// zap.Log.fio_log_debug("hello from fio\n"); // zap.Logging.fio_log_debug("hello from fio\n");
std.debug.print("Listening on 0.0.0.0:3000\n", .{}); std.debug.print("Listening on 0.0.0.0:3000\n", .{});

View file

@ -7,6 +7,14 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
var buffer: [1024]u8 = undefined; var buffer: [1024]u8 = undefined;
var read_len: ?usize = null; var read_len: ?usize = null;
@ -43,7 +51,6 @@ pub fn main() !void {
}, },
); );
zap.enableDebugLog();
try listener.listen(); try listener.listen();
std.debug.print("Visit me on http://127.0.0.1:3000\n", .{}); std.debug.print("Visit me on http://127.0.0.1:3000\n", .{});

View file

@ -7,6 +7,14 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
const Lookup = std.StringHashMap([]const u8); const Lookup = std.StringHashMap([]const u8);
const auth_lock_pw_table = false; const auth_lock_pw_table = false;
@ -140,8 +148,6 @@ pub fn main() !void {
}); });
try listener.listen(); try listener.listen();
zap.enableDebugLog();
// Usernames -> Passwords for the /login page // Usernames -> Passwords for the /login page
// ------------------------------------------ // ------------------------------------------
var userpass = Lookup.init(allocator); var userpass = Lookup.init(allocator);

View file

@ -81,20 +81,17 @@ const ContextManager = struct {
// //
// Websocket Callbacks // Websocket Callbacks
// //
fn on_open_websocket(context: ?*Context, handle: WebSockets.WsHandle) void { fn on_open_websocket(context: ?*Context, handle: WebSockets.WsHandle) !void {
if (context) |ctx| { if (context) |ctx| {
_ = WebsocketHandler.subscribe(handle, &ctx.subscribeArgs) catch |err| { _ = try WebsocketHandler.subscribe(handle, &ctx.subscribeArgs);
std.log.err("Error opening websocket: {any}", .{err});
return;
};
// say hello // say hello
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
const message = std.fmt.bufPrint( const message = try std.fmt.bufPrint(
&buf, &buf,
"{s} joined the chat.", "{s} joined the chat.",
.{ctx.userName}, .{ctx.userName},
) catch unreachable; );
// send notification to all others // send notification to all others
WebsocketHandler.publish(.{ .channel = ctx.channel, .message = message }); WebsocketHandler.publish(.{ .channel = ctx.channel, .message = message });
@ -102,16 +99,16 @@ fn on_open_websocket(context: ?*Context, handle: WebSockets.WsHandle) void {
} }
} }
fn on_close_websocket(context: ?*Context, uuid: isize) void { fn on_close_websocket(context: ?*Context, uuid: isize) !void {
_ = uuid; _ = uuid;
if (context) |ctx| { if (context) |ctx| {
// say goodbye // say goodbye
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
const message = std.fmt.bufPrint( const message = try std.fmt.bufPrint(
&buf, &buf,
"{s} left the chat.", "{s} left the chat.",
.{ctx.userName}, .{ctx.userName},
) catch unreachable; );
// send notification to all others // send notification to all others
WebsocketHandler.publish(.{ .channel = ctx.channel, .message = message }); WebsocketHandler.publish(.{ .channel = ctx.channel, .message = message });
@ -124,7 +121,7 @@ fn handle_websocket_message(
handle: WebSockets.WsHandle, handle: WebSockets.WsHandle,
message: []const u8, message: []const u8,
is_text: bool, is_text: bool,
) void { ) !void {
_ = handle; _ = handle;
_ = is_text; _ = is_text;
@ -145,11 +142,11 @@ fn handle_websocket_message(
if (message.len > max_msg_len) { if (message.len > max_msg_len) {
trimmed_message = message[0..max_msg_len]; trimmed_message = message[0..max_msg_len];
} }
const chat_message = std.fmt.bufPrint( const chat_message = try std.fmt.bufPrint(
&buf, &buf,
format_string, format_string,
.{ ctx.userName, trimmed_message }, .{ ctx.userName, trimmed_message },
) catch unreachable; );
// send notification to all others // send notification to all others
WebsocketHandler.publish( WebsocketHandler.publish(
@ -169,7 +166,7 @@ fn handle_websocket_message(
// HTTP stuff // HTTP stuff
// //
fn on_request(r: zap.Request) !void { fn on_request(r: zap.Request) !void {
r.setHeader("Server", "zap.example") catch unreachable; try r.setHeader("Server", "zap.example");
try r.sendBody( try r.sendBody(
\\ <html><body> \\ <html><body>
\\ <h1>This is a simple Websocket chatroom example</h1> \\ <h1>This is a simple Websocket chatroom example</h1>
@ -177,7 +174,7 @@ fn on_request(r: zap.Request) !void {
); );
} }
fn on_upgrade(r: zap.Request, target_protocol: []const u8) void { fn on_upgrade(r: zap.Request, target_protocol: []const u8) !void {
// make sure we're talking the right protocol // make sure we're talking the right protocol
if (!std.mem.eql(u8, target_protocol, "websocket")) { if (!std.mem.eql(u8, target_protocol, "websocket")) {
std.log.warn("received illegal protocol: {s}", .{target_protocol}); std.log.warn("received illegal protocol: {s}", .{target_protocol});
@ -190,10 +187,7 @@ fn on_upgrade(r: zap.Request, target_protocol: []const u8) void {
return; return;
}; };
WebsocketHandler.upgrade(r.h, &context.settings) catch |err| { try WebsocketHandler.upgrade(r.h, &context.settings);
std.log.err("Error in websocketUpgrade(): {any}", .{err});
return;
};
std.log.info("connection upgrade OK", .{}); std.log.info("connection upgrade OK", .{});
} }

View file

@ -1,3 +1,16 @@
//! zap.App takes the zap.Endpoint concept one step further: instead of having
//! only per-endpoint instance data (fields of your Endpoint struct), endpoints
//! in a zap.App easily share a global 'App Context'.
//!
//! In addition to the global App Context, all Endpoint request handlers also
//! receive an arena allocator for easy, care-free allocations. There is one
//! arena allocator per thread, and arenas are reset after each request.
//!
//! Just like regular / legacy zap.Endpoints, returning errors from request
//! handlers is OK. It's decided on a per-endpoint basis how errors are dealt
//! with, via the ErrorStrategy enum field.
//!
//! See `App.Create()`.
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator; const ArenaAllocator = std.heap.ArenaAllocator;
@ -16,7 +29,10 @@ pub const AppOpts = struct {
}; };
/// creates an App with custom app context /// creates an App with custom app context
pub fn Create(comptime Context: type) type { pub fn Create(
/// Your user-defined "Global App Context" type
comptime Context: type,
) type {
return struct { return struct {
const App = @This(); const App = @This();
@ -336,7 +352,6 @@ pub fn Create(comptime Context: type) type {
var it = _static.track_arenas.valueIterator(); var it = _static.track_arenas.valueIterator();
while (it.next()) |arena| { while (it.next()) |arena| {
// std.debug.print("deiniting arena: {*}\n", .{arena});
arena.deinit(); arena.deinit();
} }
_static.track_arenas.deinit(_static.gpa); _static.track_arenas.deinit(_static.gpa);

View file

@ -1,23 +1,18 @@
const std = @import("std"); //! Access to facil.io's logging facilities
//!
// TODO: rework logging in zap //! Zap uses Zig's standard logging facilities, which you can control like this:
//!
debugOn: bool, //! ```zig
//! pub const std_options: std.Options = .{
/// Access to facil.io's logging facilities //! // general log level
const Log = @This(); //! .log_level = .info,
//! .log_scope_levels = &[_]std.log.ScopeLevel{
pub fn init(comptime debug: bool) Log { //! // log level specific to zap
return .{ //! .{ .scope = .zap, .level = .debug },
.debugOn = debug, //! },
}; //! };
} //! ```
const Logging = @This();
pub fn log(self: *const Log, comptime fmt: []const u8, args: anytype) void {
if (self.debugOn) {
std.debug.print("[zap] - " ++ fmt, args);
}
}
pub extern const fio_log_level_none: c_int; pub extern const fio_log_level_none: c_int;
pub extern const fio_log_level_fatal: c_int; pub extern const fio_log_level_fatal: c_int;
@ -34,12 +29,9 @@ pub extern fn fio_log_error(msg: [*c]const u8) void;
pub extern fn fio_log_fatal(msg: [*c]const u8) void; pub extern fn fio_log_fatal(msg: [*c]const u8) void;
pub extern fn fio_log_debug(msg: [*c]const u8) void; pub extern fn fio_log_debug(msg: [*c]const u8) void;
// pub fn getDebugLogger(comptime debug: bool) type { /// Error reporting of last resort
// return struct { pub fn on_uncaught_error(comptime domain: []const u8, err: anyerror) void {
// pub fn log(comptime fmt: []const u8, args: anytype) void { const std = @import("std");
// if (debug) { const log = std.log.scoped(.zap);
// std.debug.print("[zap] - " ++ fmt, args); log.err(domain ++ " : {}", .{err});
// } }
// }
// };
// }

View file

@ -10,17 +10,18 @@
//! ```zig //! ```zig
//! /// The http request path / slug of the endpoint //! /// The http request path / slug of the endpoint
//! path: []const u8, //! path: []const u8,
//! error_strategy: zap.Endpoint.ErrorStrategy,
//! //!
//! /// Handlers by request method: //! /// Handlers by request method:
//! pub fn get(_: *Self, _: zap.Request) void {} //! pub fn get(_: *Self, _: zap.Request) !void {}
//! pub fn post(_: *Self, _: zap.Request) void {} //! pub fn post(_: *Self, _: zap.Request) !void {}
//! pub fn put(_: *Self, _: zap.Request) void {} //! pub fn put(_: *Self, _: zap.Request) !void {}
//! pub fn delete(_: *Self, _: zap.Request) void {} //! pub fn delete(_: *Self, _: zap.Request) !void {}
//! pub fn patch(_: *Self, _: zap.Request) void {} //! pub fn patch(_: *Self, _: zap.Request) !void {}
//! pub fn options(_: *Self, _: zap.Request) void {} //! pub fn options(_: *Self, _: zap.Request) !void {}
//! //!
//! // optional, if auth stuff is used: //! // optional, if auth stuff is used:
//! pub fn unauthorized(_: *Self, _: zap.Request) void {} //! pub fn unauthorized(_: *Self, _: zap.Request) !void {}
//! ``` //! ```
//! //!
//! Example: //! Example:
@ -30,22 +31,24 @@
//! //!
//! ```zig //! ```zig
//! const StopEndpoint = struct { //! const StopEndpoint = struct {
//! path: []const u8,
//! error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
//! //!
//! pub fn init( path: []const u8,) StopEndpoint { //! pub fn init(path: []const u8) StopEndpoint {
//! return .{ //! return .{
//! .path = path, //! .path = path,
//! }; //! };
//! } //! }
//! //!
//! pub fn post(_: *StopEndpoint, _: zap.Request) void {} //! pub fn get(_: *StopEndpoint, _: zap.Request) !void {
//! pub fn put(_: *StopEndpoint, _: zap.Request) void {}
//! pub fn delete(_: *StopEndpoint, _: zap.Request) void {}
//! pub fn patch(_: *StopEndpoint, _: zap.Request) void {}
//! pub fn options(_: *StopEndpoint, _: zap.Request) void {}
//!
//! pub fn get(_: *StopEndpoint, _: zap.Request) void {
//! zap.stop(); //! zap.stop();
//! } //! }
//!
//! pub fn post(_: *StopEndpoint, _: zap.Request) !void {}
//! pub fn put(_: *StopEndpoint, _: zap.Request) !void {}
//! pub fn delete(_: *StopEndpoint, _: zap.Request) !void {}
//! pub fn patch(_: *StopEndpoint, _: zap.Request) !void {}
//! pub fn options(_: *StopEndpoint, _: zap.Request) !void {}
//! }; //! };
//! ``` //! ```
@ -57,9 +60,11 @@ const auth = @import("http_auth.zig");
pub const ErrorStrategy = enum { pub const ErrorStrategy = enum {
/// log errors to console /// log errors to console
log_to_console, log_to_console,
/// log errors to console AND generate a HTML response /// send an HTML response containing an error trace
log_to_response, log_to_response,
/// raise errors -> TODO: clarify: where can they be caught? in App.run() /// raise errors.
/// raised errors, if kept unhandled, will ultimately be logged by
/// zap.Logging.on_uncaught_error()
raise, raise,
}; };
@ -195,7 +200,7 @@ pub const Binder = struct {
switch (self.endpoint.*.error_strategy) { switch (self.endpoint.*.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} : {}", .{ Bound, r.method orelse "(no method)", err }), .log_to_console => zap.log.err("Error in {} {s} : {}", .{ Bound, r.method orelse "(no method)", err }),
} }
} }
} }
@ -384,13 +389,20 @@ pub const Listener = struct {
if (r.path) |p| { if (r.path) |p| {
for (endpoints.items) |interface| { for (endpoints.items) |interface| {
if (std.mem.startsWith(u8, p, interface.path)) { if (std.mem.startsWith(u8, p, interface.path)) {
return try interface.call(interface, r); return interface.call(interface, r) catch |err| {
zap.log.err(
"Endpoint onRequest error {} in endpoint interface {}\n",
.{ err, interface },
);
};
} }
} }
} }
// if set, call the user-provided default callback // if set, call the user-provided default callback
if (on_request) |foo| { if (on_request) |foo| {
try foo(r); foo(r) catch |err| {
zap.Logging.on_uncaught_error("Endpoint on_request", err);
};
} }
} }
}; };

View file

@ -194,18 +194,13 @@ fn fiobjectify(
.@"struct" => |S| { .@"struct" => |S| {
// create a new fio hashmap // create a new fio hashmap
const m = fio.fiobj_hash_new(); const m = fio.fiobj_hash_new();
// std.debug.print("new struct\n", .{});
inline for (S.fields) |Field| { inline for (S.fields) |Field| {
// don't include void fields // don't include void fields
if (Field.type == void) continue; if (Field.type == void) continue;
// std.debug.print(" new field: {s}\n", .{Field.name});
const fname = fio.fiobj_str_new(util.toCharPtr(Field.name), Field.name.len); const fname = fio.fiobj_str_new(util.toCharPtr(Field.name), Field.name.len);
// std.debug.print(" fiobj name : {any}\n", .{fname});
const v = @field(value, Field.name); const v = @field(value, Field.name);
// std.debug.print(" value: {any}\n", .{v});
const fvalue = fiobjectify(v); const fvalue = fiobjectify(v);
// std.debug.print(" fiobj value: {any}\n", .{fvalue});
_ = fio.fiobj_hash_set(m, fname, fvalue); _ = fio.fiobj_hash_set(m, fname, fvalue);
fio.fiobj_free_wrapped(fname); fio.fiobj_free_wrapped(fname);
} }
@ -225,7 +220,6 @@ fn fiobjectify(
}, },
// TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972) // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)
.slice => { .slice => {
// std.debug.print("new slice\n", .{});
if (ptr_info.child == u8 and std.unicode.utf8ValidateSlice(value)) { if (ptr_info.child == u8 and std.unicode.utf8ValidateSlice(value)) {
return fio.fiobj_str_new(util.toCharPtr(value), value.len); return fio.fiobj_str_new(util.toCharPtr(value), value.len);
} }

View file

@ -1,7 +1,6 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Log = @import("log.zig");
const http = @import("http.zig"); const http = @import("http.zig");
const fio = @import("fio.zig"); const fio = @import("fio.zig");
@ -138,24 +137,24 @@ fn parseBinfilesFrom(a: Allocator, o: fio.FIOBJ) !HttpParam {
fio.FIOBJ_T_DATA => { fio.FIOBJ_T_DATA => {
if (fio.is_invalid(data) == 1) { if (fio.is_invalid(data) == 1) {
data_slice = "(zap: invalid data)"; data_slice = "(zap: invalid data)";
std.log.warn("WARNING: HTTP param binary file is not a data object\n", .{}); zap.log.warn("HTTP param binary file is not a data object\n", .{});
} else { } else {
// the data // the data
const data_len = fio.fiobj_data_len(data); const data_len = fio.fiobj_data_len(data);
var data_buf = fio.fiobj_data_read(data, data_len); var data_buf = fio.fiobj_data_read(data, data_len);
if (data_len < 0) { if (data_len < 0) {
std.log.warn("WARNING: HTTP param binary file size negative: {d}\n", .{data_len}); zap.log.warn("HTTP param binary file size negative: {d}\n", .{data_len});
std.log.warn("FIOBJ_TYPE of data is: {d}\n", .{fio.fiobj_type(data)}); zap.log.warn("FIOBJ_TYPE of data is: {d}\n", .{fio.fiobj_type(data)});
} else { } else {
if (data_buf.len != data_len) { if (data_buf.len != data_len) {
std.log.warn("WARNING: HTTP param binary file size mismatch: should {d}, is: {d}\n", .{ data_len, data_buf.len }); zap.log.warn("HTTP param binary file size mismatch: should {d}, is: {d}\n", .{ data_len, data_buf.len });
} }
if (data_buf.len > 0) { if (data_buf.len > 0) {
data_slice = data_buf.data[0..data_buf.len]; data_slice = data_buf.data[0..data_buf.len];
} else { } else {
std.log.warn("WARNING: HTTP param binary file buffer size negative: {d}\n", .{data_buf.len}); zap.log.warn("HTTP param binary file buffer size negative: {d}\n", .{data_buf.len});
data_slice = "(zap: invalid data: negative BUFFER size)"; data_slice = "(zap: invalid data: negative BUFFER size)";
} }
} }
@ -165,7 +164,7 @@ fn parseBinfilesFrom(a: Allocator, o: fio.FIOBJ) !HttpParam {
const fiostr = fio.fiobj_obj2cstr(data); const fiostr = fio.fiobj_obj2cstr(data);
if (fiostr.len == 0) { if (fiostr.len == 0) {
data_slice = "(zap: empty string data)"; data_slice = "(zap: empty string data)";
std.log.warn("WARNING: HTTP param binary file has empty string object\n", .{}); zap.log.warn("WARNING: HTTP param binary file has empty string object\n", .{});
} else { } else {
data_slice = fiostr.data[0..fiostr.len]; data_slice = fiostr.data[0..fiostr.len];
} }
@ -185,15 +184,15 @@ fn parseBinfilesFrom(a: Allocator, o: fio.FIOBJ) !HttpParam {
const file_mimetype_obj = fio.fiobj_ary_entry(mt_ary, i); const file_mimetype_obj = fio.fiobj_ary_entry(mt_ary, i);
var has_error: bool = false; var has_error: bool = false;
if (fio.is_invalid(file_data_obj) == 1) { if (fio.is_invalid(file_data_obj) == 1) {
std.log.debug("file data invalid in array", .{}); zap.log.debug("file data invalid in array", .{});
has_error = true; has_error = true;
} }
if (fio.is_invalid(file_name_obj) == 1) { if (fio.is_invalid(file_name_obj) == 1) {
std.log.debug("file name invalid in array", .{}); zap.log.debug("file name invalid in array", .{});
has_error = true; has_error = true;
} }
if (fio.is_invalid(file_mimetype_obj) == 1) { if (fio.is_invalid(file_mimetype_obj) == 1) {
std.log.debug("file mimetype invalid in array", .{}); zap.log.debug("file mimetype invalid in array", .{});
has_error = true; has_error = true;
} }
if (has_error) { if (has_error) {
@ -358,7 +357,6 @@ pub fn sendBody(self: *const Request, body: []const u8) HttpError!void {
*anyopaque, *anyopaque,
@ptrFromInt(@intFromPtr(body.ptr)), @ptrFromInt(@intFromPtr(body.ptr)),
), body.len); ), body.len);
zap.debug("Request.sendBody(): ret = {}\n", .{ret});
if (ret == -1) return error.HttpSendBody; if (ret == -1) return error.HttpSendBody;
self.markAsFinished(true); self.markAsFinished(true);
} }
@ -381,7 +379,7 @@ pub fn setContentType(self: *const Request, c: ContentType) HttpError!void {
.JSON => "application/json", .JSON => "application/json",
else => "text/html", else => "text/html",
}; };
zap.debug("setting content-type to {s}\n", .{s}); zap.log.debug("setting content-type to {s}\n", .{s});
return self.setHeader("content-type", s); return self.setHeader("content-type", s);
} }
@ -393,21 +391,6 @@ pub fn redirectTo(self: *const Request, path: []const u8, code: ?http.StatusCode
self.markAsFinished(true); self.markAsFinished(true);
} }
/// shows how to use the logger
pub fn setContentTypeWithLogger(
self: *const Request,
c: ContentType,
logger: *const Log,
) HttpError!void {
const s = switch (c) {
.TEXT => "text/plain",
.JSON => "application/json",
else => "text/html",
};
logger.log("setting content-type to {s}\n", .{s});
return self.setHeader("content-type", s);
}
/// 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 Request) !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);
@ -518,21 +501,18 @@ pub fn setHeader(self: *const Request, name: []const u8, value: []const u8) Http
.capa = name.len, .capa = name.len,
}; };
zap.debug("setHeader: hname = {s}\n", .{name});
const vname: fio.fio_str_info_s = .{ const vname: fio.fio_str_info_s = .{
.data = util.toCharPtr(value), .data = util.toCharPtr(value),
.len = value.len, .len = value.len,
.capa = value.len, .capa = value.len,
}; };
zap.debug("setHeader: vname = {s}\n", .{value});
const ret = fio.http_set_header2(self.h, hname, vname); const ret = fio.http_set_header2(self.h, hname, vname);
// FIXME without the following if, we get errors in release builds // FIXME without the following if, we get errors in release builds
// at least we don't have to log unconditionally // at least we don't have to log unconditionally
if (ret == -1) { if (ret == -1) {
std.debug.print("***************** zap.zig:274\n", .{}); zap.log.debug("***************** zap.zig:274\n", .{});
} }
zap.debug("setHeader: ret = {}\n", .{ret});
if (ret == 0) return; if (ret == 0) return;
return error.HttpSetHeader; return error.HttpSetHeader;
@ -700,7 +680,7 @@ pub fn setCookie(self: *const Request, args: CookieArgs) HttpError!void {
// TODO: still happening? // TODO: still happening?
const ret = fio.http_set_cookie(self.h, c); const ret = fio.http_set_cookie(self.h, c);
if (ret == -1) { if (ret == -1) {
std.log.err("fio.http_set_cookie returned: {}\n", .{ret}); zap.log.err("fio.http_set_cookie returned: {}\n", .{ret});
return error.SetCookie; return error.SetCookie;
} }
} }

View file

@ -209,10 +209,6 @@ test "BearerAuthSingle authenticateRequest OK" {
try listener.register(&auth_ep); try listener.register(&auth_ep);
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("\n\n*******************************************\n", .{});
// std.debug.print("\n\nPlease run the following:\n", .{});
// std.debug.print("./zig-out/bin/http_client_runner\n", .{});
// std.debug.print("\n\n*******************************************\n", .{});
const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Bearer, .token = token }); const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Bearer, .token = token });
defer thread.join(); defer thread.join();
@ -266,8 +262,6 @@ test "BearerAuthSingle authenticateRequest test-unauthorized" {
try listener.register(&auth_ep); try listener.register(&auth_ep);
try listener.listen(); try listener.listen();
// std.debug.print("Waiting for the following:\n", .{});
// std.debug.print("./zig-out/bin/http_client http://127.0.0.1:3000/test Bearer invalid\r", .{});
const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Bearer, .token = "invalid" }); const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Bearer, .token = "invalid" });
defer thread.join(); defer thread.join();
@ -279,7 +273,6 @@ test "BearerAuthSingle authenticateRequest test-unauthorized" {
}); });
try std.testing.expectEqualStrings("UNAUTHORIZED", received_response); try std.testing.expectEqualStrings("UNAUTHORIZED", received_response);
std.debug.print("\nI made it\n", .{});
} }
test "BearerAuthMulti authenticateRequest OK" { test "BearerAuthMulti authenticateRequest OK" {
@ -316,8 +309,6 @@ test "BearerAuthMulti authenticateRequest OK" {
try listener.register(&auth_ep); try listener.register(&auth_ep);
try listener.listen(); try listener.listen();
// std.debug.print("Waiting for the following:\n", .{});
// std.debug.print("./zig-out/bin/http_client_runner http://127.0.0.1:3000/test Bearer " ++ token ++ "\r", .{});
const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Bearer, .token = token }); const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Bearer, .token = token });
defer thread.join(); defer thread.join();
@ -365,8 +356,6 @@ test "BearerAuthMulti authenticateRequest test-unauthorized" {
try listener.register(&auth_ep); try listener.register(&auth_ep);
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{});
// std.debug.print("./zig-out/bin/http_client_runner http://127.0.0.1:3000/test Bearer invalid\r", .{});
const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Bearer, .token = "invalid" }); const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Bearer, .token = "invalid" });
defer thread.join(); defer thread.join();
@ -419,8 +408,6 @@ test "BasicAuth Token68 authenticateRequest" {
try listener.register(&auth_ep); try listener.register(&auth_ep);
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{});
// std.debug.print("./zig-out/bin/http_client http://127.0.0.1:3000/test Basic " ++ token ++ "\r", .{});
const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Basic, .token = token }); const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Basic, .token = token });
defer thread.join(); defer thread.join();
@ -473,8 +460,6 @@ test "BasicAuth Token68 authenticateRequest test-unauthorized" {
try listener.register(&auth_ep); try listener.register(&auth_ep);
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{});
// std.debug.print("./zig-out/bin/http_client http://127.0.0.1:3000/test Basic " ++ "invalid\r", .{});
const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Basic, .token = "invalid" }); const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Basic, .token = "invalid" });
defer thread.join(); defer thread.join();
@ -537,8 +522,6 @@ test "BasicAuth UserPass authenticateRequest" {
try listener.register(&auth_ep); try listener.register(&auth_ep);
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{});
// std.debug.print("./zig-out/bin/http_client http://127.0.0.1:3000/test Basic {s}\r", .{encoded});
const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Basic, .token = encoded }); const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Basic, .token = encoded });
defer thread.join(); defer thread.join();
@ -604,8 +587,6 @@ test "BasicAuth UserPass authenticateRequest test-unauthorized" {
try listener.register(&auth_ep); try listener.register(&auth_ep);
listener.listen() catch {}; listener.listen() catch {};
// std.debug.print("Waiting for the following:\n", .{});
// std.debug.print("./zig-out/bin/http_client http://127.0.0.1:3000/test Basic invalid\r", .{});
const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Basic, .token = "invalid" }); const thread = try makeRequestThread(a, "http://127.0.0.1:3000/test", .{ .auth = .Basic, .token = "invalid" });
defer thread.join(); defer thread.join();

View file

@ -1,6 +1,14 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
fn makeRequest(a: std.mem.Allocator, url: []const u8) !void { 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();
@ -64,7 +72,6 @@ test "http parameters" {
.max_body_size = 1 * 1024, .max_body_size = 1 * 1024,
}, },
); );
zap.enableDebugLog();
try listener.listen(); try listener.listen();
const thread = try makeRequestThread(allocator, "http://127.0.0.1:3001/?one=1&two=2&string=hello+world&float=6.28&bool=true"); const thread = try makeRequestThread(allocator, "http://127.0.0.1:3001/?one=1&two=2&string=hello+world&float=6.28&bool=true");

View file

@ -1,6 +1,14 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap"); const zap = @import("zap");
// set default log level to .info and ZAP log level to .debug
pub const std_options: std.Options = .{
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .zap, .level = .debug },
},
};
var buffer: [1024]u8 = undefined; var buffer: [1024]u8 = undefined;
var read_len: ?usize = null; var read_len: ?usize = null;
@ -41,7 +49,6 @@ test "send file" {
.max_body_size = 1 * 1024, .max_body_size = 1 * 1024,
}, },
); );
zap.enableDebugLog();
try listener.listen(); try listener.listen();
const thread = try makeRequestThread(allocator, "http://127.0.0.1:3002/?file=src/tests/testfile.txt"); const thread = try makeRequestThread(allocator, "http://127.0.0.1:3002/?file=src/tests/testfile.txt");

View file

@ -21,15 +21,15 @@ pub fn Handler(comptime ContextType: type) type {
message: []const u8, message: []const u8,
/// indicator if message is text or binary /// indicator if message is text or binary
is_text: bool, is_text: bool,
) void; ) anyerror!void;
/// Callback (type) when websocket is closed. uuid is a connection identifier, /// Callback (type) when websocket is closed. uuid is a connection identifier,
/// it is -1 if a connection could not be established /// it is -1 if a connection could not be established
pub const WsOnCloseFn = *const fn (context: ?*ContextType, uuid: isize) void; pub const WsOnCloseFn = *const fn (context: ?*ContextType, uuid: isize) anyerror!void;
/// A websocket callback function type. provides the context passed in at /// A websocket callback function type. provides the context passed in at
/// websocketHttpUpgrade(). /// websocketHttpUpgrade().
pub const WsFn = *const fn (context: ?*ContextType, handle: WsHandle) void; pub const WsFn = *const fn (context: ?*ContextType, handle: WsHandle) anyerror!void;
/// Websocket connection handler creation settings. Provide the callbacks you need, /// Websocket connection handler creation settings. Provide the callbacks you need,
/// and an optional context. /// and an optional context.
@ -68,7 +68,9 @@ pub fn Handler(comptime ContextType: type) type {
const message = msg.data[0..msg.len]; const message = msg.data[0..msg.len];
if (user_provided_settings) |settings| { if (user_provided_settings) |settings| {
if (settings.on_message) |on_message| { if (settings.on_message) |on_message| {
on_message(settings.context, handle, message, is_text == 1); on_message(settings.context, handle, message, is_text == 1) catch |err| {
zap.Logging.on_uncaught_error("WebSocket Handler on_message", err);
};
} }
} }
} }
@ -77,7 +79,9 @@ pub fn Handler(comptime ContextType: type) type {
const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(fio.websocket_udata_get(handle)))); const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(fio.websocket_udata_get(handle))));
if (user_provided_settings) |settings| { if (user_provided_settings) |settings| {
if (settings.on_open) |on_open| { if (settings.on_open) |on_open| {
on_open(settings.context, handle); on_open(settings.context, handle) catch |err| {
zap.Logging.on_uncaught_error("WebSocket Handler on_open", err);
};
} }
} }
} }
@ -86,7 +90,9 @@ pub fn Handler(comptime ContextType: type) type {
const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(fio.websocket_udata_get(handle)))); const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(fio.websocket_udata_get(handle))));
if (user_provided_settings) |settings| { if (user_provided_settings) |settings| {
if (settings.on_ready) |on_ready| { if (settings.on_ready) |on_ready| {
on_ready(settings.context, handle); on_ready(settings.context, handle) catch |err| {
zap.Logging.on_uncaught_error("WebSocket Handler on_ready", err);
};
} }
} }
} }
@ -95,7 +101,9 @@ pub fn Handler(comptime ContextType: type) type {
const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(fio.websocket_udata_get(handle)))); const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(fio.websocket_udata_get(handle))));
if (user_provided_settings) |settings| { if (user_provided_settings) |settings| {
if (settings.on_shutdown) |on_shutdown| { if (settings.on_shutdown) |on_shutdown| {
on_shutdown(settings.context, handle); on_shutdown(settings.context, handle) catch |err| {
zap.Logging.on_uncaught_error("WebSocket Handler on_shutdown", err);
};
} }
} }
} }
@ -104,7 +112,9 @@ pub fn Handler(comptime ContextType: type) type {
const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(udata))); const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(udata)));
if (user_provided_settings) |settings| { if (user_provided_settings) |settings| {
if (settings.on_close) |on_close| { if (settings.on_close) |on_close| {
on_close(settings.context, uuid); on_close(settings.context, uuid) catch |err| {
zap.Logging.on_uncaught_error("WebSocket Handler on_close", err);
};
} }
} }
} }
@ -155,10 +165,10 @@ pub fn Handler(comptime ContextType: type) type {
} }
/// Type for callback on subscription message. /// Type for callback on subscription message.
pub const SubscriptionOnMessageFn = *const fn (context: ?*ContextType, handle: WsHandle, channel: []const u8, message: []const u8) void; pub const SubscriptionOnMessageFn = *const fn (context: ?*ContextType, handle: WsHandle, channel: []const u8, message: []const u8) anyerror!void;
/// Type for callback on unsubscribe message. /// Type for callback on unsubscribe message.
pub const SubscriptionOnUnsubscribeFn = *const fn (context: ?*ContextType) void; pub const SubscriptionOnUnsubscribeFn = *const fn (context: ?*ContextType) anyerror!void;
/// Settings for subscribing to a channel. /// Settings for subscribing to a channel.
pub const SubscribeArgs = struct { pub const SubscribeArgs = struct {
@ -213,7 +223,9 @@ pub fn Handler(comptime ContextType: type) type {
if (udata) |p| { if (udata) |p| {
const args = @as(*SubscribeArgs, @ptrCast(@alignCast(p))); const args = @as(*SubscribeArgs, @ptrCast(@alignCast(p)));
if (args.on_message) |on_message| { if (args.on_message) |on_message| {
on_message(args.context, handle, channel.data[0..channel.len], message.data[0..message.len]); on_message(args.context, handle, channel.data[0..channel.len], message.data[0..message.len]) catch |err| {
zap.Logging.on_uncaught_error("WebSocket Subscription on_message", err);
};
} }
} }
} }
@ -221,7 +233,9 @@ pub fn Handler(comptime ContextType: type) type {
if (udata) |p| { if (udata) |p| {
const args = @as(*SubscribeArgs, @ptrCast(@alignCast(p))); const args = @as(*SubscribeArgs, @ptrCast(@alignCast(p)));
if (args.on_unsubscribe) |on_unsubscribe| { if (args.on_unsubscribe) |on_unsubscribe| {
on_unsubscribe(args.context); on_unsubscribe(args.context) catch |err| {
zap.Logging.on_uncaught_error("WebSocket Subscription on_unsubscribe", err);
};
} }
} }
} }

View file

@ -37,13 +37,12 @@ pub const Middleware = @import("middleware.zig");
/// Websocket API /// Websocket API
pub const WebSockets = @import("websockets.zig"); pub const WebSockets = @import("websockets.zig");
pub const Log = @import("log.zig"); pub const Logging = @import("Logging.zig");
pub const log = std.log.scoped(.zap);
pub const http = @import("http.zig"); pub const http = @import("http.zig");
pub const util = @import("util.zig"); pub const util = @import("util.zig");
// TODO: replace with comptime debug logger like in log.zig
var _debug: bool = false;
/// Start the IO reactor /// Start the IO reactor
/// ///
/// Will start listeners etc. /// Will start listeners etc.
@ -60,23 +59,9 @@ pub fn stop() void {
fio.fio_stop(); fio.fio_stop();
} }
/// Extremely simplistic zap debug function. /// Extremely simplistic zap debug function, to save a few keystrokes
/// TODO: re-wwrite logging or use std.log
pub fn debug(comptime fmt: []const u8, args: anytype) void { pub fn debug(comptime fmt: []const u8, args: anytype) void {
if (_debug) { log.debug("[zap] - " ++ fmt, args);
std.debug.print("[zap] - " ++ fmt, args);
}
}
/// Enable zap debug logging
pub fn enableDebugLog() void {
_debug = true;
}
/// start Zap with debug logging on
pub fn startWithLogging(args: fio.fio_start_args) void {
_debug = true;
fio.fio_start(args);
} }
/// Registers a new mimetype to be used for files ending with the given extension. /// Registers a new mimetype to be used for files ending with the given extension.
@ -138,14 +123,14 @@ pub const HttpRequestFn = *const fn (Request) anyerror!void;
/// websocket connection upgrade callback type /// websocket connection upgrade callback type
/// fn(request, targetstring) /// fn(request, targetstring)
pub const HttpUpgradeFn = *const fn (r: Request, target_protocol: []const u8) void; pub const HttpUpgradeFn = *const fn (r: Request, target_protocol: []const u8) anyerror!void;
/// http finish, called when zap finishes. You get your udata back in the /// http finish, called when zap finishes. You get your udata back in the
/// HttpFinishSetting struct. /// HttpFinishSetting struct.
pub const HttpFinishSettings = [*c]fio.struct_http_settings_s; pub const HttpFinishSettings = [*c]fio.struct_http_settings_s;
/// Http finish callback type /// Http finish callback type
pub const HttpFinishFn = *const fn (HttpFinishSettings) void; pub const HttpFinishFn = *const fn (HttpFinishSettings) anyerror!void;
/// Listener settings /// Listener settings
pub const HttpListenerSettings = struct { pub const HttpListenerSettings = struct {
@ -204,8 +189,7 @@ pub const HttpListener = struct {
std.debug.assert(l.settings.on_request != null); std.debug.assert(l.settings.on_request != null);
if (l.settings.on_request) |on_request| { if (l.settings.on_request) |on_request| {
on_request(req) catch |err| { on_request(req) catch |err| {
// TODO: log / handle the error in a better way Logging.on_uncaught_error("HttpListener on_request", err);
std.debug.print("zap on_request error: {}", .{err});
}; };
} }
} }
@ -229,8 +213,7 @@ pub const HttpListener = struct {
req._user_context = &user_context; req._user_context = &user_context;
l.settings.on_response.?(req) catch |err| { l.settings.on_response.?(req) catch |err| {
// TODO: log / handle the error in a better way Logging.on_uncaught_error("HttpListener on_response", err);
std.debug.print("zap on_response error: {}", .{err});
}; };
} }
} }
@ -253,14 +236,18 @@ pub const HttpListener = struct {
var user_context: Request.UserContext = .{}; var user_context: Request.UserContext = .{};
req._user_context = &user_context; req._user_context = &user_context;
l.settings.on_upgrade.?(req, zigtarget); l.settings.on_upgrade.?(req, zigtarget) catch |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| { if (the_one_and_only_listener) |l| {
l.settings.on_finish.?(s); l.settings.on_finish.?(s) catch |err| {
Logging.on_uncaught_error("HttpListener on_finish", err);
};
} }
} }
@ -390,7 +377,6 @@ pub const LowLevel = struct {
*anyopaque, *anyopaque,
@ptrFromInt(@intFromPtr(body.ptr)), @ptrFromInt(@intFromPtr(body.ptr)),
), body.len); ), body.len);
debug("sendBody(): ret = {}\n", .{ret});
if (ret != -1) return error.HttpSendBody; if (ret != -1) return error.HttpSendBody;
} }
}; };