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

Merge branch 'zig-0.12.0'

This commit is contained in:
Rene Schallner 2024-04-21 14:20:15 +02:00
commit 1e1999802a
38 changed files with 426 additions and 267 deletions

View file

@ -1,21 +1,20 @@
name: Works with Zig master
on:
# push:
# branches:
# - master
# pull_request:
# branches:
# - master
# schedule:
# - cron: "0 0 * * *"
workflow_dispatch:
push:
branches:
- zig-0.12.0
pull_request:
branches:
- zig-0.12.0
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
ci:
strategy:
matrix:
# platform: [ubuntu-latest, windows-latest, macos-latest]
platform: [ubuntu-latest]
platform: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
@ -26,5 +25,46 @@ jobs:
run: zig version
- name: Build all examples
run: zig build all
- name: Run all tests
run: zig build test
# Run tests separately so we can see more clearly which one fails
- name: Run mustache tests
run: zig build test-mustache
- name: Run httpparams tests
run: zig build test-httpparams
- name: Run sendfile tests
run: zig build test-sendfile
- name: Run authentication tests
run: zig build test-authentication
- name: Report end of tests
run: echo "tests finished"
update-readme:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- uses: actions/checkout@v3
- uses: goto-bus-stop/setup-zig@v2
with:
version: master
- name: Build announceybot
run: zig build announceybot
- name: Run script to update README
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ steps.tag.outputs.version }}
run: |
zig-out/bin/announceybot update-readme "zig-0.12.0"
- name: Commit and push if it has changed
run: |
git diff
git checkout zig-0.12.0
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git commit -am "Update README"
git push origin zig-0.12.0
>>>>>>> zig-0.12.0

1
.gitignore vendored
View file

@ -11,7 +11,6 @@ wrk/csharp/obj/
wrk/csharp/out/
scratch
**/.mypy_cache/*
docs/
.DS_Store
.vs/
**/*.perflog

View file

@ -1,5 +1,3 @@
# ⚡zap⚡ - blazingly fast backends in zig
![](https://github.com/zigzap/zap/actions/workflows/build-zig-11.yml/badge.svg) ![](https://github.com/zigzap/zap/actions/workflows/mastercheck.yml/badge.svg) [![Discord](https://img.shields.io/discord/1107835896356675706?label=chat&logo=discord&style=plastic)](https://discord.gg/jQAAN6Ubyj)
@ -26,17 +24,17 @@ that it proved to be:
Exactly the goals I set out to achieve!
## Most FAQ:
### Zap uses the latest stable zig release (0.11.0) for a reason. So you don't have to keep up with frequent breaking changes. It's an "LTS feature". If you want to use zig master, use the `zig-0.12.0` branch but be aware that I don't provide `build.zig.zon` snippets or tagged releases for it for the time being. If you know what you are doing, that shouldn't stop you from using it with zig master though.
### Zap uses the latest stable zig release (0.1@.0) for a reason. So you don't have to keep up with frequent breaking changes. It's an "LTS feature". If you want to use zig master, use the `zig-0.13.0` branch (coming soon) but be aware that I don't provide `build.zig.zon` snippets or tagged releases for it for the time being. If you know what you are doing, that shouldn't stop you from using it with zig master though.
- Q: **Where is the API documentation?**
- A: Docs are a work in progress. You can check them out [here](https://zigzap.org/zap). The docs are based on the `zig-0.12.0` branch but apply to the current release (zig 0.11.0), too.
- A: Docs are a work in progress. You can check them out [here](https://zigzap.org/zap).
- A: Run `zig build run-docserver` to serve them locally.
- Q: **Zap doesn't build with Zig master?**
- A: See the 0.12.0 branch. An example of how to use it is
[here](https://github.com/zigzap/hello-0.12.0). Please note that the 0.12.0
branch is not the official master branch of ZAP. Yet. Until zig 0.12.0 is
- A: See the 0.13.0 branch (soon). An example of how to use it is
[here](https://github.com/zigzap/hello-0.13.0). Please note that the 0.13.0
branch is not the official master branch of ZAP. Yet. Until zig 0.13.0 is
released.
- Q: **Does ZAP work on Windows?**
- A: No. This is due to the underlying facil.io C library. Future versions of
@ -57,6 +55,10 @@ I recommend checking out **Endpoint-based examples for more realistic
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
port and docs dir: `zig build docserver && zig-out/bin/docserver --port=8989
--docs=path/to/docs`.
- **Super easy build process**: Zap's `build.zig` now uses the new Zig package
manager for its C-dependencies, no git submodules anymore.
- _tested on Linux and macOS (arm, M1)_
@ -222,7 +224,7 @@ code leaks memory.
## Getting started
Make sure you have **the latest zig release (0.11.0)** installed. Fetch it from
Make sure you have zig 0.12.0 installed. Fetch it from
[here](https://ziglang.org/download).
```shell
@ -236,7 +238,7 @@ $ # open http://localhost:3000 in your browser
## Using ⚡zap⚡ in your own projects
Make sure you have **the latest zig release (0.11.0)** installed. Fetch it from
Make sure you have **the latest zig release (0.12.0)** installed. Fetch it from
[here](https://ziglang.org/download).
If you don't have an existing zig project, create one like this:
@ -250,7 +252,7 @@ $ git init ## (optional)
`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,
`nix develop .#build` will only fetch zig 0.11.0.
`nix develop .#build` will only fetch zig 0.11.0. TODO: upgrade to zig 0.12.
With an existing Zig project, adding Zap to it is easy:
@ -268,9 +270,14 @@ To add zap to `build.zig.zon`:
.dependencies = .{
// zap v0.6.0
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.6.0.tar.gz",
.hash = "1220a5a1e6b18fa384d8a98e5d5a25720ddadbcfed01da2e4ca55c7cfb3dc1caa62a",
}
// when tagged:
// .url = "https://github.com/zigzap/zap/archive/refs/tags/zig-0.12.0.tar.gz",
.url = "https://github.com/zigzap/zap/archive/zig-0.12.0.tar.gz",
.hash = "122002bc4a3fb6d4c465ce9f7f0af06e9ffbe38a6ed8c7375a2121d05eee294af893",
},
.paths = .{
"",
},
}
}
```
@ -285,7 +292,8 @@ Then, in your `build.zig`'s `build` function, add the following before
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.addModule("zap", zap.module("zap"));
exe.root_module.addImport("zap", zap.module("zap"));
exe.linkLibrary(zap.artifact("facil.io"));
```
@ -404,28 +412,3 @@ pub fn main() !void {
});
}
```

View file

@ -1,11 +1,11 @@
const std = @import("std");
const build_facilio = @import("facil.io/build.zig").build_facilio;
pub fn build(b: *std.build.Builder) !void {
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
if (target.getOsTag() == .windows) {
if (target.result.os.tag == .windows) {
std.log.err("\x1b[31mPlatform Not Supported\x1b[0m\nCurrently, Facil.io and Zap are not compatible with Windows. Consider using Linux or Windows Subsystem for Linux (WSL) instead.\nFor more information, please see:\n- https://github.com/zigzap/zap#most-faq\n- https://facil.io/#forking-contributing-and-all-that-jazz\n", .{});
std.os.exit(1);
std.process.exit(1);
}
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
@ -13,24 +13,39 @@ pub fn build(b: *std.build.Builder) !void {
const use_openssl = b.option(bool, "openssl", "Use system-installed openssl for TLS support in zap") orelse blk: {
// Alternatively, use an os env var to determine whether to build openssl support
if (std.os.getenv("ZAP_USE_OPENSSL")) |val| {
if (std.posix.getenv("ZAP_USE_OPENSSL")) |val| {
if (std.mem.eql(u8, val, "true")) break :blk true;
}
break :blk false;
};
// create a module to be used internally.
var zap_module = b.createModule(.{
.source_file = .{ .path = "src/zap.zig" },
const zap_module = b.addModule("zap", .{
.root_source_file = .{ .path = "src/zap.zig" },
});
// register the module so it can be referenced using the package manager.
try b.modules.put(b.dupe("zap"), zap_module);
// try b.modules.put(b.dupe("zap"), zap_module);
const facilio = try build_facilio("facil.io", b, target, optimize, use_openssl);
const all_step = b.step("all", "build all examples");
// -- Docs
const docs_obj = b.addObject(.{
.name = "zap", // name doesn't seem to matter
.root_source_file = .{ .path = "src/zap.zig" },
.target = target,
.optimize = .Debug,
});
const install_docs = b.addInstallDirectory(.{
.install_dir = .prefix,
.install_subdir = "zap", // will also be the main namespace in the docs
.source_dir = docs_obj.getEmittedDocs(),
});
b.step("docs", "Build docs").dependOn(&install_docs.step);
// --
inline for ([_]struct {
name: []const u8,
src: []const u8,
@ -85,8 +100,8 @@ pub fn build(b: *std.build.Builder) !void {
.optimize = optimize,
});
example.root_module.addImport("zap", zap_module);
example.linkLibrary(facilio);
example.addModule("zap", zap_module);
// const example_run = example.run();
const example_run = b.addRunArtifact(example);
@ -125,7 +140,7 @@ pub fn build(b: *std.build.Builder) !void {
.optimize = optimize,
});
auth_tests.linkLibrary(facilio);
auth_tests.addModule("zap", zap_module);
auth_tests.root_module.addImport("zap", zap_module);
const run_auth_tests = b.addRunArtifact(auth_tests);
const install_auth_tests = b.addInstallArtifact(auth_tests, .{});
@ -138,7 +153,7 @@ pub fn build(b: *std.build.Builder) !void {
.optimize = optimize,
});
mustache_tests.linkLibrary(facilio);
mustache_tests.addModule("zap", zap_module);
mustache_tests.root_module.addImport("zap", zap_module);
const run_mustache_tests = b.addRunArtifact(mustache_tests);
const install_mustache_tests = b.addInstallArtifact(mustache_tests, .{});
@ -152,7 +167,8 @@ pub fn build(b: *std.build.Builder) !void {
});
httpparams_tests.linkLibrary(facilio);
httpparams_tests.addModule("zap", zap_module);
httpparams_tests.root_module.addImport("zap", zap_module);
const run_httpparams_tests = b.addRunArtifact(httpparams_tests);
// TODO: for some reason, tests aren't run more than once unless
// dependencies have changed.
@ -169,7 +185,7 @@ pub fn build(b: *std.build.Builder) !void {
});
sendfile_tests.linkLibrary(facilio);
sendfile_tests.addModule("zap", zap_module);
sendfile_tests.root_module.addImport("zap", zap_module);
const run_sendfile_tests = b.addRunArtifact(sendfile_tests);
const install_sendfile_tests = b.addInstallArtifact(sendfile_tests, .{});
@ -202,7 +218,7 @@ pub fn build(b: *std.build.Builder) !void {
//
// pkghash
//
var pkghash_exe = b.addExecutable(.{
const pkghash_exe = b.addExecutable(.{
.name = "pkghash",
.root_source_file = .{ .path = "./tools/pkghash.zig" },
.target = target,
@ -213,10 +229,33 @@ pub fn build(b: *std.build.Builder) !void {
pkghash_step.dependOn(&pkghash_build_step.step);
all_step.dependOn(&pkghash_build_step.step);
//
// docserver
//
const docserver_exe = b.addExecutable(.{
.name = "docserver",
.root_source_file = .{ .path = "./tools/docserver.zig" },
.target = target,
.optimize = optimize,
});
docserver_exe.linkLibrary(facilio);
docserver_exe.root_module.addImport("zap", zap_module);
var docserver_step = b.step("docserver", "Build docserver");
const docserver_build_step = b.addInstallArtifact(docserver_exe, .{});
docserver_step.dependOn(&docserver_build_step.step);
docserver_step.dependOn(&install_docs.step);
const docserver_run_step = b.step("run-docserver", "run the docserver");
const docserver_run = b.addRunArtifact(docserver_exe);
docserver_run_step.dependOn(&docserver_run.step);
docserver_run_step.dependOn(docserver_step);
all_step.dependOn(&docserver_build_step.step);
//
// announceybot
//
var announceybot_exe = b.addExecutable(.{
const announceybot_exe = b.addExecutable(.{
.name = "announceybot",
.root_source_file = .{ .path = "./tools/announceybot.zig" },
.target = target,

View file

@ -1 +1,10 @@
.{ .name = "zap", .version = "0.6.0" }
.{
.name = "zap",
.version = "0.7.0",
.paths = .{
"build.zig",
"build.zig.zon",
"src",
"facil.io",
},
}

View file

@ -22,7 +22,10 @@ Here is a complete `build.zig.zon` example:
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
.hash = "{hash}",
}
},
.paths = .{
"",
},
}
}
@ -35,7 +38,8 @@ Then, in your `build.zig`'s `build` function, add the following before
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.addModule("zap", zap.module("zap"));
exe.root_module.addImport("zap", zap.module("zap"));
exe.linkLibrary(zap.artifact("facil.io"));
```

View file

@ -5,7 +5,7 @@ const Handler = struct {
var alloc: std.mem.Allocator = undefined;
pub fn on_request(r: zap.Request) void {
// check for FORM parameters
// parse for FORM (body) parameters first
r.parseBody() catch |err| {
std.log.err("Parse Body error: {any}. Expected if body is empty", .{err});
};
@ -13,10 +13,11 @@ const Handler = struct {
if (r.body) |body| {
std.log.info("Body length is {any}\n", .{body.len});
}
// check for query params (for ?terminate=true)
// parse potential query params (for ?terminate=true)
r.parseQuery();
var param_count = r.getParamCount();
const param_count = r.getParamCount();
std.log.info("param_count: {}", .{param_count});
// iterate over all params
@ -56,8 +57,11 @@ const Handler = struct {
else => {
// might be a string param, we don't care
// let's just get it as string
// always_alloc param = false -> the string will be a slice from the request buffer
// --> no deinit necessary
if (r.getParamStr(Handler.alloc, kv.key.str, false)) |maybe_str| {
const value: []const u8 = if (maybe_str) |s| s.str else "(no value)";
// above, we didn't defer s.deinit because the string is just a slice from the request buffer
std.log.debug(" {s} = {s}", .{ kv.key.str, value });
} else |err| {
std.log.err("Error: {any}\n", .{err});
@ -70,7 +74,6 @@ const Handler = struct {
// check if we received a terminate=true parameter
if (r.getParamStr(Handler.alloc, "terminate", false)) |maybe_str| {
if (maybe_str) |*s| {
defer s.deinit();
std.log.info("?terminate={s}\n", .{s.str});
if (std.mem.eql(u8, s.str, "true")) {
zap.stop();
@ -87,7 +90,7 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
var allocator = gpa.allocator();
const allocator = gpa.allocator();
Handler.alloc = allocator;

View file

@ -5,17 +5,19 @@ const zap = @import("zap");
fn makeRequest(a: std.mem.Allocator, url: []const u8) !void {
const uri = try std.Uri.parse(url);
var h = std.http.Headers{ .allocator = a };
defer h.deinit();
var http_client: std.http.Client = .{ .allocator = a };
defer http_client.deinit();
var req = try http_client.request(.GET, uri, h, .{});
var server_header_buffer: [2048]u8 = undefined;
var req = try http_client.open(.GET, uri, .{
.server_header_buffer = &server_header_buffer,
.extra_headers = &.{
.{ .name = "cookie", .value = "ZIG_ZAP=awesome" },
},
});
defer req.deinit();
try req.headers.append("cookie", "ZIG_ZAP=awesome");
try req.start();
try req.send();
try req.wait();
}
@ -28,7 +30,7 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
var allocator = gpa.allocator();
const allocator = gpa.allocator();
const Handler = struct {
var alloc: std.mem.Allocator = undefined;
@ -37,17 +39,19 @@ pub fn main() !void {
std.debug.print("\n=====================================================\n", .{});
defer std.debug.print("=====================================================\n\n", .{});
r.parseCookies(false);
r.parseCookies(false); // url_encoded = false
var cookie_count = r.getCookiesCount();
const cookie_count = r.getCookiesCount();
std.log.info("cookie_count: {}", .{cookie_count});
// iterate over all cookies as strings
// iterate over all cookies as strings (always_alloc=false)
var strCookies = r.cookiesToOwnedStrList(alloc, false) catch unreachable;
defer strCookies.deinit();
std.debug.print("\n", .{});
for (strCookies.items) |kv| {
std.log.info("CookieStr `{s}` is `{s}`", .{ kv.key.str, kv.value.str });
// we don't need to deinit kv.key and kv.value because we requested always_alloc=false
// so they are just slices into the request buffer
}
std.debug.print("\n", .{});
@ -63,7 +67,7 @@ pub fn main() !void {
std.debug.print("\n", .{});
if (r.getCookieStr(alloc, "ZIG_ZAP", false)) |maybe_str| {
if (maybe_str) |*s| {
defer s.deinit();
defer s.deinit(); // unnecessary because always_alloc=false
std.log.info("Cookie ZIG_ZAP = {s}", .{s.str});
} else {

View file

@ -3,7 +3,7 @@ const zap = @import("zap");
const UserWeb = @import("userweb.zig");
const StopEndpoint = @import("stopendpoint.zig");
// this is just to demo that we can catch arbitrary slugs
// this is just to demo that we can catch arbitrary slugs as fallback
fn on_request(r: zap.Request) void {
if (r.path) |the_path| {
std.debug.print("REQUESTED PATH: {s}\n", .{the_path});
@ -16,7 +16,7 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
var allocator = gpa.allocator();
const allocator = gpa.allocator();
// we scope everything that can allocate within this block for leak detection
{
@ -56,7 +56,7 @@ pub fn main() !void {
// and run
zap.start(.{
.threads = 2000,
.threads = 2,
// IMPORTANT! It is crucial to only have a single worker for this example to work!
// Multiple workers would have multiple copies of the users hashmap.
//

View file

@ -41,12 +41,12 @@ pub fn addByName(self: *Self, first: ?[]const u8, last: ?[]const u8) !usize {
user.lastnamelen = 0;
if (first) |firstname| {
std.mem.copy(u8, user.firstnamebuf[0..], firstname);
@memcpy(user.firstnamebuf[0..firstname.len], firstname);
user.firstnamelen = firstname.len;
}
if (last) |lastname| {
std.mem.copy(u8, user.lastnamebuf[0..], lastname);
@memcpy(user.lastnamebuf[0..lastname.len], lastname);
user.lastnamelen = lastname.len;
}
@ -101,11 +101,11 @@ pub fn update(
pUser.firstnamelen = 0;
pUser.lastnamelen = 0;
if (first) |firstname| {
std.mem.copy(u8, pUser.firstnamebuf[0..], firstname);
@memcpy(pUser.firstnamebuf[0..firstname.len], firstname);
pUser.firstnamelen = firstname.len;
}
if (last) |lastname| {
std.mem.copy(u8, pUser.lastnamebuf[0..], lastname);
@memcpy(pUser.lastnamebuf[0..lastname.len], lastname);
pUser.lastnamelen = lastname.len;
}
}

View file

@ -54,7 +54,8 @@ fn userIdFromPath(self: *Self, path: []const u8) ?usize {
}
fn getUser(e: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "ep", e);
const self: *Self = @fieldParentPtr("ep", e);
if (r.path) |path| {
// /users
if (path.len == e.settings.path.len) {
@ -81,9 +82,9 @@ fn listUsers(self: *Self, r: zap.Request) void {
}
fn postUser(e: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "ep", e);
const self: *Self = @fieldParentPtr("ep", e);
if (r.body) |body| {
var 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| {
defer u.deinit();
if (self._users.addByName(u.value.first_name, u.value.last_name)) |id| {
@ -100,12 +101,12 @@ fn postUser(e: *zap.Endpoint, r: zap.Request) void {
}
fn putUser(e: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "ep", e);
const self: *Self = @fieldParentPtr("ep", e);
if (r.path) |path| {
if (self.userIdFromPath(path)) |id| {
if (self._users.get(id)) |_| {
if (r.body) |body| {
var 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| {
defer u.deinit();
var jsonbuf: [128]u8 = undefined;
@ -126,7 +127,7 @@ fn putUser(e: *zap.Endpoint, r: zap.Request) void {
}
fn deleteUser(e: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "ep", e);
const self: *Self = @fieldParentPtr("ep", e);
if (r.path) |path| {
if (self.userIdFromPath(path)) |id| {
var jsonbuf: [128]u8 = undefined;

View file

@ -41,7 +41,7 @@ fn setupUserData(a: std.mem.Allocator) !void {
}
pub fn main() !void {
var a = std.heap.page_allocator;
const a = std.heap.page_allocator;
try setupUserData(a);
var listener = zap.HttpListener.init(.{
.port = 3000,

View file

@ -5,16 +5,16 @@ const zap = @import("zap");
fn makeRequest(a: std.mem.Allocator, url: []const u8) !void {
const uri = try std.Uri.parse(url);
var h = std.http.Headers{ .allocator = a };
defer h.deinit();
var http_client: std.http.Client = .{ .allocator = a };
defer http_client.deinit();
var req = try http_client.request(.GET, uri, h, .{});
var server_header_buffer: [2048]u8 = undefined;
var req = try http_client.open(.GET, uri, .{
.server_header_buffer = &server_header_buffer,
});
defer req.deinit();
try req.start();
try req.send();
try req.wait();
}
@ -27,7 +27,7 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
var allocator = gpa.allocator();
const allocator = gpa.allocator();
const Handler = struct {
var alloc: std.mem.Allocator = undefined;
@ -44,7 +44,7 @@ pub fn main() !void {
// check for query parameters
r.parseQuery();
var param_count = r.getParamCount();
const param_count = r.getParamCount();
std.log.info("param_count: {}", .{param_count});
// ================================================================

View file

@ -30,7 +30,7 @@ fn help_and_exit(filename: []const u8, err: anyerror) void {
,
.{ filename, err },
);
std.os.exit(1);
std.process.exit(1);
}
pub fn main() !void {
const CERT_FILE = "mycert.pem";

View file

@ -72,7 +72,7 @@ const UserMiddleWare = struct {
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
// this is how we would get our self pointer
var self = @fieldParentPtr(Self, "handler", handler);
const self: *Self = @fieldParentPtr("handler", handler);
_ = self;
// do our work: fill in the user field of the context
@ -115,7 +115,7 @@ const SessionMiddleWare = struct {
// note that the first parameter is of type *Handler, not *Self !!!
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
// this is how we would get our self pointer
var self = @fieldParentPtr(Self, "handler", handler);
const self: *Self = @fieldParentPtr("handler", handler);
_ = self;
context.session = Session{
@ -151,7 +151,7 @@ const HtmlMiddleWare = struct {
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
// this is how we would get our self pointer
var self = @fieldParentPtr(Self, "handler", handler);
const self: *Self = @fieldParentPtr("handler", handler);
_ = self;
std.debug.print("\n\nHtmlMiddleware: handling request with context: {any}\n\n", .{context});
@ -190,7 +190,7 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
var allocator = gpa.allocator();
const allocator = gpa.allocator();
SharedAllocator.init(allocator);
// we create our HTML middleware component that handles the request

View file

@ -60,7 +60,7 @@ const UserMiddleWare = struct {
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
// this is how we would get our self pointer
var self = @fieldParentPtr(Self, "handler", handler);
const self: *Self = @fieldParentPtr("handler", handler);
_ = self;
// do our work: fill in the user field of the context
@ -105,7 +105,7 @@ const SessionMiddleWare = struct {
// note that the first parameter is of type *Handler, not *Self !!!
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
// this is how we would get our self pointer
var self = @fieldParentPtr(Self, "handler", handler);
const self: *Self = @fieldParentPtr("handler", handler);
_ = self;
context.session = Session{
@ -155,7 +155,7 @@ const HtmlEndpoint = struct {
}
pub fn get(ep: *zap.Endpoint, r: zap.Request) void {
const self = @fieldParentPtr(Self, "ep", ep);
const self: *Self = @fieldParentPtr("ep", ep);
_ = self;
var buf: [1024]u8 = undefined;
@ -200,7 +200,7 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
var allocator = gpa.allocator();
const allocator = gpa.allocator();
SharedAllocator.init(allocator);
// create the endpoint

View file

@ -73,7 +73,7 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
var allocator = gpa.allocator();
const allocator = gpa.allocator();
var simpleRouter = zap.Router.init(allocator, .{
.not_found = not_found,

View file

@ -46,8 +46,8 @@ const ContextManager = struct {
self.lock.lock();
defer self.lock.unlock();
var ctx = try self.allocator.create(Context);
var userName = try std.fmt.allocPrint(
const ctx = try self.allocator.create(Context);
const userName = try std.fmt.allocPrint(
self.allocator,
"{s}{d}",
.{ self.usernamePrefix, self.contexts.items.len },
@ -202,7 +202,7 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
var allocator = gpa.allocator();
const allocator = gpa.allocator();
GlobalContextManager = ContextManager.init(allocator, "chatroom", "user-");
defer GlobalContextManager.deinit();

View file

@ -2,11 +2,11 @@ const std = @import("std");
pub fn build_facilio(
comptime subdir: []const u8,
b: *std.build.Builder,
target: std.zig.CrossTarget,
b: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
use_openssl: bool,
) !*std.build.CompileStep {
) !*std.Build.Step.Compile {
const lib = b.addStaticLibrary(.{
.name = "facil.io",
.target = target,
@ -15,7 +15,7 @@ pub fn build_facilio(
// Generate flags
var flags = std.ArrayList([]const u8).init(std.heap.page_allocator);
if (lib.optimize != .Debug) try flags.append("-Os");
if (optimize != .Debug) try flags.append("-Os");
try flags.append("-Wno-return-type-c-linkage");
try flags.append("-fno-sanitize=undefined");
@ -26,7 +26,7 @@ pub fn build_facilio(
//
try flags.append("-DFIO_HTTP_EXACT_LOGGING");
if (target.getAbi() == .musl)
if (target.result.abi == .musl)
try flags.append("-D_LARGEFILE64_SOURCE");
if (use_openssl)
try flags.append("-DHAVE_OPENSSL -DFIO_TLS_FOUND");
@ -42,30 +42,36 @@ pub fn build_facilio(
lib.addIncludePath(.{ .path = subdir ++ "/lib/facil/tls" });
// C source files
lib.addCSourceFiles(&.{
subdir ++ "/lib/facil/fio.c",
subdir ++ "/lib/facil/fio_zig.c",
subdir ++ "/lib/facil/http/http.c",
subdir ++ "/lib/facil/http/http1.c",
subdir ++ "/lib/facil/http/websockets.c",
subdir ++ "/lib/facil/http/http_internal.c",
subdir ++ "/lib/facil/fiobj/fiobj_numbers.c",
subdir ++ "/lib/facil/fiobj/fio_siphash.c",
subdir ++ "/lib/facil/fiobj/fiobj_str.c",
subdir ++ "/lib/facil/fiobj/fiobj_ary.c",
subdir ++ "/lib/facil/fiobj/fiobj_data.c",
subdir ++ "/lib/facil/fiobj/fiobj_hash.c",
subdir ++ "/lib/facil/fiobj/fiobj_json.c",
subdir ++ "/lib/facil/fiobj/fiobject.c",
subdir ++ "/lib/facil/fiobj/fiobj_mustache.c",
subdir ++ "/lib/facil/cli/fio_cli.c",
}, flags.items);
lib.addCSourceFiles(.{
.files = &.{
subdir ++ "/lib/facil/fio.c",
subdir ++ "/lib/facil/fio_zig.c",
subdir ++ "/lib/facil/http/http.c",
subdir ++ "/lib/facil/http/http1.c",
subdir ++ "/lib/facil/http/websockets.c",
subdir ++ "/lib/facil/http/http_internal.c",
subdir ++ "/lib/facil/fiobj/fiobj_numbers.c",
subdir ++ "/lib/facil/fiobj/fio_siphash.c",
subdir ++ "/lib/facil/fiobj/fiobj_str.c",
subdir ++ "/lib/facil/fiobj/fiobj_ary.c",
subdir ++ "/lib/facil/fiobj/fiobj_data.c",
subdir ++ "/lib/facil/fiobj/fiobj_hash.c",
subdir ++ "/lib/facil/fiobj/fiobj_json.c",
subdir ++ "/lib/facil/fiobj/fiobject.c",
subdir ++ "/lib/facil/fiobj/fiobj_mustache.c",
subdir ++ "/lib/facil/cli/fio_cli.c",
},
.flags = flags.items,
});
if (use_openssl) {
lib.addCSourceFiles(&.{
subdir ++ "/lib/facil/tls/fio_tls_openssl.c",
subdir ++ "/lib/facil/tls/fio_tls_missing.c",
}, flags.items);
lib.addCSourceFiles(.{
.files = &.{
subdir ++ "/lib/facil/tls/fio_tls_openssl.c",
subdir ++ "/lib/facil/tls/fio_tls_missing.c",
},
.flags = flags.items,
});
}
// link against libc

View file

@ -2,4 +2,3 @@
.name = "facil.io",
.version = "0.0.12",
}

44
flake.lock generated
View file

@ -3,11 +3,11 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
@ -37,11 +37,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1689068808,
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
@ -55,11 +55,11 @@
"systems": "systems_2"
},
"locked": {
"lastModified": 1685518550,
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
@ -92,11 +92,11 @@
},
"locked": {
"dir": "contrib",
"lastModified": 1692702614,
"narHash": "sha256-FeY8hAB77tnUTDbK6WYA+DG3Nx5xQrbOC17Cfl3pTm4=",
"lastModified": 1704461694,
"narHash": "sha256-dQc9Bkh5uf0R4po3NWnCGx+3eqOZR7iSR4jmRvNNm+E=",
"owner": "neovim",
"repo": "neovim",
"rev": "014b87646fc3273a09d6b20ebb648a8eb24a0a98",
"rev": "c509f4907bf7405c9c2ae3f7eff76c5d552944cc",
"type": "github"
},
"original": {
@ -108,11 +108,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1702882221,
"narHash": "sha256-L/uOrBqkGsa45EvQk4DLq/aR6JeomW+7Mwe0mC/dVUM=",
"lastModified": 1704290814,
"narHash": "sha256-LWvKHp7kGxk/GEtlrGYV68qIvPHkU9iToomNFGagixU=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "25fef6e30d8ad48f47a8411ccfe986d8baed8a15",
"rev": "70bdadeb94ffc8806c0570eb5c2695ad29f0e421",
"type": "github"
},
"original": {
@ -124,16 +124,16 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1689088367,
"narHash": "sha256-Y2tl2TlKCWEHrOeM9ivjCLlRAKH3qoPUE/emhZECU14=",
"lastModified": 1702350026,
"narHash": "sha256-A+GNZFZdfl4JdDphYKBJ5Ef1HOiFsP18vQe9mqjmUis=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5c9ddb86679c400d6b7360797b8a22167c2053f8",
"rev": "9463103069725474698139ab10f17a9d125da859",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-23.05",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"type": "github"
}
@ -184,11 +184,11 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1692663634,
"narHash": "sha256-wioqr80UOA0tNXaJy4D0i9fFaLG2RoQi5e9Dpd4WojE=",
"lastModified": 1704888534,
"narHash": "sha256-douEXUiWCVL9NvWKYBc8ydq51qLLUwlBo6lJJoktkGw=",
"owner": "mitchellh",
"repo": "zig-overlay",
"rev": "d666e5137fe0c43353c555fb47748813084decab",
"rev": "c69295c92a98947295755a9ac2d49a8d447cc04d",
"type": "github"
},
"original": {

View file

@ -90,6 +90,7 @@
devShells.build = pkgs.mkShell {
nativeBuildInputs = with pkgs; [
zigpkgs."0.11.0"
pkgs.openssl
];
buildInputs = with pkgs; [
@ -103,6 +104,28 @@
# once we set SHELL to point to the interactive bash, neovim will
# launch the correct $SHELL in its :terminal
export SHELL=${pkgs.bashInteractive}/bin/bash
export LD_LIBRARY_PATH=${pkgs.zlib.out}/lib:${pkgs.icu.out}/lib:${pkgs.openssl.out}/lib:$LD_LIBRARY_PATH
'';
};
devShells.masta = pkgs.mkShell {
nativeBuildInputs = with pkgs; [
zigpkgs.master
pkgs.openssl
];
buildInputs = with pkgs; [
# we need a version of bash capable of being interactive
# as opposed to a bash just used for building this flake
# in non-interactive mode
bashInteractive
];
shellHook = ''
# once we set SHELL to point to the interactive bash, neovim will
# launch the correct $SHELL in its :terminal
export SHELL=${pkgs.bashInteractive}/bin/bash
export LD_LIBRARY_PATH=${pkgs.zlib.out}/lib:${pkgs.icu.out}/lib:${pkgs.openssl.out}/lib:$LD_LIBRARY_PATH
'';
};

View file

@ -112,7 +112,7 @@ pub fn Authenticating(comptime Authenticator: type) type {
/// GET: here, the auth_endpoint will be passed in as endpoint.
/// Authenticates GET requests using the Authenticator.
pub fn get(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => {
if (e.settings.unauthorized) |unauthorized| {
@ -132,7 +132,7 @@ pub fn Authenticating(comptime Authenticator: type) type {
/// POST: here, the auth_endpoint will be passed in as endpoint.
/// Authenticates POST requests using the Authenticator.
pub fn post(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => {
if (e.settings.unauthorized) |unauthorized| {
@ -152,7 +152,7 @@ pub fn Authenticating(comptime Authenticator: type) type {
/// PUT: here, the auth_endpoint will be passed in as endpoint.
/// Authenticates PUT requests using the Authenticator.
pub fn put(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => {
if (e.settings.unauthorized) |unauthorized| {
@ -172,7 +172,7 @@ pub fn Authenticating(comptime Authenticator: type) type {
/// DELETE: here, the auth_endpoint will be passed in as endpoint.
/// Authenticates DELETE requests using the Authenticator.
pub fn delete(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => {
if (e.settings.unauthorized) |unauthorized| {
@ -192,7 +192,7 @@ pub fn Authenticating(comptime Authenticator: type) type {
/// PATCH: here, the auth_endpoint will be passed in as endpoint.
/// Authenticates PATCH requests using the Authenticator.
pub fn patch(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => {
if (e.settings.unauthorized) |unauthorized| {
@ -212,7 +212,7 @@ pub fn Authenticating(comptime Authenticator: type) type {
/// OPTIONS: here, the auth_endpoint will be passed in as endpoint.
/// Authenticates OPTIONS requests using the Authenticator.
pub fn options(e: *Endpoint, r: zap.Request) void {
const authEp: *Self = @fieldParentPtr(Self, "auth_endpoint", e);
const authEp: *Self = @fieldParentPtr("auth_endpoint", e);
switch (authEp.authenticator.authenticateRequest(&r)) {
.AuthFailed => {
if (e.settings.unauthorized) |unauthorized| {

View file

@ -118,10 +118,10 @@ pub const struct_fio_str_info_s = extern struct {
pub const fio_str_info_s = struct_fio_str_info_s;
pub extern fn http_send_body(h: [*c]http_s, data: ?*anyopaque, length: usize) c_int;
pub fn fiobj_each1(arg_o: FIOBJ, arg_start_at: usize, arg_task: ?*const fn (FIOBJ, ?*anyopaque) callconv(.C) c_int, arg_arg: ?*anyopaque) callconv(.C) usize {
var o = arg_o;
var start_at = arg_start_at;
var task = arg_task;
var arg = arg_arg;
const o = arg_o;
const start_at = arg_start_at;
const task = arg_task;
const arg = arg_arg;
if ((((o != 0) and ((o & @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 1))))) == @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 0)))))) and ((o & @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 6))))) != @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 6)))))) and (fiobj_type_vtable(o).*.each != null)) return fiobj_type_vtable(o).*.each.?(o, start_at, task, arg);
return 0;
}
@ -288,8 +288,8 @@ pub const fiobj_object_header_s = extern struct {
ref: u32,
};
pub fn fiobj_type_is(arg_o: FIOBJ, arg_type: fiobj_type_enum) callconv(.C) usize {
var o = arg_o;
var @"type" = arg_type;
const o = arg_o;
const @"type" = arg_type;
while (true) {
switch (@as(c_int, @bitCast(@as(c_uint, @"type")))) {
@as(c_int, 1) => return @as(usize, @bitCast(@as(c_long, @intFromBool(((o & @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 1))))) != 0) or (@as(c_int, @bitCast(@as(c_uint, @as([*c]fiobj_type_enum, @ptrFromInt(o))[@as(c_uint, @intCast(@as(c_int, 0)))]))) == FIOBJ_T_NUMBER))))),
@ -311,7 +311,7 @@ pub fn fiobj_type_is(arg_o: FIOBJ, arg_type: fiobj_type_enum) callconv(.C) usize
return @as(usize, @bitCast(@as(c_long, @intFromBool((((o != 0) and ((o & @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 1))))) == @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 0)))))) and ((o & @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 6))))) != @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 6)))))) and (@as(c_int, @bitCast(@as(c_uint, @as([*c]fiobj_type_enum, @ptrCast(@alignCast(@as(?*anyopaque, @ptrFromInt(o & ~@as(usize, @bitCast(@as(c_long, @as(c_int, 7)))))))))[@as(c_uint, @intCast(@as(c_int, 0)))]))) == @as(c_int, @bitCast(@as(c_uint, @"type"))))))));
}
pub fn fiobj_type(arg_o: FIOBJ) callconv(.C) fiobj_type_enum {
var o = arg_o;
const o = arg_o;
if (!(o != 0)) return @as(u8, @bitCast(@as(i8, @truncate(FIOBJ_T_NULL))));
if ((o & @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 1))))) != 0) return @as(u8, @bitCast(@as(i8, @truncate(FIOBJ_T_NUMBER))));
if ((o & @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 6))))) == @as(c_ulong, @bitCast(@as(c_long, @as(c_int, 6))))) return @as(u8, @bitCast(@as(u8, @truncate(o))));
@ -326,7 +326,7 @@ pub extern const FIOBJECT_VTABLE_ARRAY: fiobj_object_vtable_s;
pub extern const FIOBJECT_VTABLE_HASH: fiobj_object_vtable_s;
pub extern const FIOBJECT_VTABLE_DATA: fiobj_object_vtable_s;
pub fn fiobj_type_vtable(arg_o: FIOBJ) callconv(.C) [*c]const fiobj_object_vtable_s {
var o = arg_o;
const o = arg_o;
while (true) {
switch (@as(c_int, @bitCast(@as(c_uint, fiobj_type(o))))) {
@as(c_int, 1) => return &FIOBJECT_VTABLE_NUMBER,
@ -361,7 +361,7 @@ pub fn fiobj_obj2float(o: FIOBJ) callconv(.C) f64 {
pub extern fn fio_ltocstr(c_long) fio_str_info_s;
pub fn fiobj_obj2cstr(o: FIOBJ) callconv(.C) fio_str_info_s {
if (!(o != 0)) {
var ret: fio_str_info_s = fio_str_info_s{
const ret: fio_str_info_s = fio_str_info_s{
.capa = @as(usize, @bitCast(@as(c_long, @as(c_int, 0)))),
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 4)))),
.data = @as([*c]u8, @ptrFromInt(@intFromPtr("null"))),
@ -374,7 +374,7 @@ pub fn fiobj_obj2cstr(o: FIOBJ) callconv(.C) fio_str_info_s {
switch (@as(c_int, @bitCast(@as(c_uint, @as(u8, @bitCast(@as(u8, @truncate(o)))))))) {
@as(c_int, 6) => {
{
var ret: fio_str_info_s = fio_str_info_s{
const ret: fio_str_info_s = fio_str_info_s{
.capa = @as(usize, @bitCast(@as(c_long, @as(c_int, 0)))),
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 4)))),
.data = @as([*c]u8, @ptrFromInt(@intFromPtr("null"))),
@ -384,7 +384,7 @@ pub fn fiobj_obj2cstr(o: FIOBJ) callconv(.C) fio_str_info_s {
},
@as(c_int, 38) => {
{
var ret: fio_str_info_s = fio_str_info_s{
const ret: fio_str_info_s = fio_str_info_s{
.capa = @as(usize, @bitCast(@as(c_long, @as(c_int, 0)))),
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 5)))),
.data = @as([*c]u8, @ptrFromInt(@intFromPtr("false"))),
@ -394,7 +394,7 @@ pub fn fiobj_obj2cstr(o: FIOBJ) callconv(.C) fio_str_info_s {
},
@as(c_int, 22) => {
{
var ret: fio_str_info_s = fio_str_info_s{
const ret: fio_str_info_s = fio_str_info_s{
.capa = @as(usize, @bitCast(@as(c_long, @as(c_int, 0)))),
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 4)))),
.data = @as([*c]u8, @ptrFromInt(@intFromPtr("true"))),
@ -556,8 +556,8 @@ pub extern fn http_date2rfc7231(target: [*c]u8, tmbuf: [*c]struct_tm) usize;
pub extern fn http_date2rfc2109(target: [*c]u8, tmbuf: [*c]struct_tm) usize;
pub extern fn http_date2rfc2822(target: [*c]u8, tmbuf: [*c]struct_tm) usize;
pub fn http_date2str(arg_target: [*c]u8, arg_tmbuf: [*c]struct_tm) callconv(.C) usize {
var target = arg_target;
var tmbuf = arg_tmbuf;
const target = arg_target;
const tmbuf = arg_tmbuf;
return http_date2rfc7231(target, tmbuf);
}
pub extern fn http_time2str(target: [*c]u8, t: time_t) usize;

View file

@ -122,7 +122,7 @@ pub fn Basic(comptime Lookup: type, comptime kind: BasicAuthStrategy) type {
);
return .AuthFailed;
}
var decoded = buffer[0..decoded_size];
const decoded = buffer[0..decoded_size];
decoder.decode(decoded, encoded) catch |err| {
zap.debug(
"ERROR: UserPassAuth: unable to decode `{s}`: {any}\n",
@ -400,7 +400,7 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
lookup: *Lookup,
args: UserPassSessionArgs,
) !Self {
var ret: Self = .{
const ret: Self = .{
.allocator = allocator,
.settings = .{
.usernameParam = try allocator.dupe(u8, args.usernameParam),

View file

@ -82,7 +82,7 @@ pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anyt
/// If `breakOnFinish` is `true`, the handler will stop handing requests down the chain if
/// the endpoint processed the request.
pub fn onRequest(handler: *HandlerType, r: zap.Request, context: *ContextType) bool {
var self = @fieldParentPtr(Self, "handler", handler);
const self: *Self = @fieldParentPtr("handler", handler);
r.setUserContext(context);
self.endpoint.onRequest(r);

View file

@ -146,10 +146,10 @@ fn makeRequest(a: std.mem.Allocator, url: []const u8, auth: ?ClientAuthReqHeader
var http_client: std.http.Client = .{ .allocator = a };
defer http_client.deinit();
var req = try http_client.request(.GET, uri, h, .{});
var req = try http_client.open(.GET, uri, h, .{});
defer req.deinit();
try req.start();
try req.send(.{});
try req.wait();
// req.deinit() panics!
// defer req.deinit();

View file

@ -10,10 +10,10 @@ fn makeRequest(a: std.mem.Allocator, url: []const u8) !void {
var http_client: std.http.Client = .{ .allocator = a };
defer http_client.deinit();
var req = try http_client.request(.GET, uri, h, .{});
var req = try http_client.open(.GET, uri, h, .{});
defer req.deinit();
try req.start();
try req.send(.{});
try req.wait();
zap.stop();
}
@ -23,7 +23,7 @@ fn makeRequestThread(a: std.mem.Allocator, url: []const u8) !std.Thread {
}
test "http parameters" {
var allocator = std.testing.allocator;
const allocator = std.testing.allocator;
const Handler = struct {
var alloc: std.mem.Allocator = undefined;

View file

@ -15,10 +15,10 @@ fn makeRequest(a: std.mem.Allocator, url: []const u8) !void {
var http_client: std.http.Client = .{ .allocator = a };
defer http_client.deinit();
var req = try http_client.request(.GET, uri, h, .{});
var req = try http_client.open(.GET, uri, h, .{});
defer req.deinit();
try req.start();
try req.send(.{});
try req.wait();
read_len = try req.readAll(&buffer);
@ -33,7 +33,7 @@ pub fn on_request(r: zap.Request) void {
}
test "send file" {
var allocator = std.testing.allocator;
const allocator = std.testing.allocator;
// setup listener
var listener = zap.HttpListener.init(

View file

@ -50,7 +50,7 @@ pub fn Handler(comptime ContextType: type) type {
/// This function will end the HTTP stage of the connection and attempt to "upgrade" to a WebSockets connection.
pub fn upgrade(h: [*c]fio.http_s, settings: *WebSocketSettings) WebSocketError!void {
var fio_settings: fio.websocket_settings_s = .{
const fio_settings: fio.websocket_settings_s = .{
.on_message = internal_on_message,
.on_open = internal_on_open,
.on_ready = internal_on_ready,
@ -64,8 +64,8 @@ pub fn Handler(comptime ContextType: type) type {
}
fn internal_on_message(handle: WsHandle, msg: fio.fio_str_info_s, is_text: u8) callconv(.C) void {
var user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(fio.websocket_udata_get(handle))));
var message = msg.data[0..msg.len];
const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(fio.websocket_udata_get(handle))));
const message = msg.data[0..msg.len];
if (user_provided_settings) |settings| {
if (settings.on_message) |on_message| {
on_message(settings.context, handle, message, is_text == 1);
@ -74,7 +74,7 @@ pub fn Handler(comptime ContextType: type) type {
}
fn internal_on_open(handle: WsHandle) callconv(.C) void {
var 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 (settings.on_open) |on_open| {
on_open(settings.context, handle);
@ -83,7 +83,7 @@ pub fn Handler(comptime ContextType: type) type {
}
fn internal_on_ready(handle: WsHandle) callconv(.C) void {
var 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 (settings.on_ready) |on_ready| {
on_ready(settings.context, handle);
@ -92,7 +92,7 @@ pub fn Handler(comptime ContextType: type) type {
}
fn internal_on_shutdown(handle: WsHandle) callconv(.C) void {
var 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 (settings.on_shutdown) |on_shutdown| {
on_shutdown(settings.context, handle);
@ -101,7 +101,7 @@ pub fn Handler(comptime ContextType: type) type {
}
fn internal_on_close(uuid: isize, udata: ?*anyopaque) callconv(.C) void {
var 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 (settings.on_close) |on_close| {
on_close(settings.context, uuid);
@ -119,7 +119,7 @@ pub fn Handler(comptime ContextType: type) type {
pub inline fn write(handle: WsHandle, message: []const u8, is_text: bool) WebSocketError!void {
if (fio.websocket_write(
handle,
fio.str2fio(message),
util.str2fio(message),
if (is_text) 1 else 0,
) != 0) {
return error.WriteError;
@ -192,7 +192,7 @@ pub fn Handler(comptime ContextType: type) type {
/// we need it to look up the ziggified callbacks.
pub inline fn subscribe(handle: WsHandle, args: *SubscribeArgs) WebSocketError!usize {
if (handle == null) return error.SubscribeError;
var fio_args: fio.websocket_subscribe_s_zigcompat = .{
const fio_args: fio.websocket_subscribe_s_zigcompat = .{
.ws = handle.?,
.channel = util.str2fio(args.channel),
.on_message = if (args.on_message) |_| internal_subscription_on_message else null,

View file

@ -43,7 +43,7 @@ pub const Tls = @import("tls.zig");
/// }
///
/// fn get(e: *zap.Endpoint, r: zap.Request) void {
/// const self: *StopEndpoint = @fieldParentPtr(StopEndpoint, "ep", e);
/// const self: *StopEndpoint = @fieldParentPtr("ep", e);
/// _ = self;
/// _ = r;
/// zap.stop();

View file

@ -28,7 +28,8 @@ fn usage() void {
\\ instructions
;
std.debug.print("{s}", .{message});
std.os.exit(1);
std.process.exit(1);
}
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
@ -88,7 +89,7 @@ fn get_tag_annotation(allocator: std.mem.Allocator, tagname: []const u8) ![]cons
tagname,
};
const result = try std.ChildProcess.exec(.{
const result = try std.ChildProcess.run(.{
.allocator = allocator,
.argv = &args,
});
@ -150,24 +151,26 @@ fn sendToDiscordPart(allocator: std.mem.Allocator, url: []const u8, message_json
// url
const uri = try std.Uri.parse(url);
// http headers
var h = std.http.Headers{ .allocator = allocator };
defer h.deinit();
try h.append("accept", "*/*");
try h.append("Content-Type", "application/json");
// client
var http_client: std.http.Client = .{ .allocator = allocator };
defer http_client.deinit();
var server_header_buffer: [2048]u8 = undefined;
// request
var req = try http_client.request(.POST, uri, h, .{});
var req = try http_client.open(.POST, uri, .{
.server_header_buffer = &server_header_buffer,
.extra_headers = &.{
.{ .name = "accept", .value = "*/*" },
.{ .name = "Content-Type", .value = "application/json" },
},
});
defer req.deinit();
req.transfer_encoding = .chunked;
// connect, send request
try req.start();
try req.send();
// send POST payload
try req.writer().writeAll(message_json);
@ -182,7 +185,7 @@ fn sendToDiscordPart(allocator: std.mem.Allocator, url: []const u8, message_json
fn sendToDiscord(allocator: std.mem.Allocator, url: []const u8, message: []const u8) !void {
// json payload
// max size: 100kB
var buf: []u8 = try allocator.alloc(u8, 100 * 1024);
const buf: []u8 = try allocator.alloc(u8, 100 * 1024);
defer allocator.free(buf);
var fba = std.heap.FixedBufferAllocator.init(buf);
var string = std.ArrayList(u8).init(fba.allocator());
@ -336,7 +339,7 @@ fn command_announce(allocator: std.mem.Allocator, tag: []const u8) !void {
defer allocator.free(url);
sendToDiscord(allocator, url, announcement) catch |err| {
std.debug.print("HTTP ERROR: {any}\n", .{err});
std.os.exit(1);
std.process.exit(1);
};
}
@ -399,7 +402,7 @@ fn command_update_readme(allocator: std.mem.Allocator, tag: []const u8) !void {
// we need to put the \n back in.
// TODO: change this by using some "search" iterator that just
// returns indices etc
var output_line = try std.fmt.allocPrint(allocator, "{s}\n", .{line});
const output_line = try std.fmt.allocPrint(allocator, "{s}\n", .{line});
defer allocator.free(output_line);
_ = try writer.write(output_line);
}

View file

@ -18,7 +18,10 @@ Modify your `build.zig.zon` like this:
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
.hash = "{hash}",
}
},
.paths = .{
"",
},
}
}

View file

@ -6,9 +6,14 @@
.dependencies = .{
// zap {tag}
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
// when tagged:
// .url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
.url = "https://github.com/zigzap/zap/archive/{tag}.tar.gz",
.hash = "{hash}",
}
},
.paths = .{
"",
},
}
}
```

View file

@ -28,7 +28,10 @@ Here is a complete `build.zig.zon` example:
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
.hash = "{hash}",
}
},
.paths = .{
"",
},
}
}
@ -41,7 +44,8 @@ Then, in your `build.zig`'s `build` function, add the following before
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.addModule("zap", zap.module("zap"));
exe.root_module.addImport("zap", zap.module("zap"));
exe.linkLibrary(zap.artifact("facil.io"));
```

44
tools/docserver.zig Normal file
View file

@ -0,0 +1,44 @@
const std = @import("std");
const zap = @import("zap");
fn on_request(r: zap.Request) void {
r.setStatus(.not_found);
r.sendBody("<html><body><h1>404 - File not found</h1></body></html>") catch return;
}
pub fn main() !void {
var args_it = std.process.args();
var port: usize = 8080;
var docs_dir: []const u8 = "zig-out/docs";
while (args_it.next()) |arg| {
if (std.mem.startsWith(u8, arg, "--port=")) {
// try to parse port
if (std.fmt.parseUnsigned(usize, arg[7..], 0)) |the_port| {
port = the_port;
} else |_| {
std.debug.print("Invalid port number. Using default port {}\n", .{port});
}
}
if (std.mem.startsWith(u8, arg, "--docs=")) {
docs_dir = arg[7..];
}
}
var listener = zap.HttpListener.init(.{
.port = port,
.on_request = on_request,
.public_folder = docs_dir,
.log = true,
});
try listener.listen();
std.debug.print("\nServing docs from {s} at 0.0.0.0:{}\n", .{ docs_dir, port });
// start worker threads
zap.start(.{
.threads = 2,
.workers = 1,
});
}

View file

@ -71,7 +71,7 @@ pub const usage_pkg =
;
pub fn gitLatestTag(gpa: Allocator, pkg_dir: []const u8) ![]const u8 {
const result = try std.ChildProcess.exec(.{
const result = try std.ChildProcess.run(.{
.allocator = gpa,
.argv = &.{
"git",
@ -97,7 +97,7 @@ pub fn gitLatestTag(gpa: Allocator, pkg_dir: []const u8) ![]const u8 {
}
pub fn gitFileList(gpa: Allocator, pkg_dir: []const u8) ![]const u8 {
const result = try std.ChildProcess.exec(.{
const result = try std.ChildProcess.run(.{
.allocator = gpa,
.argv = &.{
"git",
@ -266,8 +266,8 @@ pub fn cmdPkg(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
// computePackageHash will close the directory after completion
// std.debug.print("abspath: {s}\n", .{cwd_absolute_path});
var cwd_copy = try fs.openIterableDirAbsolute(cwd_absolute_path, .{});
errdefer cwd_copy.dir.close();
var cwd_copy = try fs.openDirAbsolute(cwd_absolute_path, .{});
errdefer cwd_copy.close();
var thread_pool: ThreadPool = undefined;
try thread_pool.init(.{ .allocator = gpa });
@ -281,7 +281,7 @@ pub fn cmdPkg(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
};
break :blk try computePackageHashExcludingDirectories(
&thread_pool,
.{ .dir = cwd_copy.dir },
cwd_copy,
excluded_directories,
);
};
@ -355,7 +355,7 @@ fn isExecutable(file: fs.File) !bool {
pub fn computePackageHashExcludingDirectories(
thread_pool: *ThreadPool,
pkg_dir: fs.IterableDir,
pkg_dir: fs.Dir,
excluded_directories: []const []const u8,
) ![Manifest.Hash.digest_length]u8 {
const gpa = thread_pool.allocator;
@ -405,7 +405,7 @@ pub fn computePackageHashExcludingDirectories(
.failure = undefined, // to be populated by the worker
};
wait_group.start();
try thread_pool.spawn(workerHashFile, .{ pkg_dir.dir, hashed_file, &wait_group });
try thread_pool.spawn(workerHashFile, .{ pkg_dir, hashed_file, &wait_group });
try all_files.append(hashed_file);
}

View file

@ -1,43 +1,33 @@
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
var allocator = gpa.allocator();
var server = std.http.Server.init(allocator, .{
.reuse_address = true,
});
defer server.deinit();
// var gpa = std.heap.GeneralPurposeAllocator(.{
// .thread_safe = true,
// }){};
// const allocator = gpa.allocator();
const address = try std.net.Address.parseIp("127.0.0.1", 3000);
try server.listen(address);
var http_server = try address.listen(.{
.reuse_address = true,
});
const max_header_size = 8192;
var read_buffer: [2048]u8 = undefined;
// const max_header_size = 8192;
while (true) {
var res = try server.accept(.{
.allocator = allocator,
.header_strategy = .{ .dynamic = max_header_size },
});
// const start_time = std.time.nanoTimestamp();
defer res.deinit();
defer _ = res.reset();
try res.wait();
const connection = try http_server.accept();
defer connection.stream.close();
var server = std.http.Server.init(connection, &read_buffer);
var request = try server.receiveHead();
const server_body: []const u8 = "HI FROM ZIG STD!\n";
res.transfer_encoding = .{ .content_length = server_body.len };
try res.headers.append("content-type", "text/plain");
try res.headers.append("connection", "close");
try res.do();
var buf: [128]u8 = undefined;
_ = try res.readAll(&buf);
_ = try res.writer().writeAll(server_body);
try res.finish();
// const end_time = std.time.nanoTimestamp();
// const diff = end_time - start_time;
// std.debug.print("{d}\n", .{diff});
try request.respond(server_body, .{
.extra_headers = &.{
.{ .name = "content_type", .value = "text/plain" },
.{ .name = "connection", .value = "close" },
},
});
}
}