Revision history for Hyperman
0.09 2026-08-04
- Chunked request bodies (Transfer-Encoding: chunked) are now decoded
(HTTP/1). The decoded body is presented as psgi.input with a matching
CONTENT_LENGTH; chunk extensions and trailers are accepted.
- Security: harden HTTP/1 request framing against request smuggling
(RFC 7230 3.3.3). Transfer-Encoding together with Content-Length, a
repeated Transfer-Encoding, or a duplicate/malformed Content-Length
(a sign, whitespace, trailing junk, or overflow) is rejected 400; an
unsupported transfer coding is 501. All close the connection so no
chunk data can be mis-framed as a following pipelined request.
t/21-smuggling.t.
- Security: the built-in redirect_https listener now truncates the
reflected Host and request-target at the first control/space byte, so
a bare LF in the Host header cannot inject or split the 301 response.
Fuzz harness for the request parser under ASan/UBSan in tools/fuzz/.
- Robustness: allocation helpers hm_xmalloc/hm_xcalloc/hm_xrealloc that
croak on OOM, so no hot-path allocation dereferences a NULL result.
tools/cppcheck.sh runs a static-analysis scan (clean).
- PSGI env: add REMOTE_HOST (the peer address, like REMOTE_ADDR),
REMOTE_PORT (the peer's port, captured at accept), and
psgix.input.buffered => 1 (psgi.input is a seekable in-memory :scalar
handle). Set for both HTTP/1 and HTTP/2.
- Multiple listeners in one run(). Pass listen => [ {..}, .. ] to bind
several listeners, each independently plain or TLS - the driving case
being plain :80 beside HTTPS :443 - or port => [80, 8080] as sugar for
several plain listeners sharing the top-level options. SERVER_PORT and
psgi.url_scheme reflect the listener each request arrived on.
- Built-in https redirect. A listener with redirect_https => $port
answers every request with a 301 to the same host and target on that
https port.
0.07 2026-08-03
- Build on OpenSSL older than 1.0.2. ALPN (SSL_CTX_set_alpn_select_cb),
used to offer HTTP/2 over TLS, is absent before 1.0.2, so the module
linked an undefined symbol and failed to load on such smokers. Guard
it behind a version check.
0.06 2026-08-02
- Fast default access log. access_log now accepts a file path or an
open handle in addition to a coderef: Hyperman then formats an
Apache Combined Log Format line in C and appends it directly, with
no per-request Perl call on the hot path.
- Populate REMOTE_ADDR in the PSGI env (HTTP/1 and HTTP/2), captured
from the peer at accept. Needed by the access log and expected by
apps.
0.05 2026-08-02
- Various fixes to compile on perls older than 5.16.
- Correct MIN_PERL_VERSION from 5.008003 to 5.010000
0.04 2026-08-02
- Link -lrt when clock_gettime needs it. backend_poll.c calls
clock_gettime(CLOCK_MONOTONIC), which on glibc before 2.17 lives in
librt, not libc.
- t/12-loop.t: make the persistent-watcher subtest more robust by adding a
watcher to prevent the test hanging like it has in some cpantesters environments.
0.03 2026-08-01
- TLS: build against pre-1.1.0 OpenSSL. Older releases lack
OPENSSL_init_ssl(), the OPENSSL_INIT_LOAD_*_STRINGS constants,
TLS_server_method(), and SSL_CTX_set_min_proto_version(); provide
a compatibility shim (SSL_library_init + SSLv23_server_method +
SSL_OP_NO_* protocol fencing) so hm_tls.h compiles instead of
failing with undeclared-identifier errors on those hosts. Also map
SSL_get1_peer_certificate to SSL_get_peer_certificate before 3.0.
- Makefile.PL: bail out cleanly (NA, not FAIL) on native Windows.
Hyperman needs fork, POSIX signals, sockets, sys/uio, and a
kqueue/epoll/io_uring/poll backend, none of which MSWin32/MinGW
provides (the build previously died on a missing <sys/uio.h>).
- t/14-prod.t: bound the respawn/recycle/stats polls by wall-clock
time instead of fixed iteration counts. A -9'd worker is respawned
with exponential backoff, so on loaded smokers the replacement can
lag; the fixed windows produced intermittent failures on the
"request counter advanced" and "supervisor respawned a replacement
worker" assertions.
0.02 2026-08-01
- io_uring backend: assign sqe->user_data directly instead of calling
io_uring_sqe_set_data64(), which only exists in liburing >= 2.2 and
left the .so with an undefined symbol on hosts with older liburing.
- Supervisor: close a signal lost-wakeup race. The pool loop now keeps
TERM/INT/HUP/USR1/USR2/CHLD blocked, reaps with WNOHANG, and waits
via sigsuspend(), so a USR1 stats dump (or any signal) arriving while
the pool is idle is serviced immediately instead of stalling until a
worker happened to exit. Fixes intermittent t/15-process.t failures.
0.01 2026-07-31
First release.
- Event-loop PSGI server: prefork supervisor + per-worker XS loop.
Passes the full Plack::Test::Suite; runs any Plack app via
`plackup -s Hyperman`.
- Pluggable readiness backends behind one C vtable: kqueue
(macOS/BSD), epoll (Linux), portable poll fallback, and an opt-in
io_uring backend (raw syscalls, poll-mode ring). Selection is
automatic; force with HYPERMAN_BACKEND.
- Hyperman::Future: native XS array-slot Future-compatible async
result. Handlers may return a Future (or any on_ready-compatible
object, e.g. CPAN Future) of the PSGI response; get/await pump the
worker's own loop re-entrantly.
- Async PSGI: psgi.streaming/delayed responder with a streaming
writer, psgix.io (dup'd client socket), psgix.loop, cancellation
of the response Future on client disconnect, timer and io_ready
Futures on the loop.
- Production: worker respawn with crash-loop throttle, SIGHUP
zero-downtime worker recycle, graceful TERM/INT drain, idle and
slow-request timeouts, pipelining fairness cap, request size
ceiling with 413, opt-in SO_REUSEPORT per-worker listeners
(Linux), access_log callback, Hyperman->stats.