mirror of
https://github.com/zigzap/zap.git
synced 2025-10-21 15:44:10 +00:00
Merge branch 'zigzap:master' into master
This commit is contained in:
commit
53774bef60
45 changed files with 777 additions and 430 deletions
|
@ -1,4 +1,4 @@
|
||||||
name: Works with Zig 0.11.0
|
name: Works with Zig 0.12.0
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
@ -18,7 +18,7 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: goto-bus-stop/setup-zig@v2
|
- uses: goto-bus-stop/setup-zig@v2
|
||||||
with:
|
with:
|
||||||
version: 0.11.0
|
version: 0.12.0
|
||||||
- name: Check zig version
|
- name: Check zig version
|
||||||
run: zig version
|
run: zig version
|
||||||
- name: Build all examples
|
- name: Build all examples
|
47
.github/workflows/mastercheck-localhost.yml
vendored
47
.github/workflows/mastercheck-localhost.yml
vendored
|
@ -1,47 +0,0 @@
|
||||||
name: Works with Zig master (localhost patch)
|
|
||||||
on:
|
|
||||||
# push:
|
|
||||||
# branches:
|
|
||||||
# - master
|
|
||||||
# pull_request:
|
|
||||||
# branches:
|
|
||||||
# - master
|
|
||||||
# schedule:
|
|
||||||
# - cron: "0 0 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ci:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
# platform: [ubuntu-latest, windows-latest, macos-latest]
|
|
||||||
platform: [ubuntu-latest]
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: goto-bus-stop/setup-zig@v2
|
|
||||||
with:
|
|
||||||
version: master
|
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.10'
|
|
||||||
- name: wget
|
|
||||||
uses: wei/wget@v1
|
|
||||||
with:
|
|
||||||
args: https://github.com/zigzap/facil.io/archive/refs/tags/zap-0.0.8.tar.gz
|
|
||||||
- name: Check zig version
|
|
||||||
run: zig version
|
|
||||||
- name: hack build.zig.zon
|
|
||||||
run: |
|
|
||||||
mv build.zig.zon build.zig.zon.moved && mv build.zig.zon.localhost build.zig.zon && python -m http.server &
|
|
||||||
sleep 3
|
|
||||||
zig build
|
|
||||||
- name: Build all examples
|
|
||||||
run: zig build all
|
|
||||||
- name: Run authentication tests
|
|
||||||
run: zig build test-authentication
|
|
||||||
- name: Run http parameter tests
|
|
||||||
run: zig build test-httpparams
|
|
||||||
- name: Run sendfile tests
|
|
||||||
run: zig build test-sendfile
|
|
||||||
|
|
65
.github/workflows/mastercheck.yml
vendored
65
.github/workflows/mastercheck.yml
vendored
|
@ -1,21 +1,20 @@
|
||||||
name: Works with Zig master
|
name: Works with Zig master
|
||||||
on:
|
on:
|
||||||
# push:
|
push:
|
||||||
# branches:
|
branches:
|
||||||
# - master
|
- zig-0.13.0
|
||||||
# pull_request:
|
pull_request:
|
||||||
# branches:
|
branches:
|
||||||
# - master
|
- zig-0.13.0
|
||||||
# schedule:
|
schedule:
|
||||||
# - cron: "0 0 * * *"
|
- cron: "0 0 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
# platform: [ubuntu-latest, windows-latest, macos-latest]
|
platform: [ubuntu-latest, macos-latest]
|
||||||
platform: [ubuntu-latest]
|
|
||||||
runs-on: ${{ matrix.platform }}
|
runs-on: ${{ matrix.platform }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
@ -26,5 +25,45 @@ jobs:
|
||||||
run: zig version
|
run: zig version
|
||||||
- name: Build all examples
|
- name: Build all examples
|
||||||
run: zig build all
|
run: zig build all
|
||||||
- name: Run all tests
|
# Run tests separately so we can see more clearly which one fails
|
||||||
run: zig build test
|
- 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.13.0"
|
||||||
|
|
||||||
|
- name: Commit and push if it has changed
|
||||||
|
run: |
|
||||||
|
git diff
|
||||||
|
git checkout zig-0.13.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.13.0
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -11,7 +11,6 @@ wrk/csharp/obj/
|
||||||
wrk/csharp/out/
|
wrk/csharp/out/
|
||||||
scratch
|
scratch
|
||||||
**/.mypy_cache/*
|
**/.mypy_cache/*
|
||||||
docs/
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.vs/
|
.vs/
|
||||||
**/*.perflog
|
**/*.perflog
|
||||||
|
|
67
README.md
67
README.md
|
@ -1,5 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
# ⚡zap⚡ - blazingly fast backends in zig
|
# ⚡zap⚡ - blazingly fast backends in zig
|
||||||
|
|
||||||
  [](https://discord.gg/jQAAN6Ubyj)
|
  [](https://discord.gg/jQAAN6Ubyj)
|
||||||
|
@ -26,18 +24,18 @@ that it proved to be:
|
||||||
|
|
||||||
Exactly the goals I set out to achieve!
|
Exactly the goals I set out to achieve!
|
||||||
|
|
||||||
|
|
||||||
## Most FAQ:
|
## 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-master` 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?**
|
- 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?**
|
- Q: **Zap doesn't build with Zig master?**
|
||||||
- A: See the 0.12.0 branch. An example of how to use it is
|
- A: See the zig-master branch (soon). An example of how to use it is
|
||||||
[here](https://github.com/zigzap/hello-0.12.0). Please note that the 0.12.0
|
[here](https://github.com/zigzap/hello-0.13.0). Please note that the
|
||||||
branch is not the official master branch of ZAP. Yet. Until zig 0.12.0 is
|
zig-master branch is not the official master branch of ZAP. Yet. Until zig
|
||||||
released.
|
0.13.0 is released.
|
||||||
- Q: **Does ZAP work on Windows?**
|
- Q: **Does ZAP work on Windows?**
|
||||||
- A: No. This is due to the underlying facil.io C library. Future versions of
|
- A: No. This is due to the underlying facil.io C library. Future versions of
|
||||||
facil.io might support Windows but there is no timeline yet. Your best options
|
facil.io might support Windows but there is no timeline yet. Your best options
|
||||||
|
@ -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
|
use cases**. Most of the examples are super stripped down to only include
|
||||||
what's necessary to show a feature.
|
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
|
- **Super easy build process**: Zap's `build.zig` now uses the new Zig package
|
||||||
manager for its C-dependencies, no git submodules anymore.
|
manager for its C-dependencies, no git submodules anymore.
|
||||||
- _tested on Linux and macOS (arm, M1)_
|
- _tested on Linux and macOS (arm, M1)_
|
||||||
|
@ -222,7 +224,7 @@ code leaks memory.
|
||||||
|
|
||||||
## Getting started
|
## 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).
|
[here](https://ziglang.org/download).
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
@ -236,7 +238,7 @@ $ # open http://localhost:3000 in your browser
|
||||||
|
|
||||||
## Using ⚡zap⚡ in your own projects
|
## 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).
|
[here](https://ziglang.org/download).
|
||||||
|
|
||||||
If you don't have an existing zig project, create one like this:
|
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
|
`nix develop` to get a development shell providing zig and all
|
||||||
dependencies to build and run the GO, python, and rust examples for the
|
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.
|
`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:
|
With an existing Zig project, adding Zap to it is easy:
|
||||||
|
|
||||||
|
@ -266,12 +268,15 @@ To add zap to `build.zig.zon`:
|
||||||
.version = "0.0.1",
|
.version = "0.0.1",
|
||||||
|
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
// zap v0.6.0
|
// zap v0.7.0
|
||||||
.zap = .{
|
.zap = .{
|
||||||
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.6.0.tar.gz",
|
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.7.0.tar.gz",
|
||||||
.hash = "1220a5a1e6b18fa384d8a98e5d5a25720ddadbcfed01da2e4ca55c7cfb3dc1caa62a",
|
.hash = "12203126ff24e8018655eb7444c91f0d527d1213af16fcf2a578281abc994d01cc46",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
.paths = .{
|
||||||
|
"",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
<!-- INSERT_DEP_END -->
|
<!-- INSERT_DEP_END -->
|
||||||
|
@ -285,8 +290,8 @@ Then, in your `build.zig`'s `build` function, add the following before
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.openssl = false, // set to true to enable TLS support
|
.openssl = false, // set to true to enable TLS support
|
||||||
});
|
});
|
||||||
exe.addModule("zap", zap.module("zap"));
|
|
||||||
exe.linkLibrary(zap.artifact("facil.io"));
|
exe.root_module.addImport("zap", zap.module("zap"));
|
||||||
```
|
```
|
||||||
|
|
||||||
From then on, you can use the Zap package in your project. Check out the
|
From then on, you can use the Zap package in your project. Check out the
|
||||||
|
@ -405,27 +410,3 @@ pub fn main() !void {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
100
build.zig
100
build.zig
|
@ -1,11 +1,11 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const build_facilio = @import("facil.io/build.zig").build_facilio;
|
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(.{});
|
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.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
|
// Standard release options allow the person running `zig build` to select
|
||||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
// 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: {
|
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
|
// Alternatively, use an os env var to determine whether to build openssl support
|
||||||
if (std.os.getenv("ZAP_USE_OPENSSL")) |val| {
|
if (std.process.getEnvVarOwned(b.allocator, "ZAP_USE_OPENSSL")) |val| {
|
||||||
|
defer b.allocator.free(val);
|
||||||
if (std.mem.eql(u8, val, "true")) break :blk true;
|
if (std.mem.eql(u8, val, "true")) break :blk true;
|
||||||
}
|
} else |_| {}
|
||||||
break :blk false;
|
break :blk false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// create a module to be used internally.
|
|
||||||
var zap_module = b.createModule(.{
|
|
||||||
.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);
|
|
||||||
|
|
||||||
const facilio = try build_facilio("facil.io", b, target, optimize, use_openssl);
|
const facilio = try build_facilio("facil.io", b, target, optimize, use_openssl);
|
||||||
|
|
||||||
|
const zap_module = b.addModule("zap", .{
|
||||||
|
.root_source_file = b.path("src/zap.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
zap_module.linkLibrary(facilio);
|
||||||
|
|
||||||
const all_step = b.step("all", "build all examples");
|
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 = b.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 {
|
inline for ([_]struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
src: []const u8,
|
src: []const u8,
|
||||||
|
@ -56,6 +71,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
.{ .name = "middleware_with_endpoint", .src = "examples/middleware_with_endpoint/middleware_with_endpoint.zig" },
|
.{ .name = "middleware_with_endpoint", .src = "examples/middleware_with_endpoint/middleware_with_endpoint.zig" },
|
||||||
.{ .name = "senderror", .src = "examples/senderror/senderror.zig" },
|
.{ .name = "senderror", .src = "examples/senderror/senderror.zig" },
|
||||||
.{ .name = "bindataformpost", .src = "examples/bindataformpost/bindataformpost.zig" },
|
.{ .name = "bindataformpost", .src = "examples/bindataformpost/bindataformpost.zig" },
|
||||||
|
.{ .name = "accept", .src = "examples/accept/accept.zig" },
|
||||||
}) |excfg| {
|
}) |excfg| {
|
||||||
const ex_name = excfg.name;
|
const ex_name = excfg.name;
|
||||||
const ex_src = excfg.src;
|
const ex_src = excfg.src;
|
||||||
|
@ -80,13 +96,12 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
|
|
||||||
var example = b.addExecutable(.{
|
var example = b.addExecutable(.{
|
||||||
.name = ex_name,
|
.name = ex_name,
|
||||||
.root_source_file = .{ .path = ex_src },
|
.root_source_file = b.path(ex_src),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
example.linkLibrary(facilio);
|
example.root_module.addImport("zap", zap_module);
|
||||||
example.addModule("zap", zap_module);
|
|
||||||
|
|
||||||
// const example_run = example.run();
|
// const example_run = example.run();
|
||||||
const example_run = b.addRunArtifact(example);
|
const example_run = b.addRunArtifact(example);
|
||||||
|
@ -120,12 +135,11 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
//
|
//
|
||||||
const auth_tests = b.addTest(.{
|
const auth_tests = b.addTest(.{
|
||||||
.name = "auth_tests",
|
.name = "auth_tests",
|
||||||
.root_source_file = .{ .path = "src/tests/test_auth.zig" },
|
.root_source_file = b.path("src/tests/test_auth.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
auth_tests.linkLibrary(facilio);
|
auth_tests.root_module.addImport("zap", zap_module);
|
||||||
auth_tests.addModule("zap", zap_module);
|
|
||||||
|
|
||||||
const run_auth_tests = b.addRunArtifact(auth_tests);
|
const run_auth_tests = b.addRunArtifact(auth_tests);
|
||||||
const install_auth_tests = b.addInstallArtifact(auth_tests, .{});
|
const install_auth_tests = b.addInstallArtifact(auth_tests, .{});
|
||||||
|
@ -133,12 +147,11 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
// mustache tests
|
// mustache tests
|
||||||
const mustache_tests = b.addTest(.{
|
const mustache_tests = b.addTest(.{
|
||||||
.name = "mustache_tests",
|
.name = "mustache_tests",
|
||||||
.root_source_file = .{ .path = "src/tests/test_mustache.zig" },
|
.root_source_file = b.path("src/tests/test_mustache.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
mustache_tests.linkLibrary(facilio);
|
mustache_tests.root_module.addImport("zap", zap_module);
|
||||||
mustache_tests.addModule("zap", zap_module);
|
|
||||||
|
|
||||||
const run_mustache_tests = b.addRunArtifact(mustache_tests);
|
const run_mustache_tests = b.addRunArtifact(mustache_tests);
|
||||||
const install_mustache_tests = b.addInstallArtifact(mustache_tests, .{});
|
const install_mustache_tests = b.addInstallArtifact(mustache_tests, .{});
|
||||||
|
@ -146,13 +159,13 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
// http paramters (qyery, body) tests
|
// http paramters (qyery, body) tests
|
||||||
const httpparams_tests = b.addTest(.{
|
const httpparams_tests = b.addTest(.{
|
||||||
.name = "http_params_tests",
|
.name = "http_params_tests",
|
||||||
.root_source_file = .{ .path = "src/tests/test_http_params.zig" },
|
.root_source_file = b.path("src/tests/test_http_params.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
httpparams_tests.linkLibrary(facilio);
|
httpparams_tests.root_module.addImport("zap", zap_module);
|
||||||
httpparams_tests.addModule("zap", zap_module);
|
|
||||||
const run_httpparams_tests = b.addRunArtifact(httpparams_tests);
|
const run_httpparams_tests = b.addRunArtifact(httpparams_tests);
|
||||||
// TODO: for some reason, tests aren't run more than once unless
|
// TODO: for some reason, tests aren't run more than once unless
|
||||||
// dependencies have changed.
|
// dependencies have changed.
|
||||||
|
@ -163,13 +176,12 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
// http paramters (qyery, body) tests
|
// http paramters (qyery, body) tests
|
||||||
const sendfile_tests = b.addTest(.{
|
const sendfile_tests = b.addTest(.{
|
||||||
.name = "sendfile_tests",
|
.name = "sendfile_tests",
|
||||||
.root_source_file = .{ .path = "src/tests/test_sendfile.zig" },
|
.root_source_file = b.path("src/tests/test_sendfile.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
sendfile_tests.linkLibrary(facilio);
|
sendfile_tests.root_module.addImport("zap", zap_module);
|
||||||
sendfile_tests.addModule("zap", zap_module);
|
|
||||||
const run_sendfile_tests = b.addRunArtifact(sendfile_tests);
|
const run_sendfile_tests = b.addRunArtifact(sendfile_tests);
|
||||||
const install_sendfile_tests = b.addInstallArtifact(sendfile_tests, .{});
|
const install_sendfile_tests = b.addInstallArtifact(sendfile_tests, .{});
|
||||||
|
|
||||||
|
@ -202,9 +214,9 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
//
|
//
|
||||||
// pkghash
|
// pkghash
|
||||||
//
|
//
|
||||||
var pkghash_exe = b.addExecutable(.{
|
const pkghash_exe = b.addExecutable(.{
|
||||||
.name = "pkghash",
|
.name = "pkghash",
|
||||||
.root_source_file = .{ .path = "./tools/pkghash.zig" },
|
.root_source_file = b.path("./tools/pkghash.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
@ -213,12 +225,36 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
pkghash_step.dependOn(&pkghash_build_step.step);
|
pkghash_step.dependOn(&pkghash_build_step.step);
|
||||||
all_step.dependOn(&pkghash_build_step.step);
|
all_step.dependOn(&pkghash_build_step.step);
|
||||||
|
|
||||||
|
//
|
||||||
|
// docserver
|
||||||
|
//
|
||||||
|
const docserver_exe = b.addExecutable(.{
|
||||||
|
.name = "docserver",
|
||||||
|
.root_source_file = b.path("./tools/docserver.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
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.addPrefixedDirectoryArg("--docs=", docs_obj.getEmittedDocs());
|
||||||
|
|
||||||
|
docserver_run_step.dependOn(&docserver_run.step);
|
||||||
|
docserver_run_step.dependOn(docserver_step);
|
||||||
|
|
||||||
|
all_step.dependOn(&docserver_build_step.step);
|
||||||
|
|
||||||
//
|
//
|
||||||
// announceybot
|
// announceybot
|
||||||
//
|
//
|
||||||
var announceybot_exe = b.addExecutable(.{
|
const announceybot_exe = b.addExecutable(.{
|
||||||
.name = "announceybot",
|
.name = "announceybot",
|
||||||
.root_source_file = .{ .path = "./tools/announceybot.zig" },
|
.root_source_file = b.path("./tools/announceybot.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1 +1,10 @@
|
||||||
.{ .name = "zap", .version = "0.6.0" }
|
.{
|
||||||
|
.name = "zap",
|
||||||
|
.version = "0.7.1",
|
||||||
|
.paths = .{
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
"src",
|
||||||
|
"facil.io",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,10 @@ Here is a complete `build.zig.zon` example:
|
||||||
.zap = .{
|
.zap = .{
|
||||||
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
|
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
|
||||||
.hash = "{hash}",
|
.hash = "{hash}",
|
||||||
}
|
},
|
||||||
|
.paths = .{
|
||||||
|
"",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +38,8 @@ Then, in your `build.zig`'s `build` function, add the following before
|
||||||
const zap = b.dependency("zap", .{
|
const zap = b.dependency("zap", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.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"));
|
exe.linkLibrary(zap.artifact("facil.io"));
|
||||||
```
|
```
|
||||||
|
|
76
examples/accept/accept.zig
Normal file
76
examples/accept/accept.zig
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const zap = @import("zap");
|
||||||
|
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
|
.thread_safe = true,
|
||||||
|
}){};
|
||||||
|
|
||||||
|
fn on_request_verbose(r: zap.Request) void {
|
||||||
|
// use a local buffer for the parsed accept headers
|
||||||
|
var accept_buffer: [1024]u8 = undefined;
|
||||||
|
var fba = std.heap.FixedBufferAllocator.init(&accept_buffer);
|
||||||
|
const accept_allocator = fba.allocator();
|
||||||
|
|
||||||
|
const content_type: zap.ContentType = content_type: {
|
||||||
|
var accept_list = r.parseAcceptHeaders(accept_allocator) catch break :content_type .HTML;
|
||||||
|
defer accept_list.deinit();
|
||||||
|
|
||||||
|
for (accept_list.items) |accept| {
|
||||||
|
break :content_type accept.toContentType() orelse continue;
|
||||||
|
}
|
||||||
|
break :content_type .HTML;
|
||||||
|
};
|
||||||
|
|
||||||
|
r.setContentType(content_type) catch return;
|
||||||
|
switch (content_type) {
|
||||||
|
.TEXT => {
|
||||||
|
r.sendBody("Hello from ZAP!!!") catch return;
|
||||||
|
},
|
||||||
|
.HTML => {
|
||||||
|
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
|
||||||
|
},
|
||||||
|
.XML => {
|
||||||
|
r.sendBody(
|
||||||
|
\\<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
\\<message>
|
||||||
|
\\ <warning>
|
||||||
|
\\ Hello from ZAP!!!
|
||||||
|
\\ </warning>
|
||||||
|
\\</message>
|
||||||
|
) catch return;
|
||||||
|
},
|
||||||
|
.JSON => {
|
||||||
|
var buffer: [128]u8 = undefined;
|
||||||
|
const json = zap.stringifyBuf(&buffer, .{ .message = "Hello from ZAP!!!" }, .{}) orelse return;
|
||||||
|
r.sendJson(json) catch return;
|
||||||
|
},
|
||||||
|
.XHTML => {
|
||||||
|
r.sendBody(
|
||||||
|
\\<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
\\<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
|
||||||
|
\\ <body>
|
||||||
|
\\ <h1>Hello from ZAP!!!</h1>
|
||||||
|
\\ </body>
|
||||||
|
\\</html>
|
||||||
|
) catch return;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var listener = zap.HttpListener.init(.{
|
||||||
|
.port = 3000,
|
||||||
|
.on_request = on_request_verbose,
|
||||||
|
.log = true,
|
||||||
|
.max_clients = 100000,
|
||||||
|
});
|
||||||
|
try listener.listen();
|
||||||
|
|
||||||
|
std.debug.print("Listening on 0.0.0.0:3000\n", .{});
|
||||||
|
|
||||||
|
// start worker threads
|
||||||
|
zap.start(.{
|
||||||
|
.threads = 2,
|
||||||
|
.workers = 2,
|
||||||
|
});
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ const Handler = struct {
|
||||||
var alloc: std.mem.Allocator = undefined;
|
var alloc: std.mem.Allocator = undefined;
|
||||||
|
|
||||||
pub fn on_request(r: zap.Request) void {
|
pub fn on_request(r: zap.Request) void {
|
||||||
// check for FORM parameters
|
// parse for FORM (body) parameters first
|
||||||
r.parseBody() catch |err| {
|
r.parseBody() catch |err| {
|
||||||
std.log.err("Parse Body error: {any}. Expected if body is empty", .{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| {
|
if (r.body) |body| {
|
||||||
std.log.info("Body length is {any}\n", .{body.len});
|
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();
|
r.parseQuery();
|
||||||
|
|
||||||
var param_count = r.getParamCount();
|
const param_count = r.getParamCount();
|
||||||
std.log.info("param_count: {}", .{param_count});
|
std.log.info("param_count: {}", .{param_count});
|
||||||
|
|
||||||
// iterate over all params
|
// iterate over all params
|
||||||
|
@ -56,8 +57,11 @@ const Handler = struct {
|
||||||
else => {
|
else => {
|
||||||
// might be a string param, we don't care
|
// might be a string param, we don't care
|
||||||
// let's just get it as string
|
// 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| {
|
if (r.getParamStr(Handler.alloc, kv.key.str, false)) |maybe_str| {
|
||||||
const value: []const u8 = if (maybe_str) |s| s.str else "(no value)";
|
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 });
|
std.log.debug(" {s} = {s}", .{ kv.key.str, value });
|
||||||
} else |err| {
|
} else |err| {
|
||||||
std.log.err("Error: {any}\n", .{err});
|
std.log.err("Error: {any}\n", .{err});
|
||||||
|
@ -70,7 +74,6 @@ const Handler = struct {
|
||||||
// check if we received a terminate=true parameter
|
// check if we received a terminate=true parameter
|
||||||
if (r.getParamStr(Handler.alloc, "terminate", false)) |maybe_str| {
|
if (r.getParamStr(Handler.alloc, "terminate", false)) |maybe_str| {
|
||||||
if (maybe_str) |*s| {
|
if (maybe_str) |*s| {
|
||||||
defer s.deinit();
|
|
||||||
std.log.info("?terminate={s}\n", .{s.str});
|
std.log.info("?terminate={s}\n", .{s.str});
|
||||||
if (std.mem.eql(u8, s.str, "true")) {
|
if (std.mem.eql(u8, s.str, "true")) {
|
||||||
zap.stop();
|
zap.stop();
|
||||||
|
@ -87,7 +90,7 @@ pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
.thread_safe = true,
|
||||||
}){};
|
}){};
|
||||||
var allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
Handler.alloc = allocator;
|
Handler.alloc = allocator;
|
||||||
|
|
||||||
|
|
|
@ -5,17 +5,19 @@ const zap = @import("zap");
|
||||||
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);
|
||||||
|
|
||||||
var h = std.http.Headers{ .allocator = a };
|
|
||||||
defer h.deinit();
|
|
||||||
|
|
||||||
var http_client: std.http.Client = .{ .allocator = a };
|
var http_client: std.http.Client = .{ .allocator = a };
|
||||||
defer http_client.deinit();
|
defer http_client.deinit();
|
||||||
|
|
||||||
var 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();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.headers.append("cookie", "ZIG_ZAP=awesome");
|
try req.send();
|
||||||
try req.start();
|
|
||||||
try req.wait();
|
try req.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
.thread_safe = true,
|
||||||
}){};
|
}){};
|
||||||
var allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
const Handler = struct {
|
const Handler = struct {
|
||||||
var alloc: std.mem.Allocator = undefined;
|
var alloc: std.mem.Allocator = undefined;
|
||||||
|
@ -37,17 +39,19 @@ pub fn main() !void {
|
||||||
std.debug.print("\n=====================================================\n", .{});
|
std.debug.print("\n=====================================================\n", .{});
|
||||||
defer 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});
|
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;
|
var strCookies = r.cookiesToOwnedStrList(alloc, false) catch unreachable;
|
||||||
defer strCookies.deinit();
|
defer strCookies.deinit();
|
||||||
std.debug.print("\n", .{});
|
std.debug.print("\n", .{});
|
||||||
for (strCookies.items) |kv| {
|
for (strCookies.items) |kv| {
|
||||||
std.log.info("CookieStr `{s}` is `{s}`", .{ kv.key.str, kv.value.str });
|
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", .{});
|
std.debug.print("\n", .{});
|
||||||
|
@ -63,7 +67,7 @@ pub fn main() !void {
|
||||||
std.debug.print("\n", .{});
|
std.debug.print("\n", .{});
|
||||||
if (r.getCookieStr(alloc, "ZIG_ZAP", false)) |maybe_str| {
|
if (r.getCookieStr(alloc, "ZIG_ZAP", false)) |maybe_str| {
|
||||||
if (maybe_str) |*s| {
|
if (maybe_str) |*s| {
|
||||||
defer s.deinit();
|
defer s.deinit(); // unnecessary because always_alloc=false
|
||||||
|
|
||||||
std.log.info("Cookie ZIG_ZAP = {s}", .{s.str});
|
std.log.info("Cookie ZIG_ZAP = {s}", .{s.str});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,7 +3,7 @@ const zap = @import("zap");
|
||||||
const UserWeb = @import("userweb.zig");
|
const UserWeb = @import("userweb.zig");
|
||||||
const StopEndpoint = @import("stopendpoint.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 {
|
fn on_request(r: zap.Request) void {
|
||||||
if (r.path) |the_path| {
|
if (r.path) |the_path| {
|
||||||
std.debug.print("REQUESTED PATH: {s}\n", .{the_path});
|
std.debug.print("REQUESTED PATH: {s}\n", .{the_path});
|
||||||
|
@ -16,7 +16,7 @@ pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
.thread_safe = true,
|
||||||
}){};
|
}){};
|
||||||
var allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
// we scope everything that can allocate within this block for leak detection
|
// we scope everything that can allocate within this block for leak detection
|
||||||
{
|
{
|
||||||
|
@ -56,7 +56,7 @@ pub fn main() !void {
|
||||||
|
|
||||||
// and run
|
// and run
|
||||||
zap.start(.{
|
zap.start(.{
|
||||||
.threads = 2000,
|
.threads = 2,
|
||||||
// IMPORTANT! It is crucial to only have a single worker for this example to work!
|
// 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.
|
// Multiple workers would have multiple copies of the users hashmap.
|
||||||
//
|
//
|
||||||
|
|
|
@ -41,12 +41,12 @@ pub fn addByName(self: *Self, first: ?[]const u8, last: ?[]const u8) !usize {
|
||||||
user.lastnamelen = 0;
|
user.lastnamelen = 0;
|
||||||
|
|
||||||
if (first) |firstname| {
|
if (first) |firstname| {
|
||||||
std.mem.copy(u8, user.firstnamebuf[0..], firstname);
|
@memcpy(user.firstnamebuf[0..firstname.len], firstname);
|
||||||
user.firstnamelen = firstname.len;
|
user.firstnamelen = firstname.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last) |lastname| {
|
if (last) |lastname| {
|
||||||
std.mem.copy(u8, user.lastnamebuf[0..], lastname);
|
@memcpy(user.lastnamebuf[0..lastname.len], lastname);
|
||||||
user.lastnamelen = lastname.len;
|
user.lastnamelen = lastname.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,11 +101,11 @@ pub fn update(
|
||||||
pUser.firstnamelen = 0;
|
pUser.firstnamelen = 0;
|
||||||
pUser.lastnamelen = 0;
|
pUser.lastnamelen = 0;
|
||||||
if (first) |firstname| {
|
if (first) |firstname| {
|
||||||
std.mem.copy(u8, pUser.firstnamebuf[0..], firstname);
|
@memcpy(pUser.firstnamebuf[0..firstname.len], firstname);
|
||||||
pUser.firstnamelen = firstname.len;
|
pUser.firstnamelen = firstname.len;
|
||||||
}
|
}
|
||||||
if (last) |lastname| {
|
if (last) |lastname| {
|
||||||
std.mem.copy(u8, pUser.lastnamebuf[0..], lastname);
|
@memcpy(pUser.lastnamebuf[0..lastname.len], lastname);
|
||||||
pUser.lastnamelen = lastname.len;
|
pUser.lastnamelen = lastname.len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,8 @@ fn userIdFromPath(self: *Self, path: []const u8) ?usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getUser(e: *zap.Endpoint, r: zap.Request) void {
|
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| {
|
if (r.path) |path| {
|
||||||
// /users
|
// /users
|
||||||
if (path.len == e.settings.path.len) {
|
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 {
|
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| {
|
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| {
|
if (maybe_user) |u| {
|
||||||
defer u.deinit();
|
defer u.deinit();
|
||||||
if (self._users.addByName(u.value.first_name, u.value.last_name)) |id| {
|
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 {
|
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 (r.path) |path| {
|
||||||
if (self.userIdFromPath(path)) |id| {
|
if (self.userIdFromPath(path)) |id| {
|
||||||
if (self._users.get(id)) |_| {
|
if (self._users.get(id)) |_| {
|
||||||
if (r.body) |body| {
|
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| {
|
if (maybe_user) |u| {
|
||||||
defer u.deinit();
|
defer u.deinit();
|
||||||
var jsonbuf: [128]u8 = undefined;
|
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 {
|
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 (r.path) |path| {
|
||||||
if (self.userIdFromPath(path)) |id| {
|
if (self.userIdFromPath(path)) |id| {
|
||||||
var jsonbuf: [128]u8 = undefined;
|
var jsonbuf: [128]u8 = undefined;
|
||||||
|
|
|
@ -41,7 +41,7 @@ fn setupUserData(a: std.mem.Allocator) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var a = std.heap.page_allocator;
|
const a = std.heap.page_allocator;
|
||||||
try setupUserData(a);
|
try setupUserData(a);
|
||||||
var listener = zap.HttpListener.init(.{
|
var listener = zap.HttpListener.init(.{
|
||||||
.port = 3000,
|
.port = 3000,
|
||||||
|
@ -63,6 +63,6 @@ pub fn main() !void {
|
||||||
// start worker threads
|
// start worker threads
|
||||||
zap.start(.{
|
zap.start(.{
|
||||||
.threads = 2,
|
.threads = 2,
|
||||||
.workers = 2,
|
.workers = 1, // user map cannot be shared among multiple worker processes
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,16 @@ const zap = @import("zap");
|
||||||
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);
|
||||||
|
|
||||||
var h = std.http.Headers{ .allocator = a };
|
|
||||||
defer h.deinit();
|
|
||||||
|
|
||||||
var http_client: std.http.Client = .{ .allocator = a };
|
var http_client: std.http.Client = .{ .allocator = a };
|
||||||
defer http_client.deinit();
|
defer http_client.deinit();
|
||||||
|
|
||||||
var 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();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.send();
|
||||||
try req.wait();
|
try req.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
.thread_safe = true,
|
||||||
}){};
|
}){};
|
||||||
var allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
const Handler = struct {
|
const Handler = struct {
|
||||||
var alloc: std.mem.Allocator = undefined;
|
var alloc: std.mem.Allocator = undefined;
|
||||||
|
@ -44,7 +44,7 @@ pub fn main() !void {
|
||||||
// check for query parameters
|
// check for query parameters
|
||||||
r.parseQuery();
|
r.parseQuery();
|
||||||
|
|
||||||
var param_count = r.getParamCount();
|
const param_count = r.getParamCount();
|
||||||
std.log.info("param_count: {}", .{param_count});
|
std.log.info("param_count: {}", .{param_count});
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
|
|
|
@ -30,7 +30,7 @@ fn help_and_exit(filename: []const u8, err: anyerror) void {
|
||||||
,
|
,
|
||||||
.{ filename, err },
|
.{ filename, err },
|
||||||
);
|
);
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
const CERT_FILE = "mycert.pem";
|
const CERT_FILE = "mycert.pem";
|
||||||
|
|
|
@ -72,7 +72,7 @@ const UserMiddleWare = struct {
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||||
|
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
var self = @fieldParentPtr(Self, "handler", handler);
|
const self: *Self = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
// do our work: fill in the user field of the context
|
// do our work: fill in the user field of the context
|
||||||
|
@ -115,7 +115,7 @@ const SessionMiddleWare = struct {
|
||||||
// note that the first parameter is of type *Handler, not *Self !!!
|
// note that the first parameter is of type *Handler, not *Self !!!
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
var self = @fieldParentPtr(Self, "handler", handler);
|
const self: *Self = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
context.session = Session{
|
context.session = Session{
|
||||||
|
@ -151,7 +151,7 @@ const HtmlMiddleWare = struct {
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||||
|
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
var self = @fieldParentPtr(Self, "handler", handler);
|
const self: *Self = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
std.debug.print("\n\nHtmlMiddleware: handling request with context: {any}\n\n", .{context});
|
std.debug.print("\n\nHtmlMiddleware: handling request with context: {any}\n\n", .{context});
|
||||||
|
@ -190,7 +190,7 @@ pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
.thread_safe = true,
|
||||||
}){};
|
}){};
|
||||||
var allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
SharedAllocator.init(allocator);
|
SharedAllocator.init(allocator);
|
||||||
|
|
||||||
// we create our HTML middleware component that handles the request
|
// we create our HTML middleware component that handles the request
|
||||||
|
|
|
@ -60,7 +60,7 @@ const UserMiddleWare = struct {
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||||
|
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
var self = @fieldParentPtr(Self, "handler", handler);
|
const self: *Self = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
// do our work: fill in the user field of the context
|
// do our work: fill in the user field of the context
|
||||||
|
@ -105,7 +105,7 @@ const SessionMiddleWare = struct {
|
||||||
// note that the first parameter is of type *Handler, not *Self !!!
|
// note that the first parameter is of type *Handler, not *Self !!!
|
||||||
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
pub fn onRequest(handler: *Handler, r: zap.Request, context: *Context) bool {
|
||||||
// this is how we would get our self pointer
|
// this is how we would get our self pointer
|
||||||
var self = @fieldParentPtr(Self, "handler", handler);
|
const self: *Self = @fieldParentPtr("handler", handler);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
context.session = Session{
|
context.session = Session{
|
||||||
|
@ -155,7 +155,7 @@ const HtmlEndpoint = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(ep: *zap.Endpoint, r: zap.Request) void {
|
pub fn get(ep: *zap.Endpoint, r: zap.Request) void {
|
||||||
const self = @fieldParentPtr(Self, "ep", ep);
|
const self: *Self = @fieldParentPtr("ep", ep);
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
var buf: [1024]u8 = undefined;
|
var buf: [1024]u8 = undefined;
|
||||||
|
@ -200,7 +200,7 @@ pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
.thread_safe = true,
|
||||||
}){};
|
}){};
|
||||||
var allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
SharedAllocator.init(allocator);
|
SharedAllocator.init(allocator);
|
||||||
|
|
||||||
// create the endpoint
|
// create the endpoint
|
||||||
|
|
|
@ -7,7 +7,7 @@ fn MAKE_MEGA_ERROR() !void {
|
||||||
|
|
||||||
fn MY_REQUEST_HANDLER(r: zap.Request) void {
|
fn MY_REQUEST_HANDLER(r: zap.Request) void {
|
||||||
MAKE_MEGA_ERROR() catch |err| {
|
MAKE_MEGA_ERROR() catch |err| {
|
||||||
r.sendError(err, 505);
|
r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
.thread_safe = true,
|
||||||
}){};
|
}){};
|
||||||
var allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
var simpleRouter = zap.Router.init(allocator, .{
|
var simpleRouter = zap.Router.init(allocator, .{
|
||||||
.not_found = not_found,
|
.not_found = not_found,
|
||||||
|
|
|
@ -46,8 +46,8 @@ const ContextManager = struct {
|
||||||
self.lock.lock();
|
self.lock.lock();
|
||||||
defer self.lock.unlock();
|
defer self.lock.unlock();
|
||||||
|
|
||||||
var ctx = try self.allocator.create(Context);
|
const ctx = try self.allocator.create(Context);
|
||||||
var userName = try std.fmt.allocPrint(
|
const userName = try std.fmt.allocPrint(
|
||||||
self.allocator,
|
self.allocator,
|
||||||
"{s}{d}",
|
"{s}{d}",
|
||||||
.{ self.usernamePrefix, self.contexts.items.len },
|
.{ self.usernamePrefix, self.contexts.items.len },
|
||||||
|
@ -202,7 +202,7 @@ pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
.thread_safe = true,
|
||||||
}){};
|
}){};
|
||||||
var allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
GlobalContextManager = ContextManager.init(allocator, "chatroom", "user-");
|
GlobalContextManager = ContextManager.init(allocator, "chatroom", "user-");
|
||||||
defer GlobalContextManager.deinit();
|
defer GlobalContextManager.deinit();
|
||||||
|
|
|
@ -2,11 +2,11 @@ const std = @import("std");
|
||||||
|
|
||||||
pub fn build_facilio(
|
pub fn build_facilio(
|
||||||
comptime subdir: []const u8,
|
comptime subdir: []const u8,
|
||||||
b: *std.build.Builder,
|
b: *std.Build,
|
||||||
target: std.zig.CrossTarget,
|
target: std.Build.ResolvedTarget,
|
||||||
optimize: std.builtin.OptimizeMode,
|
optimize: std.builtin.OptimizeMode,
|
||||||
use_openssl: bool,
|
use_openssl: bool,
|
||||||
) !*std.build.CompileStep {
|
) !*std.Build.Step.Compile {
|
||||||
const lib = b.addStaticLibrary(.{
|
const lib = b.addStaticLibrary(.{
|
||||||
.name = "facil.io",
|
.name = "facil.io",
|
||||||
.target = target,
|
.target = target,
|
||||||
|
@ -15,7 +15,7 @@ pub fn build_facilio(
|
||||||
|
|
||||||
// Generate flags
|
// Generate flags
|
||||||
var flags = std.ArrayList([]const u8).init(std.heap.page_allocator);
|
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("-Wno-return-type-c-linkage");
|
||||||
try flags.append("-fno-sanitize=undefined");
|
try flags.append("-fno-sanitize=undefined");
|
||||||
|
|
||||||
|
@ -26,46 +26,52 @@ pub fn build_facilio(
|
||||||
//
|
//
|
||||||
|
|
||||||
try flags.append("-DFIO_HTTP_EXACT_LOGGING");
|
try flags.append("-DFIO_HTTP_EXACT_LOGGING");
|
||||||
if (target.getAbi() == .musl)
|
if (target.result.abi == .musl)
|
||||||
try flags.append("-D_LARGEFILE64_SOURCE");
|
try flags.append("-D_LARGEFILE64_SOURCE");
|
||||||
if (use_openssl)
|
if (use_openssl)
|
||||||
try flags.append("-DHAVE_OPENSSL -DFIO_TLS_FOUND");
|
try flags.append("-DHAVE_OPENSSL -DFIO_TLS_FOUND");
|
||||||
|
|
||||||
// Include paths
|
// Include paths
|
||||||
lib.addIncludePath(.{ .path = subdir ++ "/." });
|
lib.addIncludePath(b.path(subdir ++ "/."));
|
||||||
lib.addIncludePath(.{ .path = subdir ++ "/lib/facil" });
|
lib.addIncludePath(b.path(subdir ++ "/lib/facil"));
|
||||||
lib.addIncludePath(.{ .path = subdir ++ "/lib/facil/fiobj" });
|
lib.addIncludePath(b.path(subdir ++ "/lib/facil/fiobj"));
|
||||||
lib.addIncludePath(.{ .path = subdir ++ "/lib/facil/cli" });
|
lib.addIncludePath(b.path(subdir ++ "/lib/facil/cli"));
|
||||||
lib.addIncludePath(.{ .path = subdir ++ "/lib/facil/http" });
|
lib.addIncludePath(b.path(subdir ++ "/lib/facil/http"));
|
||||||
lib.addIncludePath(.{ .path = subdir ++ "/lib/facil/http/parsers" });
|
lib.addIncludePath(b.path(subdir ++ "/lib/facil/http/parsers"));
|
||||||
if (use_openssl)
|
if (use_openssl)
|
||||||
lib.addIncludePath(.{ .path = subdir ++ "/lib/facil/tls" });
|
lib.addIncludePath(b.path(subdir ++ "/lib/facil/tls"));
|
||||||
|
|
||||||
// C source files
|
// C source files
|
||||||
lib.addCSourceFiles(&.{
|
lib.addCSourceFiles(.{
|
||||||
subdir ++ "/lib/facil/fio.c",
|
.files = &.{
|
||||||
subdir ++ "/lib/facil/fio_zig.c",
|
subdir ++ "/lib/facil/fio.c",
|
||||||
subdir ++ "/lib/facil/http/http.c",
|
subdir ++ "/lib/facil/fio_zig.c",
|
||||||
subdir ++ "/lib/facil/http/http1.c",
|
subdir ++ "/lib/facil/http/http.c",
|
||||||
subdir ++ "/lib/facil/http/websockets.c",
|
subdir ++ "/lib/facil/http/http1.c",
|
||||||
subdir ++ "/lib/facil/http/http_internal.c",
|
subdir ++ "/lib/facil/http/websockets.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fiobj_numbers.c",
|
subdir ++ "/lib/facil/http/http_internal.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fio_siphash.c",
|
subdir ++ "/lib/facil/fiobj/fiobj_numbers.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fiobj_str.c",
|
subdir ++ "/lib/facil/fiobj/fio_siphash.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fiobj_ary.c",
|
subdir ++ "/lib/facil/fiobj/fiobj_str.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fiobj_data.c",
|
subdir ++ "/lib/facil/fiobj/fiobj_ary.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fiobj_hash.c",
|
subdir ++ "/lib/facil/fiobj/fiobj_data.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fiobj_json.c",
|
subdir ++ "/lib/facil/fiobj/fiobj_hash.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fiobject.c",
|
subdir ++ "/lib/facil/fiobj/fiobj_json.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fiobj_mustache.c",
|
subdir ++ "/lib/facil/fiobj/fiobject.c",
|
||||||
subdir ++ "/lib/facil/cli/fio_cli.c",
|
subdir ++ "/lib/facil/fiobj/fiobj_mustache.c",
|
||||||
}, flags.items);
|
subdir ++ "/lib/facil/cli/fio_cli.c",
|
||||||
|
},
|
||||||
|
.flags = flags.items,
|
||||||
|
});
|
||||||
|
|
||||||
if (use_openssl) {
|
if (use_openssl) {
|
||||||
lib.addCSourceFiles(&.{
|
lib.addCSourceFiles(.{
|
||||||
subdir ++ "/lib/facil/tls/fio_tls_openssl.c",
|
.files = &.{
|
||||||
subdir ++ "/lib/facil/tls/fio_tls_missing.c",
|
subdir ++ "/lib/facil/tls/fio_tls_openssl.c",
|
||||||
}, flags.items);
|
subdir ++ "/lib/facil/tls/fio_tls_missing.c",
|
||||||
|
},
|
||||||
|
.flags = flags.items,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// link against libc
|
// link against libc
|
||||||
|
|
|
@ -2,4 +2,3 @@
|
||||||
.name = "facil.io",
|
.name = "facil.io",
|
||||||
.version = "0.0.12",
|
.version = "0.0.12",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
44
flake.lock
generated
44
flake.lock
generated
|
@ -3,11 +3,11 @@
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1673956053,
|
"lastModified": 1696426674,
|
||||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -37,11 +37,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1689068808,
|
"lastModified": 1701680307,
|
||||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -55,11 +55,11 @@
|
||||||
"systems": "systems_2"
|
"systems": "systems_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1685518550,
|
"lastModified": 1701680307,
|
||||||
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -92,11 +92,11 @@
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "contrib",
|
"dir": "contrib",
|
||||||
"lastModified": 1692702614,
|
"lastModified": 1704461694,
|
||||||
"narHash": "sha256-FeY8hAB77tnUTDbK6WYA+DG3Nx5xQrbOC17Cfl3pTm4=",
|
"narHash": "sha256-dQc9Bkh5uf0R4po3NWnCGx+3eqOZR7iSR4jmRvNNm+E=",
|
||||||
"owner": "neovim",
|
"owner": "neovim",
|
||||||
"repo": "neovim",
|
"repo": "neovim",
|
||||||
"rev": "014b87646fc3273a09d6b20ebb648a8eb24a0a98",
|
"rev": "c509f4907bf7405c9c2ae3f7eff76c5d552944cc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -108,11 +108,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1702882221,
|
"lastModified": 1704290814,
|
||||||
"narHash": "sha256-L/uOrBqkGsa45EvQk4DLq/aR6JeomW+7Mwe0mC/dVUM=",
|
"narHash": "sha256-LWvKHp7kGxk/GEtlrGYV68qIvPHkU9iToomNFGagixU=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "25fef6e30d8ad48f47a8411ccfe986d8baed8a15",
|
"rev": "70bdadeb94ffc8806c0570eb5c2695ad29f0e421",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -124,16 +124,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1689088367,
|
"lastModified": 1702350026,
|
||||||
"narHash": "sha256-Y2tl2TlKCWEHrOeM9ivjCLlRAKH3qoPUE/emhZECU14=",
|
"narHash": "sha256-A+GNZFZdfl4JdDphYKBJ5Ef1HOiFsP18vQe9mqjmUis=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "5c9ddb86679c400d6b7360797b8a22167c2053f8",
|
"rev": "9463103069725474698139ab10f17a9d125da859",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "release-23.05",
|
"ref": "nixos-23.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -184,11 +184,11 @@
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1692663634,
|
"lastModified": 1704888534,
|
||||||
"narHash": "sha256-wioqr80UOA0tNXaJy4D0i9fFaLG2RoQi5e9Dpd4WojE=",
|
"narHash": "sha256-douEXUiWCVL9NvWKYBc8ydq51qLLUwlBo6lJJoktkGw=",
|
||||||
"owner": "mitchellh",
|
"owner": "mitchellh",
|
||||||
"repo": "zig-overlay",
|
"repo": "zig-overlay",
|
||||||
"rev": "d666e5137fe0c43353c555fb47748813084decab",
|
"rev": "c69295c92a98947295755a9ac2d49a8d447cc04d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
27
flake.nix
27
flake.nix
|
@ -44,7 +44,7 @@
|
||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell {
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
# neovim-nightly-pkgs.neovim
|
# neovim-nightly-pkgs.neovim
|
||||||
zigpkgs."0.11.0"
|
zigpkgs."0.12.0"
|
||||||
bat
|
bat
|
||||||
wrk
|
wrk
|
||||||
python310
|
python310
|
||||||
|
@ -89,7 +89,8 @@
|
||||||
|
|
||||||
devShells.build = pkgs.mkShell {
|
devShells.build = pkgs.mkShell {
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
zigpkgs."0.11.0"
|
zigpkgs."0.12.0"
|
||||||
|
pkgs.openssl
|
||||||
];
|
];
|
||||||
|
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
|
@ -103,6 +104,28 @@
|
||||||
# once we set SHELL to point to the interactive bash, neovim will
|
# once we set SHELL to point to the interactive bash, neovim will
|
||||||
# launch the correct $SHELL in its :terminal
|
# launch the correct $SHELL in its :terminal
|
||||||
export SHELL=${pkgs.bashInteractive}/bin/bash
|
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
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ pub fn Authenticating(comptime Authenticator: type) type {
|
||||||
/// GET: here, the auth_endpoint will be passed in as endpoint.
|
/// GET: here, the auth_endpoint will be passed in as endpoint.
|
||||||
/// Authenticates GET requests using the Authenticator.
|
/// Authenticates GET requests using the Authenticator.
|
||||||
pub fn get(e: *Endpoint, r: zap.Request) void {
|
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)) {
|
switch (authEp.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => {
|
.AuthFailed => {
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
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.
|
/// POST: here, the auth_endpoint will be passed in as endpoint.
|
||||||
/// Authenticates POST requests using the Authenticator.
|
/// Authenticates POST requests using the Authenticator.
|
||||||
pub fn post(e: *Endpoint, r: zap.Request) void {
|
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)) {
|
switch (authEp.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => {
|
.AuthFailed => {
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
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.
|
/// PUT: here, the auth_endpoint will be passed in as endpoint.
|
||||||
/// Authenticates PUT requests using the Authenticator.
|
/// Authenticates PUT requests using the Authenticator.
|
||||||
pub fn put(e: *Endpoint, r: zap.Request) void {
|
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)) {
|
switch (authEp.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => {
|
.AuthFailed => {
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
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.
|
/// DELETE: here, the auth_endpoint will be passed in as endpoint.
|
||||||
/// Authenticates DELETE requests using the Authenticator.
|
/// Authenticates DELETE requests using the Authenticator.
|
||||||
pub fn delete(e: *Endpoint, r: zap.Request) void {
|
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)) {
|
switch (authEp.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => {
|
.AuthFailed => {
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
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.
|
/// PATCH: here, the auth_endpoint will be passed in as endpoint.
|
||||||
/// Authenticates PATCH requests using the Authenticator.
|
/// Authenticates PATCH requests using the Authenticator.
|
||||||
pub fn patch(e: *Endpoint, r: zap.Request) void {
|
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)) {
|
switch (authEp.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => {
|
.AuthFailed => {
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
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.
|
/// OPTIONS: here, the auth_endpoint will be passed in as endpoint.
|
||||||
/// Authenticates OPTIONS requests using the Authenticator.
|
/// Authenticates OPTIONS requests using the Authenticator.
|
||||||
pub fn options(e: *Endpoint, r: zap.Request) void {
|
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)) {
|
switch (authEp.authenticator.authenticateRequest(&r)) {
|
||||||
.AuthFailed => {
|
.AuthFailed => {
|
||||||
if (e.settings.unauthorized) |unauthorized| {
|
if (e.settings.unauthorized) |unauthorized| {
|
||||||
|
|
28
src/fio.zig
28
src/fio.zig
|
@ -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 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 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 {
|
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;
|
const o = arg_o;
|
||||||
var start_at = arg_start_at;
|
const start_at = arg_start_at;
|
||||||
var task = arg_task;
|
const task = arg_task;
|
||||||
var arg = arg_arg;
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -288,8 +288,8 @@ pub const fiobj_object_header_s = extern struct {
|
||||||
ref: u32,
|
ref: u32,
|
||||||
};
|
};
|
||||||
pub fn fiobj_type_is(arg_o: FIOBJ, arg_type: fiobj_type_enum) callconv(.C) usize {
|
pub fn fiobj_type_is(arg_o: FIOBJ, arg_type: fiobj_type_enum) callconv(.C) usize {
|
||||||
var o = arg_o;
|
const o = arg_o;
|
||||||
var @"type" = arg_type;
|
const @"type" = arg_type;
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (@as(c_int, @bitCast(@as(c_uint, @"type")))) {
|
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))))),
|
@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"))))))));
|
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 {
|
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 != 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, 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))));
|
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_HASH: fiobj_object_vtable_s;
|
||||||
pub extern const FIOBJECT_VTABLE_DATA: 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 {
|
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) {
|
while (true) {
|
||||||
switch (@as(c_int, @bitCast(@as(c_uint, fiobj_type(o))))) {
|
switch (@as(c_int, @bitCast(@as(c_uint, fiobj_type(o))))) {
|
||||||
@as(c_int, 1) => return &FIOBJECT_VTABLE_NUMBER,
|
@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 extern fn fio_ltocstr(c_long) fio_str_info_s;
|
||||||
pub fn fiobj_obj2cstr(o: FIOBJ) callconv(.C) fio_str_info_s {
|
pub fn fiobj_obj2cstr(o: FIOBJ) callconv(.C) fio_str_info_s {
|
||||||
if (!(o != 0)) {
|
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)))),
|
.capa = @as(usize, @bitCast(@as(c_long, @as(c_int, 0)))),
|
||||||
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 4)))),
|
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 4)))),
|
||||||
.data = @as([*c]u8, @ptrFromInt(@intFromPtr("null"))),
|
.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)))))))) {
|
switch (@as(c_int, @bitCast(@as(c_uint, @as(u8, @bitCast(@as(u8, @truncate(o)))))))) {
|
||||||
@as(c_int, 6) => {
|
@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)))),
|
.capa = @as(usize, @bitCast(@as(c_long, @as(c_int, 0)))),
|
||||||
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 4)))),
|
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 4)))),
|
||||||
.data = @as([*c]u8, @ptrFromInt(@intFromPtr("null"))),
|
.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) => {
|
@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)))),
|
.capa = @as(usize, @bitCast(@as(c_long, @as(c_int, 0)))),
|
||||||
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 5)))),
|
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 5)))),
|
||||||
.data = @as([*c]u8, @ptrFromInt(@intFromPtr("false"))),
|
.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) => {
|
@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)))),
|
.capa = @as(usize, @bitCast(@as(c_long, @as(c_int, 0)))),
|
||||||
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 4)))),
|
.len = @as(usize, @bitCast(@as(c_long, @as(c_int, 4)))),
|
||||||
.data = @as([*c]u8, @ptrFromInt(@intFromPtr("true"))),
|
.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_date2rfc2109(target: [*c]u8, tmbuf: [*c]struct_tm) usize;
|
||||||
pub extern fn http_date2rfc2822(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 {
|
pub fn http_date2str(arg_target: [*c]u8, arg_tmbuf: [*c]struct_tm) callconv(.C) usize {
|
||||||
var target = arg_target;
|
const target = arg_target;
|
||||||
var tmbuf = arg_tmbuf;
|
const tmbuf = arg_tmbuf;
|
||||||
return http_date2rfc7231(target, tmbuf);
|
return http_date2rfc7231(target, tmbuf);
|
||||||
}
|
}
|
||||||
pub extern fn http_time2str(target: [*c]u8, t: time_t) usize;
|
pub extern fn http_time2str(target: [*c]u8, t: time_t) usize;
|
||||||
|
|
52
src/http.zig
52
src/http.zig
|
@ -1,29 +1,39 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
/// HTTP Status codes according to `rfc7231`
|
/// HTTP Status codes according to `rfc9110`
|
||||||
/// https://tools.ietf.org/html/rfc7231#section-6
|
/// https://datatracker.ietf.org/doc/html/rfc9110#name-status-codes
|
||||||
/// (taken from https://github.com/Luukdegram/apple_pie/blob/master/src/response.zig)
|
/// (modified from https://github.com/Luukdegram/apple_pie/blob/master/src/response.zig)
|
||||||
pub const StatusCode = enum(u16) {
|
pub const StatusCode = enum(u16) {
|
||||||
// Informational 1xx
|
// Information responses
|
||||||
@"continue" = 100,
|
@"continue" = 100,
|
||||||
// Successful 2xx
|
|
||||||
switching_protocols = 101,
|
switching_protocols = 101,
|
||||||
|
processing = 102, // (WebDAV)
|
||||||
|
early_hints = 103,
|
||||||
|
|
||||||
|
// Successful responses
|
||||||
ok = 200,
|
ok = 200,
|
||||||
created = 201,
|
created = 201,
|
||||||
accepted = 202,
|
accepted = 202,
|
||||||
non_authoritative_information = 203,
|
non_authoritative_information = 203,
|
||||||
no_content = 204,
|
no_content = 204,
|
||||||
reset_content = 205,
|
reset_content = 205,
|
||||||
// redirections 3xx
|
|
||||||
partial_content = 206,
|
partial_content = 206,
|
||||||
|
multi_status = 207, // (WebDAV)
|
||||||
|
already_reported = 208, // (WebDAV)
|
||||||
|
im_used = 226, // (HTTP Delta encoding)
|
||||||
|
|
||||||
|
// Redirection messages
|
||||||
multiple_choices = 300,
|
multiple_choices = 300,
|
||||||
moved_permanently = 301,
|
moved_permanently = 301,
|
||||||
found = 302,
|
found = 302,
|
||||||
see_other = 303,
|
see_other = 303,
|
||||||
not_modified = 304,
|
not_modified = 304,
|
||||||
use_proxy = 305,
|
use_proxy = 305,
|
||||||
|
unused = 306,
|
||||||
temporary_redirect = 307,
|
temporary_redirect = 307,
|
||||||
// client errors 4xx
|
permanent_redirect = 308,
|
||||||
|
|
||||||
|
// Client error responses
|
||||||
bad_request = 400,
|
bad_request = 400,
|
||||||
unauthorized = 401,
|
unauthorized = 401,
|
||||||
payment_required = 402,
|
payment_required = 402,
|
||||||
|
@ -37,23 +47,35 @@ pub const StatusCode = enum(u16) {
|
||||||
gone = 410,
|
gone = 410,
|
||||||
length_required = 411,
|
length_required = 411,
|
||||||
precondition_failed = 412,
|
precondition_failed = 412,
|
||||||
request_entity_too_large = 413,
|
payload_too_large = 413,
|
||||||
request_uri_too_long = 414,
|
uri_too_long = 414,
|
||||||
unsupported_mediatype = 415,
|
unsupported_media_type = 415,
|
||||||
requested_range_not_satisfiable = 416,
|
range_not_satisfiable = 416,
|
||||||
expectation_failed = 417,
|
expectation_failed = 417,
|
||||||
/// teapot is an extension status code and not required for clients to support
|
im_a_teapot = 418,
|
||||||
teapot = 418,
|
misdirected_request = 421,
|
||||||
|
unprocessable_content = 422, // (WebDAV)
|
||||||
|
locked = 423, // (WebDAV)
|
||||||
|
failed_dependency = 424, // (WebDAV)
|
||||||
|
too_early = 425,
|
||||||
upgrade_required = 426,
|
upgrade_required = 426,
|
||||||
/// extra status code according to `https://tools.ietf.org/html/rfc6585#section-5`
|
precondition_required = 428,
|
||||||
|
too_many_requests = 429,
|
||||||
request_header_fields_too_large = 431,
|
request_header_fields_too_large = 431,
|
||||||
// server errors 5xx
|
unavailable_for_legal_reasons = 451,
|
||||||
|
|
||||||
|
// Server error responses
|
||||||
internal_server_error = 500,
|
internal_server_error = 500,
|
||||||
not_implemented = 501,
|
not_implemented = 501,
|
||||||
bad_gateway = 502,
|
bad_gateway = 502,
|
||||||
service_unavailable = 503,
|
service_unavailable = 503,
|
||||||
gateway_timeout = 504,
|
gateway_timeout = 504,
|
||||||
http_version_not_supported = 505,
|
http_version_not_supported = 505,
|
||||||
|
variant_also_negotiates = 506,
|
||||||
|
insufficient_storage = 507, // (WebDAV)
|
||||||
|
loop_detected = 508, // (WebDAV)
|
||||||
|
not_extended = 510,
|
||||||
|
network_authentication_required = 511,
|
||||||
_,
|
_,
|
||||||
|
|
||||||
/// Returns the string value of a `StatusCode`
|
/// Returns the string value of a `StatusCode`
|
||||||
|
|
|
@ -122,7 +122,7 @@ pub fn Basic(comptime Lookup: type, comptime kind: BasicAuthStrategy) type {
|
||||||
);
|
);
|
||||||
return .AuthFailed;
|
return .AuthFailed;
|
||||||
}
|
}
|
||||||
var decoded = buffer[0..decoded_size];
|
const decoded = buffer[0..decoded_size];
|
||||||
decoder.decode(decoded, encoded) catch |err| {
|
decoder.decode(decoded, encoded) catch |err| {
|
||||||
zap.debug(
|
zap.debug(
|
||||||
"ERROR: UserPassAuth: unable to decode `{s}`: {any}\n",
|
"ERROR: UserPassAuth: unable to decode `{s}`: {any}\n",
|
||||||
|
@ -400,7 +400,7 @@ pub fn UserPassSession(comptime Lookup: type, comptime lockedPwLookups: bool) ty
|
||||||
lookup: *Lookup,
|
lookup: *Lookup,
|
||||||
args: UserPassSessionArgs,
|
args: UserPassSessionArgs,
|
||||||
) !Self {
|
) !Self {
|
||||||
var ret: Self = .{
|
const ret: Self = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.settings = .{
|
.settings = .{
|
||||||
.usernameParam = try allocator.dupe(u8, args.usernameParam),
|
.usernameParam = try allocator.dupe(u8, args.usernameParam),
|
||||||
|
|
|
@ -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
|
/// If `breakOnFinish` is `true`, the handler will stop handing requests down the chain if
|
||||||
/// the endpoint processed the request.
|
/// the endpoint processed the request.
|
||||||
pub fn onRequest(handler: *HandlerType, r: zap.Request, context: *ContextType) bool {
|
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);
|
r.setUserContext(context);
|
||||||
self.endpoint.onRequest(r);
|
self.endpoint.onRequest(r);
|
||||||
|
|
||||||
|
|
163
src/request.zig
163
src/request.zig
|
@ -6,6 +6,8 @@ const fio = @import("fio.zig");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
const zap = @import("zap.zig");
|
const zap = @import("zap.zig");
|
||||||
|
|
||||||
|
const ContentType = zap.ContentType;
|
||||||
|
|
||||||
pub const HttpError = error{
|
pub const HttpError = error{
|
||||||
HttpSendBody,
|
HttpSendBody,
|
||||||
HttpSetContentType,
|
HttpSetContentType,
|
||||||
|
@ -16,15 +18,6 @@ pub const HttpError = error{
|
||||||
SendFile,
|
SendFile,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Http Content Type enum.
|
|
||||||
/// Needs some love.
|
|
||||||
pub const ContentType = enum {
|
|
||||||
TEXT,
|
|
||||||
HTML,
|
|
||||||
JSON,
|
|
||||||
// TODO: more content types
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Key value pair of strings from HTTP parameters
|
/// Key value pair of strings from HTTP parameters
|
||||||
pub const HttpParamStrKV = struct {
|
pub const HttpParamStrKV = struct {
|
||||||
key: util.FreeOrNot,
|
key: util.FreeOrNot,
|
||||||
|
@ -111,7 +104,7 @@ pub const HttpParamBinaryFile = struct {
|
||||||
filename: ?[]const u8 = null,
|
filename: ?[]const u8 = null,
|
||||||
|
|
||||||
/// format function for printing file upload data
|
/// format function for printing file upload data
|
||||||
pub fn format(value: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) std.os.WriteError!void {
|
pub fn format(value: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
const d = value.data orelse "\\0";
|
const d = value.data orelse "\\0";
|
||||||
const m = value.mimetype orelse "null";
|
const m = value.mimetype orelse "null";
|
||||||
const f = value.filename orelse "null";
|
const f = value.filename orelse "null";
|
||||||
|
@ -317,11 +310,15 @@ pub fn getUserContext(self: *const Self, comptime Context: type) ?*Context {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to send an error stack trace.
|
/// Tries to send an error stack trace.
|
||||||
pub fn sendError(self: *const Self, err: anyerror, errorcode_num: usize) void {
|
/// Use like this:
|
||||||
|
/// ```zig
|
||||||
|
/// const err = zap.HttpError; // this is to show that `err` is an Error
|
||||||
|
/// r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505);
|
||||||
|
/// ```
|
||||||
|
pub fn sendError(self: *const Self, err: anyerror, err_trace: ?std.builtin.StackTrace, errorcode_num: usize) void {
|
||||||
// TODO: query accept headers
|
// TODO: query accept headers
|
||||||
if (self._internal_sendError(err, errorcode_num)) {
|
if (self._internal_sendError(err, err_trace, errorcode_num)) {
|
||||||
return;
|
return;
|
||||||
} else |_| {
|
} else |_| {
|
||||||
self.sendBody(@errorName(err)) catch return;
|
self.sendBody(@errorName(err)) catch return;
|
||||||
|
@ -329,7 +326,7 @@ pub fn sendError(self: *const Self, err: anyerror, errorcode_num: usize) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used internally. Probably does not need to be public.
|
/// Used internally. Probably does not need to be public.
|
||||||
pub fn _internal_sendError(self: *const Self, err: anyerror, errorcode_num: usize) !void {
|
pub fn _internal_sendError(self: *const Self, err: anyerror, err_trace: ?std.builtin.StackTrace, errorcode_num: usize) !void {
|
||||||
// TODO: query accept headers
|
// TODO: query accept headers
|
||||||
// TODO: let's hope 20k is enough. Maybe just really allocate here
|
// TODO: let's hope 20k is enough. Maybe just really allocate here
|
||||||
self.h.*.status = errorcode_num;
|
self.h.*.status = errorcode_num;
|
||||||
|
@ -339,9 +336,12 @@ pub fn _internal_sendError(self: *const Self, err: anyerror, errorcode_num: usiz
|
||||||
var writer = string.writer();
|
var writer = string.writer();
|
||||||
try writer.print("ERROR: {any}\n\n", .{err});
|
try writer.print("ERROR: {any}\n\n", .{err});
|
||||||
|
|
||||||
const debugInfo = try std.debug.getSelfDebugInfo();
|
if (err_trace) |trace| {
|
||||||
const ttyConfig: std.io.tty.Config = .no_color;
|
const debugInfo = try std.debug.getSelfDebugInfo();
|
||||||
try std.debug.writeCurrentStackTrace(writer, debugInfo, ttyConfig, null);
|
const ttyConfig: std.io.tty.Config = .no_color;
|
||||||
|
try std.debug.writeStackTrace(trace, writer, fba.allocator(), debugInfo, ttyConfig);
|
||||||
|
}
|
||||||
|
|
||||||
try self.sendBody(string.items);
|
try self.sendBody(string.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,6 +439,63 @@ pub fn getHeader(self: *const Self, name: []const u8) ?[]const u8 {
|
||||||
return util.fio2str(fio.fiobj_hash_get(self.h.*.headers, hname));
|
return util.fio2str(fio.fiobj_hash_get(self.h.*.headers, hname));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const HttpHeaderCommon = enum(usize) {
|
||||||
|
/// Represents the HTTP Header "Accept".
|
||||||
|
accept,
|
||||||
|
/// Represents the HTTP Header "Cache-Control".
|
||||||
|
cache_control,
|
||||||
|
/// Represents the HTTP Header "Connection".
|
||||||
|
connection,
|
||||||
|
/// Represents the HTTP Header "Content-Encoding".
|
||||||
|
content_encoding,
|
||||||
|
/// Represents the HTTP Header "Content-Length".
|
||||||
|
content_length,
|
||||||
|
/// Represents the HTTP Header "Content-Range".
|
||||||
|
content_range,
|
||||||
|
/// Represents the HTTP Header "Content-Type".
|
||||||
|
content_type,
|
||||||
|
/// Represents the HTTP Header "Cookie".
|
||||||
|
cookie,
|
||||||
|
/// Represents the HTTP Header "Date".
|
||||||
|
date,
|
||||||
|
/// Represents the HTTP Header "Etag".
|
||||||
|
etag,
|
||||||
|
/// Represents the HTTP Header "Host".
|
||||||
|
host,
|
||||||
|
/// Represents the HTTP Header "Last-Modified".
|
||||||
|
last_modified,
|
||||||
|
/// Represents the HTTP Header "Origin".
|
||||||
|
origin,
|
||||||
|
/// Represents the HTTP Header "Set-Cookie".
|
||||||
|
set_cookie,
|
||||||
|
/// Represents the HTTP Header "Upgrade".
|
||||||
|
upgrade,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns the header value of a given common header key. Returned memory
|
||||||
|
/// should not be freed.
|
||||||
|
pub fn getHeaderCommon(self: *const Self, which: HttpHeaderCommon) ?[]const u8 {
|
||||||
|
const field = switch (which) {
|
||||||
|
.accept => fio.HTTP_HEADER_ACCEPT,
|
||||||
|
.cache_control => fio.HTTP_HEADER_CACHE_CONTROL,
|
||||||
|
.connection => fio.HTTP_HEADER_CONNECTION,
|
||||||
|
.content_encoding => fio.HTTP_HEADER_CONTENT_ENCODING,
|
||||||
|
.content_length => fio.HTTP_HEADER_CONTENT_LENGTH,
|
||||||
|
.content_range => fio.HTTP_HEADER_CONTENT_RANGE,
|
||||||
|
.content_type => fio.HTTP_HEADER_CONTENT_TYPE,
|
||||||
|
.cookie => fio.HTTP_HEADER_COOKIE,
|
||||||
|
.date => fio.HTTP_HEADER_DATE,
|
||||||
|
.etag => fio.HTTP_HEADER_ETAG,
|
||||||
|
.host => fio.HTTP_HEADER_HOST,
|
||||||
|
.last_modified => fio.HTTP_HEADER_LAST_MODIFIED,
|
||||||
|
.origin => fio.HTTP_HEADER_ORIGIN,
|
||||||
|
.set_cookie => fio.HTTP_HEADER_SET_COOKIE,
|
||||||
|
.upgrade => fio.HTTP_HEADER_UPGRADE,
|
||||||
|
};
|
||||||
|
const fiobj = zap.fio.fiobj_hash_get(self.h.*.headers, field);
|
||||||
|
return zap.fio2str(fiobj);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set header.
|
/// Set header.
|
||||||
pub fn setHeader(self: *const Self, name: []const u8, value: []const u8) HttpError!void {
|
pub fn setHeader(self: *const Self, name: []const u8, value: []const u8) HttpError!void {
|
||||||
const hname: fio.fio_str_info_s = .{
|
const hname: fio.fio_str_info_s = .{
|
||||||
|
@ -520,6 +577,78 @@ pub fn parseCookies(self: *const Self, url_encoded: bool) void {
|
||||||
fio.http_parse_cookies(self.h, if (url_encoded) 1 else 0);
|
fio.http_parse_cookies(self.h, if (url_encoded) 1 else 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const AcceptItem = struct {
|
||||||
|
raw: []const u8,
|
||||||
|
type: Fragment,
|
||||||
|
subtype: Fragment,
|
||||||
|
q: f64,
|
||||||
|
|
||||||
|
const Fragment = union(enum) {
|
||||||
|
glob,
|
||||||
|
value: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn lessThan(_: void, lhs: AcceptItem, rhs: AcceptItem) bool {
|
||||||
|
return lhs.q < rhs.q;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toContentType(item: AcceptItem) ?ContentType {
|
||||||
|
if (ContentType.string_map.get(item.raw)) |common| {
|
||||||
|
return common;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// List holding access headers parsed by parseAcceptHeaders()
|
||||||
|
const AcceptHeaderList = std.ArrayList(AcceptItem);
|
||||||
|
|
||||||
|
/// Parses `Accept:` http header into `list`, ordered from highest q factor to lowest
|
||||||
|
pub fn parseAcceptHeaders(self: *const Self, allocator: std.mem.Allocator) !AcceptHeaderList {
|
||||||
|
const accept_str = self.getHeaderCommon(.accept) orelse return error.NoAcceptHeader;
|
||||||
|
|
||||||
|
const comma_count = std.mem.count(u8, accept_str, ",");
|
||||||
|
|
||||||
|
var list = try AcceptHeaderList.initCapacity(allocator, comma_count + 1);
|
||||||
|
errdefer list.deinit();
|
||||||
|
|
||||||
|
var tok_iter = std.mem.tokenize(u8, accept_str, ", ");
|
||||||
|
while (tok_iter.next()) |tok| {
|
||||||
|
var split_iter = std.mem.split(u8, tok, ";");
|
||||||
|
const mimetype_str = split_iter.next().?;
|
||||||
|
const q_factor = q_factor: {
|
||||||
|
const q_factor_str = split_iter.next() orelse break :q_factor 1;
|
||||||
|
var eq_iter = std.mem.split(u8, q_factor_str, "=");
|
||||||
|
const q = eq_iter.next().?;
|
||||||
|
if (q[0] != 'q') break :q_factor 1;
|
||||||
|
const value = eq_iter.next() orelse break :q_factor 1;
|
||||||
|
const parsed = std.fmt.parseFloat(f64, value) catch break :q_factor 1;
|
||||||
|
break :q_factor parsed;
|
||||||
|
};
|
||||||
|
|
||||||
|
var type_split_iter = std.mem.split(u8, mimetype_str, "/");
|
||||||
|
|
||||||
|
const mimetype_type_str = type_split_iter.next() orelse continue;
|
||||||
|
const mimetype_subtype_str = type_split_iter.next() orelse continue;
|
||||||
|
|
||||||
|
const new_item: AcceptItem = .{
|
||||||
|
.raw = mimetype_str,
|
||||||
|
.type = if (std.mem.eql(u8, "*", mimetype_type_str)) .glob else .{ .value = mimetype_type_str },
|
||||||
|
.subtype = if (std.mem.eql(u8, "*", mimetype_subtype_str)) .glob else .{ .value = mimetype_subtype_str },
|
||||||
|
.q = q_factor,
|
||||||
|
};
|
||||||
|
for (list.items, 1..) |item, i| {
|
||||||
|
if (AcceptItem.lessThan({}, new_item, item)) {
|
||||||
|
list.insertAssumeCapacity(i, new_item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
list.appendAssumeCapacity(new_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/// Set a response cookie
|
/// Set a response cookie
|
||||||
pub fn setCookie(self: *const Self, args: CookieArgs) HttpError!void {
|
pub fn setCookie(self: *const Self, args: CookieArgs) HttpError!void {
|
||||||
const c: fio.http_cookie_args_s = .{
|
const c: fio.http_cookie_args_s = .{
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const zap = @import("zap");
|
const zap = @import("zap");
|
||||||
// const Authenticators = @import("http_auth.zig");
|
|
||||||
const Authenticators = zap.Auth;
|
const Authenticators = zap.Auth;
|
||||||
const Endpoint = zap.Endpoint;
|
const Endpoint = zap.Endpoint;
|
||||||
const fio = zap;
|
const fio = zap;
|
||||||
// const fio = @import("fio.zig");
|
|
||||||
const util = zap;
|
const util = zap;
|
||||||
// const util = @import("util.zig");
|
|
||||||
|
|
||||||
test "BearerAuthSingle authenticate" {
|
test "BearerAuthSingle authenticate" {
|
||||||
const a = std.testing.allocator;
|
const a = std.testing.allocator;
|
||||||
|
@ -132,37 +129,34 @@ const ClientAuthReqHeaderFields = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
fn makeRequest(a: std.mem.Allocator, url: []const u8, auth: ?ClientAuthReqHeaderFields) !void {
|
fn makeRequest(a: std.mem.Allocator, url: []const u8, auth: ?ClientAuthReqHeaderFields) !void {
|
||||||
const uri = try std.Uri.parse(url);
|
|
||||||
|
|
||||||
var h = std.http.Headers{ .allocator = a };
|
|
||||||
defer h.deinit();
|
|
||||||
|
|
||||||
if (auth) |auth_fields| {
|
|
||||||
const authstring = try std.fmt.allocPrint(a, "{s}{s}", .{ auth_fields.auth.str(), auth_fields.token });
|
|
||||||
defer a.free(authstring);
|
|
||||||
try h.append(auth_fields.auth.headerFieldStrHeader(), authstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
var http_client: std.http.Client = .{ .allocator = a };
|
var http_client: std.http.Client = .{ .allocator = a };
|
||||||
defer http_client.deinit();
|
defer http_client.deinit();
|
||||||
|
|
||||||
var req = try http_client.request(.GET, uri, h, .{});
|
var auth_buf: [256]u8 = undefined;
|
||||||
defer req.deinit();
|
const auth_string: []const u8 = blk: {
|
||||||
|
if (auth) |auth_fields| {
|
||||||
try req.start();
|
const authstring = try std.fmt.bufPrint(&auth_buf, "{s}{s}", .{ auth_fields.auth.str(), auth_fields.token });
|
||||||
try req.wait();
|
break :blk authstring;
|
||||||
// req.deinit() panics!
|
} else {
|
||||||
// defer req.deinit();
|
break :blk "";
|
||||||
|
}
|
||||||
// without this block, the tests sometimes get stuck which
|
};
|
||||||
// might have to do with connection pooling and connections being in
|
_ = try http_client.fetch(.{
|
||||||
// a different state when all data has been read?!?
|
.location = .{ .url = url },
|
||||||
{
|
.headers = .{
|
||||||
var buffer: [1024]u8 = undefined;
|
.authorization = .omit,
|
||||||
// we know we won't receive a lot
|
},
|
||||||
const len = try req.reader().readAll(&buffer);
|
.extra_headers = blk: {
|
||||||
std.debug.print("RESPONSE:\n{s}\n", .{buffer[0..len]});
|
if (auth) |auth_fields| {
|
||||||
}
|
break :blk &.{.{
|
||||||
|
.name = auth_fields.auth.headerFieldStrHeader(),
|
||||||
|
.value = auth_string,
|
||||||
|
}};
|
||||||
|
} else {
|
||||||
|
break :blk &.{};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
zap.stop();
|
zap.stop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,13 @@ const std = @import("std");
|
||||||
const zap = @import("zap");
|
const zap = @import("zap");
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
var h = std.http.Headers{ .allocator = a };
|
|
||||||
defer h.deinit();
|
|
||||||
|
|
||||||
var http_client: std.http.Client = .{ .allocator = a };
|
var http_client: std.http.Client = .{ .allocator = a };
|
||||||
defer http_client.deinit();
|
defer http_client.deinit();
|
||||||
|
|
||||||
var req = try http_client.request(.GET, uri, h, .{});
|
_ = try http_client.fetch(.{
|
||||||
defer req.deinit();
|
.location = .{ .url = url },
|
||||||
|
});
|
||||||
|
|
||||||
try req.start();
|
|
||||||
try req.wait();
|
|
||||||
zap.stop();
|
zap.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +17,7 @@ fn makeRequestThread(a: std.mem.Allocator, url: []const u8) !std.Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
test "http parameters" {
|
test "http parameters" {
|
||||||
var allocator = std.testing.allocator;
|
const allocator = std.testing.allocator;
|
||||||
|
|
||||||
const Handler = struct {
|
const Handler = struct {
|
||||||
var alloc: std.mem.Allocator = undefined;
|
var alloc: std.mem.Allocator = undefined;
|
||||||
|
|
|
@ -7,20 +7,16 @@ var read_len: ?usize = null;
|
||||||
const testfile = @embedFile("testfile.txt");
|
const testfile = @embedFile("testfile.txt");
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
var h = std.http.Headers{ .allocator = a };
|
|
||||||
defer h.deinit();
|
|
||||||
|
|
||||||
var http_client: std.http.Client = .{ .allocator = a };
|
var http_client: std.http.Client = .{ .allocator = a };
|
||||||
defer http_client.deinit();
|
defer http_client.deinit();
|
||||||
|
var response = std.ArrayList(u8).init(a);
|
||||||
var req = try http_client.request(.GET, uri, h, .{});
|
defer response.deinit();
|
||||||
defer req.deinit();
|
_ = try http_client.fetch(.{
|
||||||
|
.location = .{ .url = url },
|
||||||
try req.start();
|
.response_storage = .{ .dynamic = &response },
|
||||||
try req.wait();
|
});
|
||||||
read_len = try req.readAll(&buffer);
|
read_len = response.items.len;
|
||||||
|
@memcpy(buffer[0..read_len.?], response.items);
|
||||||
|
|
||||||
zap.stop();
|
zap.stop();
|
||||||
}
|
}
|
||||||
|
@ -33,7 +29,7 @@ pub fn on_request(r: zap.Request) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
test "send file" {
|
test "send file" {
|
||||||
var allocator = std.testing.allocator;
|
const allocator = std.testing.allocator;
|
||||||
|
|
||||||
// setup listener
|
// setup listener
|
||||||
var listener = zap.HttpListener.init(
|
var listener = zap.HttpListener.init(
|
||||||
|
|
|
@ -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.
|
/// 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 {
|
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_message = internal_on_message,
|
||||||
.on_open = internal_on_open,
|
.on_open = internal_on_open,
|
||||||
.on_ready = internal_on_ready,
|
.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 {
|
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))));
|
const user_provided_settings: ?*WebSocketSettings = @as(?*WebSocketSettings, @ptrCast(@alignCast(fio.websocket_udata_get(handle))));
|
||||||
var 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);
|
||||||
|
@ -74,7 +74,7 @@ pub fn Handler(comptime ContextType: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_on_open(handle: WsHandle) callconv(.C) void {
|
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 (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);
|
||||||
|
@ -83,7 +83,7 @@ pub fn Handler(comptime ContextType: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_on_ready(handle: WsHandle) callconv(.C) void {
|
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 (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);
|
||||||
|
@ -92,7 +92,7 @@ pub fn Handler(comptime ContextType: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_on_shutdown(handle: WsHandle) callconv(.C) void {
|
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 (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);
|
||||||
|
@ -101,7 +101,7 @@ pub fn Handler(comptime ContextType: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_on_close(uuid: isize, udata: ?*anyopaque) callconv(.C) void {
|
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 (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);
|
||||||
|
@ -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 {
|
pub inline fn write(handle: WsHandle, message: []const u8, is_text: bool) WebSocketError!void {
|
||||||
if (fio.websocket_write(
|
if (fio.websocket_write(
|
||||||
handle,
|
handle,
|
||||||
fio.str2fio(message),
|
util.str2fio(message),
|
||||||
if (is_text) 1 else 0,
|
if (is_text) 1 else 0,
|
||||||
) != 0) {
|
) != 0) {
|
||||||
return error.WriteError;
|
return error.WriteError;
|
||||||
|
@ -192,7 +192,7 @@ pub fn Handler(comptime ContextType: type) type {
|
||||||
/// we need it to look up the ziggified callbacks.
|
/// we need it to look up the ziggified callbacks.
|
||||||
pub inline fn subscribe(handle: WsHandle, args: *SubscribeArgs) WebSocketError!usize {
|
pub inline fn subscribe(handle: WsHandle, args: *SubscribeArgs) WebSocketError!usize {
|
||||||
if (handle == null) return error.SubscribeError;
|
if (handle == null) return error.SubscribeError;
|
||||||
var fio_args: fio.websocket_subscribe_s_zigcompat = .{
|
const fio_args: fio.websocket_subscribe_s_zigcompat = .{
|
||||||
.ws = handle.?,
|
.ws = handle.?,
|
||||||
.channel = util.str2fio(args.channel),
|
.channel = util.str2fio(args.channel),
|
||||||
.on_message = if (args.on_message) |_| internal_subscription_on_message else null,
|
.on_message = if (args.on_message) |_| internal_subscription_on_message else null,
|
||||||
|
|
31
src/zap.zig
31
src/zap.zig
|
@ -43,7 +43,7 @@ pub const Tls = @import("tls.zig");
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn get(e: *zap.Endpoint, r: zap.Request) void {
|
/// fn get(e: *zap.Endpoint, r: zap.Request) void {
|
||||||
/// const self: *StopEndpoint = @fieldParentPtr(StopEndpoint, "ep", e);
|
/// const self: *StopEndpoint = @fieldParentPtr("ep", e);
|
||||||
/// _ = self;
|
/// _ = self;
|
||||||
/// _ = r;
|
/// _ = r;
|
||||||
/// zap.stop();
|
/// zap.stop();
|
||||||
|
@ -118,10 +118,27 @@ pub fn enableDebugLog() void {
|
||||||
|
|
||||||
/// start Zap with debug logging on
|
/// start Zap with debug logging on
|
||||||
pub fn startWithLogging(args: fio.fio_start_args) void {
|
pub fn startWithLogging(args: fio.fio_start_args) void {
|
||||||
debug = true;
|
_debug = true;
|
||||||
fio.fio_start(args);
|
fio.fio_start(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers a new mimetype to be used for files ending with the given extension.
|
||||||
|
pub fn mimetypeRegister(file_extension: []const u8, mime_type_str: []const u8) void {
|
||||||
|
// NOTE: facil.io is expecting a non-const pointer to u8 values, but it does not
|
||||||
|
// not appear to actually modify the value. Here we do a const cast so
|
||||||
|
// that it is easy to pass static strings to http_mimetype_register without
|
||||||
|
// needing to allocate a buffer on the heap.
|
||||||
|
const extension = @constCast(file_extension);
|
||||||
|
const mimetype = fio.fiobj_str_new(mime_type_str.ptr, mime_type_str.len);
|
||||||
|
|
||||||
|
fio.http_mimetype_register(extension.ptr, extension.len, mimetype);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the Mime-Type registry (it will be empty after this call).
|
||||||
|
pub fn mimetypeClear() void {
|
||||||
|
fio.http_mimetype_clear();
|
||||||
|
}
|
||||||
|
|
||||||
pub const ListenError = error{
|
pub const ListenError = error{
|
||||||
AlreadyListening,
|
AlreadyListening,
|
||||||
ListenError,
|
ListenError,
|
||||||
|
@ -142,8 +159,18 @@ pub const HttpError = error{
|
||||||
pub const ContentType = enum {
|
pub const ContentType = enum {
|
||||||
TEXT,
|
TEXT,
|
||||||
HTML,
|
HTML,
|
||||||
|
XML,
|
||||||
JSON,
|
JSON,
|
||||||
|
XHTML,
|
||||||
// TODO: more content types
|
// TODO: more content types
|
||||||
|
|
||||||
|
pub const string_map = std.ComptimeStringMap(ContentType, .{
|
||||||
|
.{ "text/plain", .TEXT },
|
||||||
|
.{ "text/html", .HTML },
|
||||||
|
.{ "application/xml", .XML },
|
||||||
|
.{ "application/json", .JSON },
|
||||||
|
.{ "application/xhtml+xml", .XHTML },
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Used internally: facilio Http request callback function type
|
/// Used internally: facilio Http request callback function type
|
||||||
|
|
Binary file not shown.
|
@ -28,7 +28,8 @@ fn usage() void {
|
||||||
\\ instructions
|
\\ instructions
|
||||||
;
|
;
|
||||||
std.debug.print("{s}", .{message});
|
std.debug.print("{s}", .{message});
|
||||||
std.os.exit(1);
|
|
||||||
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
|
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
@ -88,7 +89,7 @@ fn get_tag_annotation(allocator: std.mem.Allocator, tagname: []const u8) ![]cons
|
||||||
tagname,
|
tagname,
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = try std.ChildProcess.exec(.{
|
const result = try std.ChildProcess.run(.{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.argv = &args,
|
.argv = &args,
|
||||||
});
|
});
|
||||||
|
@ -150,24 +151,26 @@ fn sendToDiscordPart(allocator: std.mem.Allocator, url: []const u8, message_json
|
||||||
// url
|
// url
|
||||||
const uri = try std.Uri.parse(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
|
// client
|
||||||
var http_client: std.http.Client = .{ .allocator = allocator };
|
var http_client: std.http.Client = .{ .allocator = allocator };
|
||||||
defer http_client.deinit();
|
defer http_client.deinit();
|
||||||
|
|
||||||
|
var server_header_buffer: [2048]u8 = undefined;
|
||||||
|
|
||||||
// request
|
// 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();
|
defer req.deinit();
|
||||||
|
|
||||||
req.transfer_encoding = .chunked;
|
req.transfer_encoding = .chunked;
|
||||||
|
|
||||||
// connect, send request
|
// connect, send request
|
||||||
try req.start();
|
try req.send();
|
||||||
|
|
||||||
// send POST payload
|
// send POST payload
|
||||||
try req.writer().writeAll(message_json);
|
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 {
|
fn sendToDiscord(allocator: std.mem.Allocator, url: []const u8, message: []const u8) !void {
|
||||||
// json payload
|
// json payload
|
||||||
// max size: 100kB
|
// 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);
|
defer allocator.free(buf);
|
||||||
var fba = std.heap.FixedBufferAllocator.init(buf);
|
var fba = std.heap.FixedBufferAllocator.init(buf);
|
||||||
var string = std.ArrayList(u8).init(fba.allocator());
|
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);
|
defer allocator.free(url);
|
||||||
sendToDiscord(allocator, url, announcement) catch |err| {
|
sendToDiscord(allocator, url, announcement) catch |err| {
|
||||||
std.debug.print("HTTP ERROR: {any}\n", .{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.
|
// we need to put the \n back in.
|
||||||
// TODO: change this by using some "search" iterator that just
|
// TODO: change this by using some "search" iterator that just
|
||||||
// returns indices etc
|
// 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);
|
defer allocator.free(output_line);
|
||||||
_ = try writer.write(output_line);
|
_ = try writer.write(output_line);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,11 @@ Modify your `build.zig.zon` like this:
|
||||||
.zap = .{
|
.zap = .{
|
||||||
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
|
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
|
||||||
.hash = "{hash}",
|
.hash = "{hash}",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
.paths = .{
|
||||||
|
"",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -6,9 +6,14 @@
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
// zap {tag}
|
// zap {tag}
|
||||||
.zap = .{
|
.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}",
|
.hash = "{hash}",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
.paths = .{
|
||||||
|
"",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -28,8 +28,11 @@ Here is a complete `build.zig.zon` example:
|
||||||
.zap = .{
|
.zap = .{
|
||||||
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
|
.url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz",
|
||||||
.hash = "{hash}",
|
.hash = "{hash}",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
.paths = .{
|
||||||
|
"",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -41,7 +44,8 @@ Then, in your `build.zig`'s `build` function, add the following before
|
||||||
const zap = b.dependency("zap", .{
|
const zap = b.dependency("zap", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.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"));
|
exe.linkLibrary(zap.artifact("facil.io"));
|
||||||
```
|
```
|
||||||
|
|
47
tools/docserver.zig
Normal file
47
tools/docserver.zig
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
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/zap";
|
||||||
|
|
||||||
|
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..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zap.mimetypeRegister("wasm", "application/wasm");
|
||||||
|
|
||||||
|
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 });
|
||||||
|
std.debug.print("\nSee docs at http://localhost:{}\n\n", .{port});
|
||||||
|
|
||||||
|
// start worker threads
|
||||||
|
zap.start(.{
|
||||||
|
.threads = 2,
|
||||||
|
.workers = 1,
|
||||||
|
});
|
||||||
|
}
|
|
@ -71,7 +71,7 @@ pub const usage_pkg =
|
||||||
;
|
;
|
||||||
|
|
||||||
pub fn gitLatestTag(gpa: Allocator, pkg_dir: []const u8) ![]const u8 {
|
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,
|
.allocator = gpa,
|
||||||
.argv = &.{
|
.argv = &.{
|
||||||
"git",
|
"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 {
|
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,
|
.allocator = gpa,
|
||||||
.argv = &.{
|
.argv = &.{
|
||||||
"git",
|
"git",
|
||||||
|
@ -266,8 +266,8 @@ pub fn cmdPkg(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
|
||||||
|
|
||||||
// computePackageHash will close the directory after completion
|
// computePackageHash will close the directory after completion
|
||||||
// std.debug.print("abspath: {s}\n", .{cwd_absolute_path});
|
// std.debug.print("abspath: {s}\n", .{cwd_absolute_path});
|
||||||
var cwd_copy = try fs.openIterableDirAbsolute(cwd_absolute_path, .{});
|
var cwd_copy = try fs.openDirAbsolute(cwd_absolute_path, .{});
|
||||||
errdefer cwd_copy.dir.close();
|
errdefer cwd_copy.close();
|
||||||
|
|
||||||
var thread_pool: ThreadPool = undefined;
|
var thread_pool: ThreadPool = undefined;
|
||||||
try thread_pool.init(.{ .allocator = gpa });
|
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(
|
break :blk try computePackageHashExcludingDirectories(
|
||||||
&thread_pool,
|
&thread_pool,
|
||||||
.{ .dir = cwd_copy.dir },
|
cwd_copy,
|
||||||
excluded_directories,
|
excluded_directories,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -355,7 +355,7 @@ fn isExecutable(file: fs.File) !bool {
|
||||||
|
|
||||||
pub fn computePackageHashExcludingDirectories(
|
pub fn computePackageHashExcludingDirectories(
|
||||||
thread_pool: *ThreadPool,
|
thread_pool: *ThreadPool,
|
||||||
pkg_dir: fs.IterableDir,
|
pkg_dir: fs.Dir,
|
||||||
excluded_directories: []const []const u8,
|
excluded_directories: []const []const u8,
|
||||||
) ![Manifest.Hash.digest_length]u8 {
|
) ![Manifest.Hash.digest_length]u8 {
|
||||||
const gpa = thread_pool.allocator;
|
const gpa = thread_pool.allocator;
|
||||||
|
@ -405,7 +405,7 @@ pub fn computePackageHashExcludingDirectories(
|
||||||
.failure = undefined, // to be populated by the worker
|
.failure = undefined, // to be populated by the worker
|
||||||
};
|
};
|
||||||
wait_group.start();
|
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);
|
try all_files.append(hashed_file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,33 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
// var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
// .thread_safe = true,
|
||||||
}){};
|
// }){};
|
||||||
var allocator = gpa.allocator();
|
// const allocator = gpa.allocator();
|
||||||
|
|
||||||
var server = std.http.Server.init(allocator, .{
|
|
||||||
.reuse_address = true,
|
|
||||||
});
|
|
||||||
defer server.deinit();
|
|
||||||
|
|
||||||
const address = try std.net.Address.parseIp("127.0.0.1", 3000);
|
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) {
|
while (true) {
|
||||||
var res = try server.accept(.{
|
const connection = try http_server.accept();
|
||||||
.allocator = allocator,
|
defer connection.stream.close();
|
||||||
.header_strategy = .{ .dynamic = max_header_size },
|
var server = std.http.Server.init(connection, &read_buffer);
|
||||||
});
|
|
||||||
// const start_time = std.time.nanoTimestamp();
|
|
||||||
defer res.deinit();
|
|
||||||
defer _ = res.reset();
|
|
||||||
try res.wait();
|
|
||||||
|
|
||||||
|
var request = try server.receiveHead();
|
||||||
const server_body: []const u8 = "HI FROM ZIG STD!\n";
|
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 request.respond(server_body, .{
|
||||||
_ = try res.readAll(&buf);
|
.extra_headers = &.{
|
||||||
_ = try res.writer().writeAll(server_body);
|
.{ .name = "content_type", .value = "text/plain" },
|
||||||
try res.finish();
|
.{ .name = "connection", .value = "close" },
|
||||||
// const end_time = std.time.nanoTimestamp();
|
},
|
||||||
// const diff = end_time - start_time;
|
});
|
||||||
// std.debug.print("{d}\n", .{diff});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue