DownloadArtifact copies the PDS's response headers after calling WriteHeader, which freezes the header map, so none of them reach the client and net/http sniffs a Content-Type from the first bytes instead: a JSON artifact is served as text/plain; charset=utf-8, an APK as application/zip.
This sets the headers before the status. An artifact is served as application/octet-stream, as an attachment under its own name, with nosniff, a sandboxing Content-Security-Policy (the one the PDS itself sends for blobs) and the PDS's Content-Length. The PDS's other headers (rate limits and so on) are no longer passed on.
The one exception is an artifact recorded as application/json, which is served as application/json. JSON is inert on the appview's origin: with nosniff a browser never renders it as a page or runs it as a script. And some clients need it served as JSON. An atproto OAuth client metadata document, for one, is only accepted by authorization servers as application/json (the spec requires status 200 and that Content-Type), so with this a CLI can attach its client document to each release and use the release's download URL as its client_id.
#2237 (https://tangled.org/tangled.org/core/pulls/2237) fixes the same ordering bug and serves every artifact as application/octet-stream. This takes the same approach, and the same reasoning for not trusting recorded types or file names, and adds only the application/json exception.
Tests: setArtifactHeaders for JSON (with and without parameters), a zip-recorded APK, SVG, HTML, a */* wildcard and no type at all; awkward file names; and serveArtifact through an httptest.ResponseRecorder, which, like a real response, keeps the headers as they were at WriteHeader. That test fails on the current code with Content-Type = "".