New in the 0.4.0-SNAPSHOT development line — everything listed here landed after the 0.3.0 release and is not part of it. Every entry links to the section that documents it, and those sections carry the NEW badge. Each brick of the suite keeps its own page of this kind; the ecosystem index gathers them. When the next release train ships, this page is frozen with it and restarts empty on the dev line.
Fixes that change behaviour
-
writeTimeoutis applied —Server.Builder.writeTimeout(Duration)was accepted and never read (chappe#13). It now bounds each blocking write of an HTTP/1.1 response: when the client stops reading and the socket refuses the bytes for longer than the timeout (30 s by default), Chappe closes the connection and the client gets a truncated body, where the connection’s virtual thread used to stay blocked with no bound. It is not an inactivity bound: a Server-Sent Events stream that stays silent for minutes between events is not affected. If a client of yours legitimately stalls reading for longer than 30 s, raise the value. Reference — timeouts, Migration — upgrading from 0.3.0. -
The last response survives the close — when an HTTP/1.1 connection ends after a response (a
431, a400, orConnection: close) while request bytes are still unread, Chappe used to close at once; the TCP stack then answered with a reset, and the reset destroyed the response before the client read it ("Connection reset"). Chappe now closes in stages, as RFC 9112 §9.6 describes: it half-closes, drains what the client still sends for at most 2 s or 1 MiB, then closes, so the response ends with a FIN (chappe#19). Over TLS it sendsclose_notifyfirst and drains the ciphertext without decrypting it (chappe#21). A lost connection, a client that closed first, the idle timeout and a WebSocket takeover still close at once. Internals — threading model, HTTP capabilities.