AtlatestRepositorysigil-http
1# Changelog
2
3All notable changes to **sigil-http** are documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## [0.18.2] - 2026-07-23
9
10### Added
12- **`http-fetch-bytes`: a byte-faithful, in-memory HTTP fetch.** It returns a
13 response as `{ status, headers, body }` where the body is a raw bytevector and
14 is never decoded to a string, so binary payloads (wasm modules, tarballs,
15 images) round-trip uncorrupted. It preserves header order and duplicates (an
16 ordered alist of lowercased-name/value pairs), so a relay can faithfully
17 forward repeated headers like `Set-Cookie`, and it does not follow redirects
18 (a 3xx is returned as-is, which is what a faithful proxy needs). It handles
19 `Content-Length`, chunked, and connection-close framing, with a
20 single-allocation body assembly. `http-request` stays the string-oriented
21 convenience path; reach for `http-fetch-bytes` when the bytes must survive
22 exactly.
25## [0.18.1] - 2026-07-11
27### Fixed
29- **`http-server-stop` now actually stops a running serve loop.** The server
30 record is immutable — `http-server-start` and the serve loop derive updated
31 copies — so a caller that held the record it passed to `http-server-start`
32 never shared state with the loop, and stopping from another task silently
33 did nothing (the loop kept running forever; with the loop now suspending on
34 the scheduler, it would have kept a periodic wait alive indefinitely). The
35 stop signal now lives in a one-slot vector created per `make-http-server`
36 and carried by reference through every derived record; `http-server-stop`
37 sets it and the loop — whose waits are all deadline-bounded — sees it
38 within the sweep interval, closes the sockets it owns, and
39 `http-server-start` returns. Stopping an idle server completes in ~100ms
40 (probe-verified; hung forever before). Covered by phase 3 of
41 `test/integration/run-starvation-test.sh`.
43- **Server loop no longer starves other async tasks' socket I/O.** While at
44 least one client was connected (e.g. a browser holding an SSE stream), the
45 server loop's drain phase busy-spun a short-timeout native `socket-select`.
46 Because the async scheduler only polls socket io-waiters when its run queue
47 is empty, that busy loop kept the queue perpetually non-empty and every
48 OTHER task's socket read starved — first reads on outbound connections
49 (IRC-style clients, websocket clients, IPC sockets) were delayed for as long
50 as any HTTP client stayed connected, while timer- and channel-driven work
51 kept running. The drain now suspends on its whole socket set
52 (listen + clients) through the scheduler via `await-readable-any`, waking
53 immediately on readable data and sweeping connection timeouts on a bounded
54 deadline (1s), so sibling io-waiters are serviced within milliseconds.
55 Regression test: `test/integration/run-starvation-test.sh` (compiled probe;
56 measures a sibling socket's first-read latency with a client parked on the
57 server).
59 **Requires** sigil 0.17.10 or newer (the first release providing
60 `(sigil async)` `await-readable-any`); the package's `sigil:` requirement is
61 bumped to `^0.17.10` accordingly.
63## [0.18.0] - 2026-07-10
65### Added
67- **Persistent connections (keep-alive).** Non-streaming HTTP/1.1 responses now
68 keep the TCP connection open and serve subsequent requests on the same socket
69 instead of forcing `Connection: close` after every response. The server honors
70 an explicit `Connection: close` and defaults HTTP/1.0 to close; the age-based
71 timeout is refreshed per request so it acts as an idle timeout for kept-alive
72 connections. This removes the connection-churn that amplified image-heavy page
73 loads.
74- **Chunked response transfer-encoding.** Streaming responses whose length is
75 unknown (SSE and bare procedure bodies) are now framed with
76 `Transfer-Encoding: chunked` and a terminating `0\r\n\r\n`, instead of relying
77 on connection close for framing. `http-response/file` keeps its
78 `Content-Length` framing (byte-exact).
79- **`Range:` requests and `206 Partial Content`.** `http-response/file` accepts
80 a `range:` keyword (the raw request `Range` header) and honors byte ranges:
81 `bytes=A-B`, open-ended `bytes=A-`, and suffix `bytes=-N`. Satisfiable ranges
82 yield `206` with `Content-Range`; unsatisfiable ranges yield `416 Range Not
83 Satisfiable` with `Content-Range: bytes */<total>`; an absent or malformed
84 header falls back to a full `200`. Adds the `HTTP-RANGE-NOT-SATISFIABLE`
85 constant and exports `resolve-range`.
87### Notes
89- Reusing a **streamed** connection for keep-alive is not yet supported — a
90 streaming response still closes when the stream ends (the select loop would
91 need to re-adopt the goroutine-owned socket). HTTP request pipelining is also
92 unsupported. Both are tracked follow-ups.
94## [0.17.0] - 2026-07-10
96### Changed
98- Streaming responses (`http-response/file`, SSE) now work from a bare
99 `http-serve` / `http-server-start` **without** wrapping the call in
100 `with-async`. The server establishes its own async scheduler when none is
101 active, and reuses the caller's when one is present. This fixes streaming and
102 SSE routes throwing `go: not running in an async context` on a default
103 server, which caused large assets to intermittently fail to download.
104- `HEAD` requests now return identical status and headers (including a correct
105 `Content-Length`) with **zero body bytes**, instead of sending the full body.
107### Added
109- Opt-in automatic gzip via a `gzip:` option on `make-http-server` /
110 `http-serve` (default `#f`, so the default server is unchanged). When enabled,
111 non-streaming responses are gzip-encoded per the request's `Accept-Encoding`
112 (compressible content types over a size floor), adding `Content-Encoding:
113 gzip` and `Vary: Accept-Encoding`. Streaming and incompressible bodies are
114 left untouched.
116## [0.16.7] - 2026-07-07
118### Changed
120- Realigned the sigil toolchain pin to `^0.17`.
121- `http-response/json` now accepts either a dict or an already-encoded string.
122- `http-response/sse-broadcast` defaults its message handler to identity.
124## [0.16.6] - 2026-06-30
126### Fixed
128- HTTP client `timeout:` callers can now distinguish a request that was never
129 sent from one that was delivered but whose ack is unconfirmed.
131## [0.16.5] - 2026-06-30
133### Changed
135- Threaded a `connect-timeout:` option through the HTTP client and relocked onto
136 sigil-tls 0.16.2.
138## [0.16.4] - 2026-06-30
140### Fixed
142- Response reads now terminate on HTTP framing rather than on connection close.
144## [0.16.3] - 2026-06-29
146### Added
148- Opt-in `timeout:` keyword for HTTP client reads.
150## [0.16.2] - 2026-06-24
152### Changed
154- Repointed sigil-test dev-dependencies at the reintegrated monorepo.
156## [0.16.1] - 2026-05-31
158### Added
160- `http-response-gzip` response helper (gzip content negotiation).
162### Changed
164- Response send loop rewritten to be O(n) via offset-based partial writes,
165 avoiding O(n²) recopying of large bodies over slow links.
167## [0.16.0] - 2026-05-06
169Initial tagged release of the standalone `sigil-http` package, extracted from
170the sigil monorepo (requires sigil `^0.16`).
172### Fixed
174- Non-blocking HTTP response writes.
175- HTTP request body byte handling (Content-Length counted in bytes).
177### Added
179- Server crash diagnostics and guard blocks around the handler, streaming
180 goroutine, and server loop; an outer server-loop guard that restarts on an
181 otherwise-escaping exception.
182- SSE heartbeat utility for dead-client detection.
184[0.17.0]: https://codeberg.org/sigil/sigil-http/compare/v0.16.7...v0.17.0
185[0.16.7]: https://codeberg.org/sigil/sigil-http/compare/v0.16.6...v0.16.7
186[0.16.6]: https://codeberg.org/sigil/sigil-http/compare/v0.16.5...v0.16.6
187[0.16.5]: https://codeberg.org/sigil/sigil-http/compare/v0.16.4...v0.16.5
188[0.16.4]: https://codeberg.org/sigil/sigil-http/compare/v0.16.3...v0.16.4
189[0.16.3]: https://codeberg.org/sigil/sigil-http/compare/v0.16.2...v0.16.3
190[0.16.2]: https://codeberg.org/sigil/sigil-http/compare/v0.16.1...v0.16.2
191[0.16.1]: https://codeberg.org/sigil/sigil-http/compare/v0.16.0...v0.16.1
192[0.16.0]: https://codeberg.org/sigil/sigil-http/releases/tag/v0.16.0