Skip to content

feat(zig-ffi): HTTP server primitives for OikosBot webhook receiver - #77

Merged
hyperpolymath merged 2 commits into
mainfrom
feat/zig-ffi-http-server
Aug 11, 2026
Merged

feat(zig-ffi): HTTP server primitives for OikosBot webhook receiver#77
hyperpolymath merged 2 commits into
mainfrom
feat/zig-ffi-http-server

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Adds a synchronous, single-threaded HTTP/1.1 server FFI surface for sitting behind a TLS reverse proxy (Caddy / nginx). Intended use: the OikosBot links libgateway.so alongside libhpm_crypto.so and composes them — no router, no TLS, no concurrency primitives here.

Why this repo: the user-elected home for HTTP server primitives, matching the repo's HTTP-domain identity (verb governance is the Elixir layer; this is the protocol-primitive layer alongside the existing gRPC / GraphQL parsers).

New Zig exports (libgateway.so):

  • hpm_http_server_listen / _port / _free / _accept
  • hpm_http_request_method / _path / _header / _body / _respond / _free

Implementation notes:

  • Heap-allocated RequestCtx holds the connection + IO buffers + the std.http.Server + parsed std.http.Server.Request, so inner Reader / Writer pointer addresses stay stable for the lifetime of the request.
  • Headers parsed via std.http.Server's HeaderIterator with case-insensitive name match.
  • Method enum ordinal matches std.http.Method directly (GET=0..PATCH=8).
  • Body capped at 1 MiB; content-length-driven read; idempotent.
  • Connection always closes after respond (keep_alive=false) — keeps the surface narrow for v1.

Idris2 ABI:

  • New src/abi/HttpServer.idr with %foreign declarations and safe wrappers mirroring the Zig exports. gateway.ipkg updated.

Tests:

  • 15/15 main module tests pass (zig test src/main.zig -lc): GET / POST + body / header lookup / header-absent / path size-query / extra response headers / arbitrary status / method ordinals / null req safety / listen failure paths / port introspection.

Pre-existing build hygiene fixes (latent under Zig 0.15.2):

  • Handle: opaque → struct (Zig 0.15 forbids fields on opaque {}).
  • Callback callconv: .C → .c (rename in Zig 0.15).

Unrelated red test: ffi/zig/grpc/parser.zig::"parse gRPC frame header" fails because the test fixture isn't a valid HTTP/2 HEADERS frame. Pre-existing on main; not addressed here.

Summary

Closes #

Type of change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (would change existing behaviour)
  • 🕳️ Soundness fix (fixes a checker/proof false-negative)
  • 📖 Documentation
  • 🧹 Refactor / tech debt (behaviour-preserving)
  • ⚡ Performance
  • 🔧 Build / CI / tooling

How has this been verified?

Checklist

  • My commits are signed (git commit -S).
  • I ran the project's own checks/tests locally and they pass.
  • New files carry the correct SPDX-License-Identifier (code/config MPL-2.0,
    prose CC-BY-SA-4.0); I did not relicense existing files.
  • Docs are updated, and no public claim now overstates what the code does.
  • I have not introduced a soundness hole (or I have flagged where I might have).

Notes for reviewers

hyperpolymath and others added 2 commits May 28, 2026 08:50
Adds a synchronous, single-threaded HTTP/1.1 server FFI surface for
sitting behind a TLS reverse proxy (Caddy / nginx). Intended use:
the OikosBot links libgateway.so alongside libhpm_crypto.so and
composes them — no router, no TLS, no concurrency primitives here.

Why this repo: the user-elected home for HTTP server primitives,
matching the repo's HTTP-domain identity (verb governance is the
Elixir layer; this is the protocol-primitive layer alongside the
existing gRPC / GraphQL parsers).

New Zig exports (libgateway.so):
- hpm_http_server_listen / _port / _free / _accept
- hpm_http_request_method / _path / _header / _body / _respond / _free

Implementation notes:
- Heap-allocated RequestCtx holds the connection + IO buffers + the
  std.http.Server + parsed std.http.Server.Request, so inner Reader /
  Writer pointer addresses stay stable for the lifetime of the request.
- Headers parsed via std.http.Server's HeaderIterator with
  case-insensitive name match.
- Method enum ordinal matches std.http.Method directly (GET=0..PATCH=8).
- Body capped at 1 MiB; content-length-driven read; idempotent.
- Connection always closes after respond (keep_alive=false) — keeps
  the surface narrow for v1.

Idris2 ABI:
- New src/abi/HttpServer.idr with %foreign declarations and safe
  wrappers mirroring the Zig exports. gateway.ipkg updated.

Tests:
- 15/15 main module tests pass (zig test src/main.zig -lc):
  GET / POST + body / header lookup / header-absent / path size-query /
  extra response headers / arbitrary status / method ordinals / null req
  safety / listen failure paths / port introspection.

Pre-existing build hygiene fixes (latent under Zig 0.15.2):
- Handle: opaque → struct (Zig 0.15 forbids fields on opaque {}).
- Callback callconv: .C → .c (rename in Zig 0.15).

Unrelated red test: ffi/zig/grpc/parser.zig::"parse gRPC frame header"
fails because the test fixture isn't a valid HTTP/2 HEADERS frame.
Pre-existing on main; not addressed here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
@hyperpolymath
hyperpolymath merged commit 2814967 into main Aug 11, 2026
20 of 21 checks passed
@hyperpolymath
hyperpolymath deleted the feat/zig-ffi-http-server branch August 11, 2026 23:23
@gitar-bot

gitar-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant