feat(http3): transport reactor pool + CID steering + hq-interop endpoint (#80)#90
Merged
EdmondDantes merged 9 commits intoJun 26, 2026
Conversation
5 tasks
Contributor
CoverageTotal lines: 81.42% → 75.80% (-5.62 pp)
❌ Regression in touched files (> 1.0 pp drop)
Add |
…int (#80) Split the HTTP/3 transport from PHP execution and add the interop endpoint. Reactor pool (D1-D8, gated TRUE_ASYNC_SERVER_REACTOR_POOL=1 + setWorkers(2+)): dedicated C reactors own the QUIC sockets - no PHP on the transport thread. Parsed requests cross to PHP workers by pointer (one http_request_t, persistent allocation domain, flag-aware accessors); responses return over a non-blocking reverse channel. Buffered GET/POST and static are served on the reactor; reactor-paired sticky dispatch with load spill (D5). CID steering (D6): owner-reactor id encoded in the connection id, stray (migrated) datagrams forwarded to the owner; migration-storm guard sheds connections rebinding past a rate cap. Fix: register issued NEW_CONNECTION_ID CIDs in the conn_map so rotated DCIDs route (RFC 9000 5.1). Interop: second QUIC ALPN hq-interop served straight off the transport (no nghttp3) - raw GET <path> -> file bytes + FIN from setHttp3HqDocroot(), zero-copy via mmap, correct FIN incl. empty bodies; h3 stays preferred. quic-interop-runner endpoint with a build-from-source Dockerfile. Tests: full h3 phpt suite 44/44 on release and under ASan (no UAF / overflow / double-free) across the split, CID steering and the hq path; hq validated byte-exact (0/1/5K/16K/128K/512K), multiplexing, traversal, and under 5% packet loss; real HTTP/3 confirmed with an independent aioquic h3 client. Fuzz: weak stub for http_request_init_headers so the parser/h2 fuzz targets link. Refs #80.
07ce14c to
c92b4ea
Compare
….c (#80) These are HTTP_SERVER_TEST_HOOKS-gated entry points the phpt suite calls to drive reactor-pool / worker internals directly — not a unit test. The old name read like a stray test living in src/core; the new name makes clear it is test-hook plumbing. Pure rename: file body and build gating unchanged, config.m4 / config.w32 / CMakeLists updated. reactor_pool phpt 9/9 green.
The rename commit staged only the file move; git add aborted on a stale pathspec, so config.m4 / CMakeLists.txt / config.w32 still listed the old reactor_pool_test.c and a fresh build/checkout could not find it. Completes the rename.
Strip task/PR/phase tags from function bodies (allowed only in module-header banners per CODING_STANDARDS sec 13a.4), drop decorative WHAT-restating and "used by X" notes, collapse over-verbose docstrings -- keeping the load-bearing lifetime/threading/UAF/security invariants. Comments only; no behaviour change. h3 + reactor_pool phpt 53/53.
) §1: confine the hq-interop file open to the docroot via openat2(RESOLVE_BENEATH) with a realpath+containment fallback, closing the realpath()->open() TOCTOU window. Gate the POSIX mmap path under #ifndef PHP_WIN32 (Windows stub returns false; munmap site guarded too) so http3 compiles on Win32. Cleanups across the #80 reactor/worker + H3 code: - dead internal NULL-checks -> ZEND_ASSERT (worker inbox/dispatch/registry, http3 packet/listener/connection/dispatch/callbacks; both coroutine disposes). - const on write-once locals/params and read-only accessors. - EXPECTED/UNEXPECTED hints on cold reject/overflow/alloc-fail branches only. - local/param renames for clarity; drop a stray scope block; magic 12 -> sizeof; refresh a stale "reactors carry no transport" comment. Build clean (0 warnings), phpt 240/240. Claude-Session: https://claude.ai/code/session_019jfu3UHdtfatCpeAM69zeQ
) PHP 8.6's php-sdk-binary-tools (php-sdk-2.7.1) no longer ships vs17 deps, so the old config failed at the SDK step: "The passed CRT 'vs17' doesn't match any available for branch '8.6'". Mirror the true-async/releases workflow, whose Windows job is green: runner windows-2025-vs2026 (VS2026 toolset), CRT vs18, SDK branch php-sdk-2.7.1. Claude-Session: https://claude.ai/code/session_019jfu3UHdtfatCpeAM69zeQ
…eases) (#80) After the vs18 bump the build got past the SDK step but died in build.bat: find-vs-toolset.bat buckets every MSVC >= 14.30 as "vs17" and has no vs18 bucket, so `-s %VS_TOOLSET%` resolved to "ERROR: no toolset found for vs18". The true-async/releases Windows job (green) doesn't pin the toolset at all — it runs `%SDK_RUNNER% -t <task>` and lets phpsdk-vs18 select the default. Mirror that in build.bat and test.bat (find-vs-toolset.bat now unused). Claude-Session: https://claude.ai/code/session_019jfu3UHdtfatCpeAM69zeQ
…ally (#80) CI (LINUX_X64_DEBUG_ZTS) intermittently saw cooldown_blocked=0 (expected 1). Root cause: conn1 was an idle keep-alive (drain_spread defaults to 5s, so it is not drained at its first commit), so its single conn slot only freed when the client's 3s read timed out and FIN'd. On a slow/loaded debug build the slot-free -> listener-resume -> conn2-accept chain then overran conn2's own read window, so conn2's blocked event had not registered at the fixed-sleep read. Fix: send `Connection: close` on conn1 so the server frees the slot right after its response (server-initiated), and poll for the stable terminal state (epoch/reactive/blocked = 1/1/1) instead of reading once after a fixed sleep. Verified 12/12 under full 16-core CPU saturation. Claude-Session: https://claude.ai/code/session_019jfu3UHdtfatCpeAM69zeQ
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.
What
The #80 work: split the HTTP/3 transport from PHP execution (reactor pool),
add CID steering + a migration-storm guard, fix rotated-DCID routing, and
add a quic-interop endpoint with an
hq-interop(HTTP/0.9-over-QUIC) shim.49 commits, ~+8.7k/-0.7k LOC. The hot h3 path stays byte-for-byte unchanged
(all new behaviour is gated/parallel); the full h3 phpt suite is green and
ASan-clean throughout.
Highlights
Transport reactor pool (D1–D8, gated
TRUE_ASYNC_SERVER_REACTOR_POOL=1+setWorkers(2+))http_request_t,persistent allocation domain, flag-aware accessors); responses return over
a non-blocking reverse channel. Buffered GET/POST + static served on the
reactor. Reactor-paired sticky dispatch with load spill (D5).
CID steering (D6) + robustness
forwarded to the owner reactor. Migration-storm guard sheds connections
that rebind past a rate cap. Known limitation documented: a circular
path-validation deadlock under pathological back-to-back migrations.
DCIDs route (RFC 9000 §5.1).
Interop endpoint + hq-interop shim
hq-interopserved straight off the transport (nonghttp3): raw
GET <path>-> file bytes + FIN fromsetHttp3HqDocroot(),zero-copy via mmap, correct FIN incl. empty bodies. h3 stays preferred.
tests/interop/quic/, build-from-sourceDockerfile).
Testing
instrumented .so): zero use-after-free / overflow / double-free across the
reactor split, CID steering, and the hq path.
and under 5% packet loss (netem) — plus a live quic-go interop client
(downloaded files, exit 0).
:status 200,byte-exact 5K + 512K).
Known follow-ups (not blocking)
it (raw ptr proven safe today).
simulator's packet capture is incomplete under Docker Desktop + WSL2.
Refs #80.