Advertise byte ranges on downloads, and record the live checks

Stalwart honors a single byte range on its download endpoint but sends
no Accept-Ranges, and Chrome's PDF viewer only reads a file in pieces
when the first response says it can. The proxy now says so itself.

Checked live on 0.16.22: ContactCard/changes reports creates, updates
and destroys exactly, which the contacts store's sync relies on, and a
range the server cannot serve gets the whole file with 200, never 416.
The mock now answers ranges the same way and sends no Accept-Ranges.
This commit is contained in:
2026-09-16 12:10:20 -07:00
parent ebf678be73
commit 8a08c3d6db
4 changed files with 24 additions and 9 deletions
+10 -7
View File
@@ -139,20 +139,23 @@ export const server = createServer(async (req, res) => {
const b = blobs.get(blobId ?? "");
if (!b) { res.writeHead(404); return res.end(); }
const type = url.searchParams.get("accept") ?? b.type;
// One byte range, the way a PDF viewer or a video element asks for one.
/*
* One byte range, answered as Stalwart answers it (0.16.22, checked live
* on 2026-09-16): a 206 for a single range it can serve, and the whole
* file with a 200 for anything else -- several ranges, or one past the
* end. It never sends Accept-Ranges.
*/
const m = /^bytes=(\d*)-(\d*)$/.exec(String(req.headers.range ?? ""));
if (m && (m[1] || m[2])) {
const size = b.data.length;
const start = m[1] ? Number(m[1]) : Math.max(0, size - Number(m[2]));
const end = m[1] && m[2] ? Math.min(Number(m[2]), size - 1) : size - 1;
if (start >= size || start > end) {
res.writeHead(416, { "content-range": `bytes */${size}` });
return res.end();
if (start < size && start <= end) {
res.writeHead(206, { "content-type": type, "content-length": end - start + 1, "content-range": `bytes ${start}-${end}/${size}` });
return res.end(b.data.subarray(start, end + 1));
}
res.writeHead(206, { "content-type": type, "content-length": end - start + 1, "content-range": `bytes ${start}-${end}/${size}`, "accept-ranges": "bytes" });
return res.end(b.data.subarray(start, end + 1));
}
res.writeHead(200, { "content-type": type, "content-length": b.data.length, "accept-ranges": "bytes" });
res.writeHead(200, { "content-type": type, "content-length": b.data.length });
return res.end(b.data);
}
/*