Windows portability: fix TCP bind (#82) + StaticHandler/static serving#83
Merged
Merged
Conversation
TCP bind failed on Windows with 'Async\AsyncException: Failed to bind to <host>:<port>: operation not supported on socket'. The listener setup derived 'use REUSEPORT' as !http_server_use_shared_listen_fd(). That boolean models two platform camps (kernel-LB REUSEPORT vs shared-fd dup), but Windows is neither: Winsock has no SO_REUSEPORT and libuv's uv_tcp_bind() returns UV_ENOTSUP when UV_TCP_REUSEPORT is set. Since use_shared_listen_fd() is false on Windows (no POSIX dup), !false wrongly requested REUSEPORT, so every TCP bind failed. Add http_server_use_reuseport() as an explicit capability predicate: false on Windows, !use_shared_listen_fd() on POSIX. Single-listener Windows now binds directly; POSIX behaviour is unchanged. Verified locally on Windows: tests/phpt/server/h1 binds and serves (21/22 pass).
Root validation tested only for a leading '/', so every Windows path (C:\...) was rejected and StaticHandler was unusable on Windows. Use IS_ABSOLUTE_PATH (leading '/' on POSIX; drive-letter / UNC on Windows); POSIX behaviour unchanged. Found while running the server phpt suite on Windows for #82; unblocks ~8 static tests + core/033.
…nted) 009 (OwnerMatch, uid-based) and 021 (REJECT via open(O_NOFOLLOW)) exercise symlink enforcement that is POSIX-specific: O_NOFOLLOW does not exist on Windows and symlink() needs privilege there. SKIPIF records WHY and flags the Windows reparse-point enforcement as a tracked gap — explicitly not a silent mute. A real Windows reparse-point reject is a separate follow-up.
The async send_file engine opened files with O_RDONLY|O_CLOEXEC only. On Windows that is text mode: CRLF translation and a 0x1A byte treated as EOF corrupt/truncate binary bodies (precompressed .br/.gz, byte ranges, images). Add O_BINARY, mirroring open_for_policy in http_static_safety.c. No-op on POSIX (O_BINARY is 0/undefined).
REUSEPORT bind (#82), StaticHandler absolute-path acceptance, and the send_file O_BINARY fix.
Contributor
CoverageTotal lines: 81.36% → 81.42% (+0.06 pp)
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #82 —
Async\AsyncException: Failed to bind to <host>:<port>: operation not supported on socketon Windows — plus three adjacent Windows-portability bugs surfaced while running the serverphptsuite on Windows for the first time.Fixes
SO_REUSEPORT, which libuv'suv_tcp_bind()rejects withUV_ENOTSUPon Windows (Winsock has noSO_REUSEPORT). REUSEPORT is now a platform capability (http_server_use_reuseport()), never requested on Windows; the default single-listener server binds directly. No change on Linux/BSD/macOS.StaticHandleraccepts native Windows absolute paths. Root validation accepted only a leading/, rejecting everyC:\...path. Now usesIS_ABSOLUTE_PATH(drive-letter / UNC on Windows, leading/on POSIX).send_fileengine opened files withoutO_BINARY→ text-mode CRLF/0x1Acorruption/truncation of binary bodies (precompressed.br/.gz, byte ranges, images). Now opensO_BINARY, matchingopen_for_policy.O_NOFOLLOWis POSIX-only; theSKIPIFrecords the gap rather than silently muting.Verification
The server
phptsuite now executes on Windows (it was structurally skipped before). Local run across core/h1/h2/static/tls/compression/chaos: 119 pass / 10 fail / 22 skip.Known remaining Windows issues (follow-up)
Deeper reactor/lifecycle bugs, several in the separate
ext/asyncrepo — tracked for focused follow-up:RST_STREAMdoesn't cancel a blocked handler — connection read isn't pumped while the handler awaits (h2/007, h2/008, chaos/001). Basic coroutine cancellation works on Windows; this is reactor read-pumping.ThreadPoolcross-thread transfer crash (core/007) — needs a debugger.