Changes for version 0.60 - 2026-10-16

  • The compiled application is read into a C struct at `to_app`: the request path no longer looks the router, hooks, mounts and policies up by name, nor the matched route's fields, nor the context class's stash. A dynamic route costs about 0.5us over a bare PSGI app in-process, down from 0.9us.
  • A static mount of Punk's own is served without the SCRIPT_NAME and PATH_INFO rewrite or a Perl frame, and its ETag and Last-Modified are formatted once per stat, not per hit.
  • The session reads its cookie through the C parser; `rate_limit` keeps the resolved ABI pointer instead of scanning the environment per request (the `PUNK_NO_HM_ABI` switch is read before the first request); the CSP policy is frozen around the nonce; `headers` hands out its frozen list rather than copying it; metrics keep the start time in a context slot.
  • A WebSocket message in one frame is handed on from the read buffer; ping and pong payloads are built only for a listener; a room broadcast queues to each member in C; buffers that grew for a large message shrink back once empty.
  • SECURITY: `$f->get`, `$c->await` and the csrf check wrote to a stale stack after running Perl.
  • SECURITY: the OpenAPI mount validated a body it never read when the request carried no Content-Length, and reserved a declared length up front.
  • SECURITY: a middleware editing a static body in place edited the file cache, and every later hit served the edit.
  • SECURITY: one WebSocket client could keep a worker to itself.
  • SECURITY: a rate limit keyed on a header limited nothing when the header was absent; it counts against the address.
  • SECURITY: `database backend` and `$c->txn` loaded a class named in config without checking it was a class name.

Documentation

the Punk command line

Modules

a MVC web framework
the per-application registry and boot compiler
async and await in Punk apps, controllers and models
the authentication battery
password hashing
cross-origin resource sharing
single-use CSRF tokens
a pluggable cache with TTL
a cache store on disk, shared by the whole worker pool
an in process cache store, bounded by bytes
the punk command line: registry, dispatcher and commands
YAML configuration with secrets kept out of the file
the per-request object
base class for Punk controllers
the DBI subclass that makes every statement observable
the observed database handle
the observed statement handle
the development error page
an async result that runs on the loop, or blocks
scaffold a new Punk application
security response headers
a level-based logger
the storage-agnostic model tier
the default DBI backend for Punk models
a non-blocking backend for Punk models
a directory of markdown as a documentation site
the api mount: spec-first operations
base class for Punk plugins
content addressed storage for uploads
Content-Security-Policy with a per request nonce
ETags, Last-Modified and 304s for dynamic responses
liveness and readiness probes that mean different things
translations and language negotiation
Idempotency on unsafe methods
a Prometheus endpoint whose labels cannot run away
give every request an id
sitemap.xml and robots.txt from the route table
rate limiting and IP blocking over Hyperman's shared arena
a lazy wrapper over the PSGI environment
a response builder
the compiled-at-boot route tables (XS)
the handle an under returns
a Server-Sent Events stream
the bounded body of a ranged send_file response
signed cookie sessions
server-side sessions, on any store
serving files from a directory
a streamed response for an ordinary route
an in-process test client for Punk applications
a pure-Perl RFC 6455 codec for testing WebSocket servers
the client side of one WebSocket connection
the transaction a $c->txn block receives
the outbound HTTP agent on the context
an uploaded file from a multipart form
collecting request validation
the Template::Stencil view engine
the pluggable view engine registry (XS)
a WebSocket connection
pub/sub groups of WebSocket connections