Revision history for Hyperman

0.11    2026-08-06
        - Connection detach, the protocol-upgrade seam: Hyperman::detach($env)
          hands a live HTTP/1 socket to the application. The server stops
          watching the fd, forgets the connection and does not close it, so
          the app's own psgix.loop watchers on that fd fire. The app writes
          its own upgrade response and returns a discarded sentinel
          ([101, [], []]). This is what a WebSocket layer needs; before it,
          a hijacked socket kept racing the server's own read watcher.
        - $env->{'psgix.hyperman.conn'} = [ fd, generation id ] - the ticket
          detach works from, and the way an app detects that detaching is
          possible (HTTP/2 streams and other servers do not provide it).
        - Detach is refused, with a specific message, for HTTP/2 and TLS
          connections, a stale ticket, a response still draining, and a
          second detach of the same connection.
        - 1xx and 426 responses now carry their real reason phrase: a 101
          serialised as "HTTP/1.1 101 OK" before this.

0.10    2026-08-05
        - Public C ABI for XS consumers 

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.
