AtlatestRepositorysigil-http
sigil-http / treeCHANGELOG.md
1
# Changelog3
All notable changes to **sigil-http** are documented in this file.5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),6
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).8
## [0.18.2] - 2026-07-2310
### Added12
- **`http-fetch-bytes`: a byte-faithful, in-memory HTTP fetch.** It returns a13
response as `{ status, headers, body }` where the body is a raw bytevector and14
is never decoded to a string, so binary payloads (wasm modules, tarballs,15
images) round-trip uncorrupted. It preserves header order and duplicates (an16
ordered alist of lowercased-name/value pairs), so a relay can faithfully17
forward repeated headers like `Set-Cookie`, and it does not follow redirects18
(a 3xx is returned as-is, which is what a faithful proxy needs). It handles19
`Content-Length`, chunked, and connection-close framing, with a20
single-allocation body assembly. `http-request` stays the string-oriented21
convenience path; reach for `http-fetch-bytes` when the bytes must survive22
exactly.25
## [0.18.1] - 2026-07-1127
### Fixed29
- **`http-server-stop` now actually stops a running serve loop.** The server30
record is immutable — `http-server-start` and the serve loop derive updated31
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 silently33
did nothing (the loop kept running forever; with the loop now suspending on34
the scheduler, it would have kept a periodic wait alive indefinitely). The35
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 it38
within the sweep interval, closes the sockets it owns, and39
`http-server-start` returns. Stopping an idle server completes in ~100ms40
(probe-verified; hung forever before). Covered by phase 3 of41
`test/integration/run-starvation-test.sh`.43
- **Server loop no longer starves other async tasks' socket I/O.** While at44
least one client was connected (e.g. a browser holding an SSE stream), the45
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 queue47
is empty, that busy loop kept the queue perpetually non-empty and every48
OTHER task's socket read starved — first reads on outbound connections49
(IRC-style clients, websocket clients, IPC sockets) were delayed for as long50
as any HTTP client stayed connected, while timer- and channel-driven work51
kept running. The drain now suspends on its whole socket set52
(listen + clients) through the scheduler via `await-readable-any`, waking53
immediately on readable data and sweeping connection timeouts on a bounded54
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 the57
server).59
**Requires** sigil 0.17.10 or newer (the first release providing60
`(sigil async)` `await-readable-any`); the package's `sigil:` requirement is61
bumped to `^0.17.10` accordingly.63
## [0.18.0] - 2026-07-1065
### Added67
- **Persistent connections (keep-alive).** Non-streaming HTTP/1.1 responses now68
keep the TCP connection open and serve subsequent requests on the same socket69
instead of forcing `Connection: close` after every response. The server honors70
an explicit `Connection: close` and defaults HTTP/1.0 to close; the age-based71
timeout is refreshed per request so it acts as an idle timeout for kept-alive72
connections. This removes the connection-churn that amplified image-heavy page73
loads.74
- **Chunked response transfer-encoding.** Streaming responses whose length is75
unknown (SSE and bare procedure bodies) are now framed with76
`Transfer-Encoding: chunked` and a terminating `0\r\n\r\n`, instead of relying77
on connection close for framing. `http-response/file` keeps its78
`Content-Length` framing (byte-exact).79
- **`Range:` requests and `206 Partial Content`.** `http-response/file` accepts80
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 ranges82
yield `206` with `Content-Range`; unsatisfiable ranges yield `416 Range Not83
Satisfiable` with `Content-Range: bytes */<total>`; an absent or malformed84
header falls back to a full `200`. Adds the `HTTP-RANGE-NOT-SATISFIABLE`85
constant and exports `resolve-range`.87
### Notes89
- Reusing a **streamed** connection for keep-alive is not yet supported — a90
streaming response still closes when the stream ends (the select loop would91
need to re-adopt the goroutine-owned socket). HTTP request pipelining is also92
unsupported. Both are tracked follow-ups.94
## [0.17.0] - 2026-07-1096
### Changed98
- Streaming responses (`http-response/file`, SSE) now work from a bare99
`http-serve` / `http-server-start` **without** wrapping the call in100
`with-async`. The server establishes its own async scheduler when none is101
active, and reuses the caller's when one is present. This fixes streaming and102
SSE routes throwing `go: not running in an async context` on a default103
server, which caused large assets to intermittently fail to download.104
- `HEAD` requests now return identical status and headers (including a correct105
`Content-Length`) with **zero body bytes**, instead of sending the full body.107
### Added109
- 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 are114
left untouched.116
## [0.16.7] - 2026-07-07118
### Changed120
- 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-30126
### Fixed128
- HTTP client `timeout:` callers can now distinguish a request that was never129
sent from one that was delivered but whose ack is unconfirmed.131
## [0.16.5] - 2026-06-30133
### Changed135
- Threaded a `connect-timeout:` option through the HTTP client and relocked onto136
sigil-tls 0.16.2.138
## [0.16.4] - 2026-06-30140
### Fixed142
- Response reads now terminate on HTTP framing rather than on connection close.144
## [0.16.3] - 2026-06-29146
### Added148
- Opt-in `timeout:` keyword for HTTP client reads.150
## [0.16.2] - 2026-06-24152
### Changed154
- Repointed sigil-test dev-dependencies at the reintegrated monorepo.156
## [0.16.1] - 2026-05-31158
### Added160
- `http-response-gzip` response helper (gzip content negotiation).162
### Changed164
- 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-06169
Initial tagged release of the standalone `sigil-http` package, extracted from170
the sigil monorepo (requires sigil `^0.16`).172
### Fixed174
- Non-blocking HTTP response writes.175
- HTTP request body byte handling (Content-Length counted in bytes).177
### Added179
- Server crash diagnostics and guard blocks around the handler, streaming180
goroutine, and server loop; an outer server-loop guard that restarts on an181
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.0185
[0.16.7]: https://codeberg.org/sigil/sigil-http/compare/v0.16.6...v0.16.7186
[0.16.6]: https://codeberg.org/sigil/sigil-http/compare/v0.16.5...v0.16.6187
[0.16.5]: https://codeberg.org/sigil/sigil-http/compare/v0.16.4...v0.16.5188
[0.16.4]: https://codeberg.org/sigil/sigil-http/compare/v0.16.3...v0.16.4189
[0.16.3]: https://codeberg.org/sigil/sigil-http/compare/v0.16.2...v0.16.3190
[0.16.2]: https://codeberg.org/sigil/sigil-http/compare/v0.16.1...v0.16.2191
[0.16.1]: https://codeberg.org/sigil/sigil-http/compare/v0.16.0...v0.16.1192
[0.16.0]: https://codeberg.org/sigil/sigil-http/releases/tag/v0.16.0