download.kiwix.org routes the large Wikimedia-family ZIMs (Wikipedia,
Wikiversity, Wikibooks — including the flagship full Wikipedia) to
dumps.wikimedia.org, which enforces a User-Agent policy and returns HTTP
403 for requests with a missing or generic (axios/x) User-Agent. Because
doResumableDownload sent no User-Agent, every Wikimedia-hosted ZIM failed
to download while Kiwix-mirror-hosted ZIMs succeeded — so a curated set or
Easy Setup run would silently stall on exactly the highest-value content.
Add a descriptive User-Agent to the HEAD and GET requests. Verified
against the live mirror: default/empty UA -> 403, ProjectNOMAD UA -> 200/206.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
download.kiwix.org (and some of its mirrors) don't always set a
Content-Type header on .zim responses. The MIME validator was reading
`headers['content-type'] || ''`, then running each allowlist entry
through `''.includes(...)` which is always false, so every download
from those hosts was rejected with `MIME type is not allowed`.
RFC 7231 §3.1.1.5 says missing Content-Type may be treated as
application/octet-stream by the recipient, and that's already in every
binary-content allowlist we use (ZIM, PMTILES, base assets). Default
the missing case to that and the validator does the right thing.
Strict callers that don't list octet-stream still reject as before.
Downloads are now written to `filepath + '.tmp'` and atomically renamed
to the final path only on successful completion. Kiwix globs for `*.zim`
and ZimService filters `.endsWith('.zim')`, so `.tmp` files are invisible
to both during download. The same staging applies to `.pmtiles` map files.
Ref #372
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three bugs caused downloads to hang, disappear, or leave stuck spinners:
1. Wikipedia downloads that failed never updated the DB status from 'downloading',
leaving the spinner stuck forever. Now the worker's failed handler marks them as failed.
2. No stall detection on streaming downloads - if data stopped flowing mid-download,
the job hung indefinitely. Added a 5-minute stall timer that triggers retry.
3. Failed jobs were invisible to users since only waiting/active/delayed states were
queried. Now failed jobs appear with error indicators in the download list.
Closes#364, closes#216
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>