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

Merge branch 'master' into zig-master

This commit is contained in:
Rene Schallner 2024-10-14 22:12:23 +02:00
commit 54c2ed64c6
No known key found for this signature in database
6 changed files with 60 additions and 32 deletions

View file

@ -58,7 +58,7 @@ master though.
## Here's what works
I recommend checking out **Endpoint-based examples for more realistic
use cases**. Most of the examples are super stripped down to only include
use cases**. Most of the examples are super stripped down to only include
what's necessary to show a feature.
**NOTE: To see API docs, run `zig build run-docserver`.** To specify a custom
@ -132,10 +132,10 @@ port and docs dir: `zig build docserver && zig-out/bin/docserver --port=8989
call `r.sendError(err, status_code)` when you catch an error and a stack trace
will be returned to the client / browser.
- [**HTTPS**](examples/https/https.zig): Shows how easy it is to use facil.io's
openssl support. Must be compiled with `-Dopenssl=true` or the environment
openssl support. Must be compiled with `-Dopenssl=true` or the environment
variable `ZAP_USE_OPENSSL` set to `true` and requires openssl dev dependencies
(headers, lib) to be installed on the system.
- run it like this: `ZAP_USE_OPENSSL=true zig build run-https`
- run it like this: `ZAP_USE_OPENSSL=true zig build run-https`
OR like this: `zig build -Dopenssl=true run-https`
- it will tell you how to generate certificates
- [**simple_router**](examples/simple_router/simple_router.zig): See how you
@ -181,7 +181,7 @@ simplistic testing scenario.
So, being somewhere in the ballpark of basic GO performance, zig zap seems to be
... of reasonable performance 😎.
... of reasonable performance 😎.
I can rest my case that developing ZAP was a good idea because it's faster than
both alternatives: a) staying with Python, and b) creating a GO + Zig hybrid.
@ -257,7 +257,7 @@ $ git init ## (optional)
**Note**: Nix/NixOS users are lucky; you can use the existing `flake.nix` and run
`nix develop` to get a development shell providing zig and all
dependencies to build and run the GO, python, and rust examples for the
`wrk` performance tests. For the mere building of zap projects,
`wrk` performance tests. For the mere building of zap projects,
`nix develop .#build` will only fetch zig 0.11.0. TODO: upgrade to latest zig.
With an existing Zig project, adding Zap to it is easy:
@ -274,9 +274,9 @@ To add zap to `build.zig.zon`:
.version = "0.0.1",
.dependencies = .{
// zap v0.7.0
// zap v0.8.0
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.7.0.tar.gz",
.url = "https://github.com/zigzap/zap/archive/v0.8.0.tar.gz",
.hash = "12209936c3333b53b53edcf453b1670babb9ae8c2197b1ca627c01e72670e20c1a21",
},
},
@ -416,3 +416,4 @@ pub fn main() !void {
}
```

View file

@ -123,19 +123,17 @@ const SessionMiddleWare = struct {
//
// !!!! ENDPOINT !!!
//
// We define an endpoint as we usually would.
// NO ROUTING IS PERFORMED
// as we are just going to wrap it in a bunch of Middleware components
// and therefore NOT using an endpoint listener that would the routing for us
// We define an endpoint as we usually would; however,
// NO ROUTING IS PERFORMED BY DEFAULT!
//
// Hence, the endpoint should check r.path in its on_request to check wether
// it is adressed or not.
// This can be changed using the EndpointHandlerOptions passed into the
// EndpointHandler.init() method.
//
// N.B. the EndpointHandler checks if the endpoint turned the request into
// "finished" state, e.g. by sending anything. If the endpoint didn't finish the
// request, the EndpointHandler will pass the request on to the next handler in
// the chain if there is one. See also the EndpointHandler's `breakOnFinish`
// parameter.
// the chain if there is one. See also the EndpointHandlerOptions's
// `breakOnFinish` parameter.
//
const HtmlEndpoint = struct {
ep: zap.Endpoint = undefined,
@ -210,7 +208,7 @@ pub fn main() !void {
var htmlHandler = zap.Middleware.EndpointHandler(Handler, Context).init(
htmlEndpoint.endpoint(), // the endpoint
null, // no other handler (we are the last in the chain)
true, // break on finish. See EndpointHandler for this. Not applicable here.
.{}, // We can set custom EndpointHandlerOptions here
);
// we wrap it in the session Middleware component

View file

@ -11,8 +11,16 @@ pub const fio_url_s = extern struct {
target: fio_str_info_s,
};
pub extern fn fio_url_parse(url: [*c]const u8, length: usize) fio_url_s;
/// Negative thread / worker values indicate a fraction of the number of CPU cores. i.e., -2 will normally indicate "half" (1/2) the number of cores.
///
/// If one value is set to zero, it will be the absolute value of the other value. i.e.: if .threads == -2 and .workers == 0, than facil.io will run 2 worker processes with (cores/2) threads per process.
pub const struct_fio_start_args = extern struct {
/// The number of threads to run in the thread pool.
threads: i16,
/// The number of worker processes to run (in addition to a root process)
///
/// This invokes facil.io's cluster mode, where a crashed worker will be automatically re-spawned and "hot restart" is enabled (using the USR1 signal).
workers: i16,
};
pub const fio_start_args = struct_fio_start_args;

View file

@ -51,23 +51,38 @@ pub fn Handler(comptime ContextType: anytype) type {
};
}
/// Options used to change the behavior of an `EndpointHandler`
pub const EndpointHandlerOptions = struct {
/// If `true`, the handler will stop handing requests down the chain if the
/// endpoint processed the request.
breakOnFinish: bool = true,
/// If `true`, the handler will only execute against requests that match
/// the endpoint's `path` setting.
checkPath: bool = false,
};
/// A convenience handler for artibrary zap.Endpoint
pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anytype) type {
return struct {
handler: HandlerType,
endpoint: *zap.Endpoint,
breakOnFinish: bool,
options: EndpointHandlerOptions,
const Self = @This();
/// Create an endpointhandler from an endpoint and pass in the next (other) handler in the chain.
/// If `breakOnFinish` is `true`, the handler will stop handing requests down the chain if
/// the endpoint processed the request.
pub fn init(endpoint: *zap.Endpoint, other: ?*HandlerType, breakOnFinish: bool) Self {
///
/// By default no routing is performed on requests. This behavior can be changed by setting
/// `checkPath` in the provided options.
///
/// If the `breakOnFinish` option is `true`, the handler will stop handing requests down the chain
/// if the endpoint processed the request.
pub fn init(endpoint: *zap.Endpoint, other: ?*HandlerType, options: EndpointHandlerOptions) Self {
return .{
.handler = HandlerType.init(onRequest, other),
.endpoint = endpoint,
.breakOnFinish = breakOnFinish,
.options = options,
};
}
@ -84,10 +99,14 @@ pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anyt
pub fn onRequest(handler: *HandlerType, r: zap.Request, context: *ContextType) bool {
const self: *Self = @fieldParentPtr("handler", handler);
r.setUserContext(context);
self.endpoint.onRequest(r);
if (!self.options.checkPath or
std.mem.startsWith(u8, r.path orelse "", self.endpoint.settings.path))
{
self.endpoint.onRequest(r);
}
// if the request was handled by the endpoint, we may break the chain here
if (r.isFinished() and self.breakOnFinish) {
if (r.isFinished() and self.options.breakOnFinish) {
return true;
}
return self.handler.handleOther(r, context);

View file

@ -15,7 +15,7 @@ extern fn fiobj_mustache_build2(dest: fio.FIOBJ, mustache: ?*mustache_s, data: f
extern fn fiobj_mustache_free(mustache: ?*mustache_s) void;
/// Load arguments used when creating a new Mustache instance.
pub const MustacheLoadArgs = struct {
pub const LoadArgs = struct {
/// Filename. This enables partial templates on filesystem.
filename: ?[]const u8 = null,
@ -51,7 +51,7 @@ pub const Error = error{
/// Create a new `Mustache` instance; `deinit()` should be called to free
/// the object after usage.
pub fn init(load_args: MustacheLoadArgs) Error!Self {
pub fn init(load_args: LoadArgs) Error!Self {
var err: mustache_error_en = undefined;
const args: MustacheLoadArgsFio = .{
@ -113,7 +113,7 @@ pub fn deinit(self: *Self) void {
// pub extern fn fiobj_mustache_build2(dest: FIOBJ, mustache: ?*mustache_s, data: FIOBJ) FIOBJ;
/// The result from calling `build`.
const MustacheBuildResult = struct {
pub const BuildResult = struct {
fiobj_result: fio.FIOBJ = 0,
/// Holds the context converted into a fiobj.
@ -121,13 +121,13 @@ const MustacheBuildResult = struct {
fiobj_context: fio.FIOBJ = 0,
/// Free the data backing a `MustacheBuildResult` instance.
pub fn deinit(m: *const MustacheBuildResult) void {
pub fn deinit(m: *const BuildResult) void {
fio.fiobj_free_wrapped(m.fiobj_result);
fio.fiobj_free_wrapped(m.fiobj_context);
}
/// Retrieve a string representation of the built template.
pub fn str(m: *const MustacheBuildResult) ?[]const u8 {
pub fn str(m: *const BuildResult) ?[]const u8 {
return util.fio2str(m.fiobj_result);
}
};
@ -137,13 +137,13 @@ const MustacheBuildResult = struct {
// TODO: The build may be slow because it needs to convert zig types to facil.io
// types. However, this needs to be investigated into.
// See `fiobjectify` for more information.
pub fn build(self: *Self, data: anytype) MustacheBuildResult {
pub fn build(self: *Self, data: anytype) BuildResult {
const T = @TypeOf(data);
if (@typeInfo(T) != .Struct) {
@compileError("No struct: '" ++ @typeName(T) ++ "'");
}
var result: MustacheBuildResult = .{};
var result: BuildResult = .{};
result.fiobj_context = fiobjectify(data);
result.fiobj_result = fiobj_mustache_build(self.handle, result.fiobj_context);

View file

@ -431,8 +431,10 @@ pub fn setContentTypeFromFilename(self: *const Self, filename: []const u8) !void
}
}
/// Returns the header value of given key name. Returned mem is temp.
/// Do not free it.
/// Returns the header value of given key name.
/// NOTE that header-names are lowerased automatically while parsing the request.
/// so please only use lowercase keys!
/// Returned mem is temp. Do not free it.
pub fn getHeader(self: *const Self, name: []const u8) ?[]const u8 {
const hname = fio.fiobj_str_new(util.toCharPtr(name), name.len);
defer fio.fiobj_free_wrapped(hname);