PSL 6.1.0
In PSL 5.x, we focused on the foundational networking stack-TCP, TLS, Unix sockets, UDP, and connection pooling. It was all about getting the low-level plumbing right.
With the 6.x series, we're moving up the stack and diving into protocols. Our ultimate goal is to bring robust support for HTTP/2, DNS, SMTP, WebSockets, and more. PSL 6.1.0 is the crucial first step: it delivers the core infrastructure that all of these upcoming features will rely on.
What's Coming Next?
Everything in 6.1 was built with a clear destination in mind. We are paving the way for:
- π HTTP Client - Powered by our new H2 and TLS implementations, featuring automatic protocol negotiation, HTTP/1.1 fallback, and connection pooling.
- π₯οΈ HTTP Server β A fully asynchronous HTTP/1.1 and HTTP/2 server with middleware support.
- π DNS β A complete async resolver supporting DNSSEC, DNS-over-TLS, caching, and racing resolvers.
- π§ SMTP β Fully asynchronous email delivery.
- π WebSockets β Supported both standalone over HTTP/1.1 and via H2's extended CONNECT.
The components introduced today are the engine for this roadmap. The new H2 connections will drive the HTTP client and server, the new async Cache will back the DNS resolver, and the new Compression system will handle content-encoding seamlessly.
What's New in 6.1.0
ποΈ Streaming Compression
We've added streaming compression and decompression natively to IO handles. By defining your own CompressorInterface or DecompressorInterface (brotli, gzip, zstd, etc.), PSL gives you four handle decorators to wire them directly into the IO system:
CompressingReadHandle&CompressingWriteHandleDecompressingReadHandle&DecompressingWriteHandle
We've also included compress() and decompress() convenience functions for simple, one-shot operations. Under the hood, write handles implement the new BufferedWriteHandleInterface for explicit flushing and cancellation, while read handles accept configurable chunk sizes. Compressors automatically reset after calling finish(), making them easily reusable across streams.
π¦ HPACK (HTTP/2 Header Compression)
This release includes a complete RFC 7541 encoder and decoder, featuring static table lookups, dynamic table indexing, and Huffman coding.
We wanted to be absolutely certain of its reliability, so we tested it against 14 independent implementations from the http2jp test suite. That translates to 1,172 tests and over 102,000 assertions, covering every encoding variant and edge case with full roundtrip verification.
β‘ H2 (HTTP/2 Binary Framing)
Weβve shipped full support for the HTTP/2 binary framing protocol (RFC 9113), plus key extensions.
To keep responsibilities clean, connections are split by role. ServerConnection handles client prefaces, response headers, server pushes, Alt-Svc, and ORIGIN. Meanwhile, ClientConnection manages connection prefaces, priority signaling, and extended CONNECT.
Comprehensive Frame Support:
- All 10 core frame types.
ALTSVC(RFC 7838) for HTTP/3 migration signaling.ORIGIN(RFC 8336) for connection coalescing.PRIORITY_UPDATE(RFC 9218) for extensible prioritization.
Smart, Async-Native Flow Control:
We've designed flow control to get out of your way. sendAllData() automatically chunks payloads by window size and waits for updates. waitForSendWindow() suspends the fiber entirely (zero polling!) and resumes exactly when the window opens. Multiple fibers can wait on different streams with independent cancellation, and connection-level updates efficiently wake all relevant waiters.
Additional H2 Features:
- BDP auto-tuning for dynamic receive window sizing.
- Built-in rate limiting to prevent SETTINGS, PING, or RST_STREAM floods.
- Auto-GOAWAY on protocol errors, eliminating manual error handling.
- Deep stream introspection (
getStreamState(),activeStreamCount(),isConnected()). - Extended CONNECT (RFC 8441) to bootstrap WebSockets over H2.
- Immutable
ServerConfigurationandClientConfigurationusing fluentwith*builders.
π§ Async-Safe Memory Cache
We're introducing an async-safe, in-memory LRU cache. The standout feature here is per-key atomicity powered by KeyedSequence.
If two fibers request the same cache key simultaneously, only one will compute the result. The other simply waits and receives the cached valueβpreventing cache stampedes and eliminating duplicate work.
LocalStore: A bounded LRU cache with a configurable max size and TTL support. It uses an event loop timer for proactive expiration, dropping to zero overhead when there are no expiring entries.NullStore: A dummy cache that never stores and always recomputes. It's perfect for testing or temporarily disabling caching without having to modify your calling code.
π IO Enhancements
We've introduced BufferedWriteHandleInterface, which extends the standard WriteHandleInterface with a flush() method. This is essential for handles that buffer data internally (like the new compression writers) and need an explicit "send everything now" trigger with full cancellation support.