Caching
The protocol includes ETag-based caching to avoid redundant data transfer and Cache-Control: no-store to prevent stale data in intermediate caches.
ETags
Every 200 OK GET response includes an ETag header encoding the read range:
ETag: "{start_offset}:{end_offset}"
The start offset is the query parameter value (including sentinels like -1 or now). The end offset is the Stream-Next-Offset from the same response.
Closed stream suffix
When the stream is closed and the reader is at the tail, the ETag has a :c suffix:
ETag: "-1:0000000000000003_000000000000001a:c"
Examples
GET ?offset=-1 → ETag: "-1:0000000000000003_000000000000001a"
GET ?offset=now → ETag: "now:0000000000000003_000000000000001a"
GET ?offset=0000...0001 → ETag: "0000...0001:0000...0003"
Conditional requests (304)
Clients can send If-None-Match with a previously received ETag:
curl -H 'If-None-Match: "-1:0000000000000003_000000000000001a"' \
http://localhost:4437/v1/stream/my-stream?offset=-1
If the ETag matches (no new data since last read), the server returns:
HTTP/1.1 304 Not Modified
Stream-Next-Offset: 0000000000000003_000000000000001a
Stream-Up-To-Date: true
Cache-Control: no-store
No body is sent, saving bandwidth.
If the ETag does not match (new data available), the server returns a normal 200 OK with updated data and a new ETag.
Cache-Control
The server includes Cache-Control: no-store on all responses (200, 201, 204, 304, 400, 404, 409, 413). This prevents intermediate HTTP caches (CDNs, proxies) from serving stale stream data.
SSE responses use Cache-Control: no-cache instead, which allows caching but requires revalidation.