Skip to content

Zig 0.16#190

Open
Sahasrara wants to merge 20 commits intokarlseguin:masterfrom
Sahasrara:zig-0.16
Open

Zig 0.16#190
Sahasrara wants to merge 20 commits intokarlseguin:masterfrom
Sahasrara:zig-0.16

Conversation

@Sahasrara
Copy link
Copy Markdown

No description provided.

karlseguin and others added 20 commits September 29, 2025 08:22
Also update to point to the latest websocket.zig dev commit.
karlseguin#171)

* Enhance CORS to include credentials handling and allow multi cors origin values

Added support for credentials in CORS configuration.
Allow multi cors origin values

* Enhance CORS middleware: support wildcard & multiple origins, credentials; add tests

- Add Origin union and parseOrigin() to middleware/Cors.zig; init now takes MiddlewareConfig and uses arena for origin parsing
- Support wildcard ("*") and comma-separated origin lists; set Access-Control-Allow-Origin to "*" for wildcard, or echo allowed origin for lists
- Preserve and emit Access-Control-Allow-Credentials, Allow-Methods, Allow-Headers, and Max-Age for preflight requests
- Update tests: increase test thread array size, spawn dedicated CORS servers (wildcard, single, multiple), add comprehensive tests for GET and OPTIONS preflight flows and negative cases
- Ensure Origin header is sent in relevant test requests

* Fix parsing of multiple CORS origins by initializing count to 0

* tests: stop and deinit CORS test servers in tests:afterAll

* docs(readme): cleanup formatting, fix typos, and expand CORS documentation

- Normalize whitespace, punctuation and list formatting across README
- Fix typos and improve wording for clarity
- Expand CORS middleware section with examples and behavior:
  - document wildcard, single and multiple origins
  - add credentials option and note about wildcard+credentials restriction
  - show preflight headers and 204 behavior
- Update middleware path reference to httpz.middleware.Cors
- Minor formatting tweaks in many sections (headers, code blocks, comments)
…in#180)

Add errdefer to unlock mutex when listen() fails before reaching
the success paths. Without this, errors during socket setup, binding,
or worker initialization leave the mutex locked, causing subsequent
calls to listen() or listenInNewThread() to deadlock.

This bug is particularly severe with listenInNewThread() because the
main thread waits on a condition variable, and when the spawned thread
exits with the mutex locked, the condition wakes the main thread which
then hangs forever trying to reacquire the mutex.

Adds test that verifies mutex is properly released by calling listen()
twice when bind fails. Without the fix, the second call deadlocks.
* Introduce Config.AddressConfig.

* Let callers provide a pre-parsed Address for the listener

* Express the default listener address in a simpler way

* update readme to show the new way of setting listener address
…ybe BSD)

See: karlseguin#185

he reason I didn't think it was possible is that, once we upgrade to websockets, we switch the to ONESHOT / EV_DISPATCH. And I _thought_ this would be enough to ensure that we only ever process 1 message at a time. The re-arming only happens as the last step the worker thread does..so while 2 threads could technically be running on the same connection, one of those threads would be in the process of shutting down and 100% NOT be doing anything with the connection. And that all works.

EXCEPT for a tiny window during our initial switch to EV_DISPATCH. Say a connection is upgraded and also sends 2 websocket messages. While a single poll (`kevent`) won't return 2 distinct events for that 1 connection, they could get split into 2 separate polls. We end up with:

```
wait#1
  [signal, fd#1.recv#1]
wait#2
  [fd#1.recv#2]
```

and this happens because as we're processing the wait#1 and before we switch to EV_DISPATCH, `fd#1.recv#2` has already been received and queued.  Even if you delete and re-add, it seems like that only deals with future events, it doesn't clear our any already/pending events. So we need to mimic what we alreayd do for HTTP connections, which is as a guard clause for a connection that's already being processed. But we still keep the ONESHOT / DISPATCH because it does work beyond the initial window, and that just helps prevent wakeups that we'll just have to reject via the guard.
karlseguin#186

Also add .any as an alternative to the first example in the readme
Rewrites httpz to build and test green on Zig 0.16.0. The 0.16 refactors
of std.Io, std.posix, std.net, std.heap, and std.Thread leave the 0.15
codebase unable to compile; this port reinstates the removed surface via
local io_shim/posix_shim, adapts everywhere a 0.15 API signature changed,
and fixes three subtle correctness issues surfaced by the new semantics:

  - std.c.errno(rc) checks `rc == -1` by integer VALUE, not bit pattern,
    so the 0.15-style `@as(usize, @bitcast(@as(isize, c_int_rc)))`
    pattern turns every error return into silent SUCCESS. The shim keeps
    the raw c_int through the errno check.
  - fcntl returns c_int; a flag response with bit 31 set was being
    sign-extended through isize and then panicked on `@intCast(isize →
    usize)`. The shim widens successful returns via `@as(u32, @bitcast)`.
  - kqueue EV_ADD | EV_DISPATCH requires an explicit EV_ENABLE to re-arm
    on macOS after the filter fires and auto-disables. Plain EV_ADD on
    re-arm does not reliably re-enable; websocket upgrade test's second
    frame was silently lost.

Also caught: ArrayList.clearRetainingCapacity now `@memset(items,
undefined)` in 0.16, clobbering snapshots the test runner's FakeReader
had captured; ArenaAllocator.resize now asserts `loadFirstNode().?` and
panics on empty arenas; extern-struct defaults for posix.sockaddr.in
aren't always picked up by partial init — the Address shim now
zero-fills and sets required fields explicitly.

All 109 tests pass on macOS/arm64 with Zig 0.16.0. Targets
upstream/dev as the PR base.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@karlseguin
Copy link
Copy Markdown
Owner

Hi. i wanted to thank you so much for this. I'm working on my own update, which is quite similar to yours. I also clone a chunk of posix.zig into the repo. I think the biggest difference is that Server.init takes an std.Io instance, but it only uses it for things like locks/conditions (With the eventual goal that it would actually swap out all the networking code for it).

I feel bad that you did all this work, and I probably won't end up merging it. But I wanted you to know that it's been helpful to get me un-stuck in some places.

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.

8 participants