Summary
Add HTTP byte-range support to locally served cached artifacts so clients can resume interrupted downloads without transferring the entire file again. This is particularly useful for large OCI blobs, Python wheels and generic release assets.
Affected code
internal/handler/handler.go: serveArtifact and its callers
internal/handler/generic.go: release-asset response handling
internal/handler/container.go: cached OCI blob response handling
- Storage reader interfaces, if efficient seeking or ranged reads require backend support
Current behavior
The shared artifact-serving path receives the HTTP method rather than the full request. It does not inspect Range or If-Range, does not advertise byte-range support and streams the complete artifact with 200 OK.
A client attempting to resume an interrupted download therefore receives the whole representation again. Depending on the client, it must restart the download or report that resuming is unsupported.
Ignoring range requests is permitted by HTTP, so this is an enhancement rather than a protocol-compliance bug. It nevertheless imposes avoidable bandwidth and I/O costs on users downloading large cached files.
Expected behavior
For cached artifacts that the proxy can serve with reliable size and range access:
- Advertise
Accept-Ranges: bytes.
- Honor supported byte ranges with
206 Partial Content, the correct Content-Range and the length of the selected bytes.
- Support bounded, open-ended and suffix ranges.
- Return
416 Range Not Satisfiable with Content-Range: bytes */<size> for a valid but unsatisfiable range.
- Respect
If-Range: serve the full representation when the supplied validator does not match.
- Preserve ordinary full-download and
HEAD behavior, including sending no body for HEAD.
Suggested implementation
Pass the request, or its relevant headers, into the artifact-serving layer. Prefer standard HTTP serving helpers where the storage reader supports their seeking requirements.
For non-seekable object-storage readers, consider backend ranged reads. Reading and discarding a large prefix can produce a correct response but does not provide the same storage-I/O savings. Avoid buffering whole large artifacts in memory merely to support seeking.
Define multi-range handling explicitly: either implement multipart responses or safely ignore unsupported multi-range requests and serve the complete representation. Do not silently interpret a multi-range request as a different single range. Only advertise range support on paths that actually implement it; direct-storage redirects remain subject to the destination's capabilities.
Acceptance tests
- Request a bounded range and verify status, headers and exact response bytes.
- Exercise open-ended and suffix ranges, including a suffix larger than the artifact.
- Request a range starting at or beyond the end of the artifact and verify
416.
- Verify matching and mismatching
If-Range validators.
- Verify no-range requests still return the full artifact and
HEAD never sends a body.
- Cover the chosen malformed-range and multi-range behavior.
- Cover supported storage reader types and ensure cached range requests do not re-download the artifact from upstream.
Summary
Add HTTP byte-range support to locally served cached artifacts so clients can resume interrupted downloads without transferring the entire file again. This is particularly useful for large OCI blobs, Python wheels and generic release assets.
Affected code
internal/handler/handler.go:serveArtifactand its callersinternal/handler/generic.go: release-asset response handlinginternal/handler/container.go: cached OCI blob response handlingCurrent behavior
The shared artifact-serving path receives the HTTP method rather than the full request. It does not inspect
RangeorIf-Range, does not advertise byte-range support and streams the complete artifact with200 OK.A client attempting to resume an interrupted download therefore receives the whole representation again. Depending on the client, it must restart the download or report that resuming is unsupported.
Ignoring range requests is permitted by HTTP, so this is an enhancement rather than a protocol-compliance bug. It nevertheless imposes avoidable bandwidth and I/O costs on users downloading large cached files.
Expected behavior
For cached artifacts that the proxy can serve with reliable size and range access:
Accept-Ranges: bytes.206 Partial Content, the correctContent-Rangeand the length of the selected bytes.416 Range Not SatisfiablewithContent-Range: bytes */<size>for a valid but unsatisfiable range.If-Range: serve the full representation when the supplied validator does not match.HEADbehavior, including sending no body forHEAD.Suggested implementation
Pass the request, or its relevant headers, into the artifact-serving layer. Prefer standard HTTP serving helpers where the storage reader supports their seeking requirements.
For non-seekable object-storage readers, consider backend ranged reads. Reading and discarding a large prefix can produce a correct response but does not provide the same storage-I/O savings. Avoid buffering whole large artifacts in memory merely to support seeking.
Define multi-range handling explicitly: either implement multipart responses or safely ignore unsupported multi-range requests and serve the complete representation. Do not silently interpret a multi-range request as a different single range. Only advertise range support on paths that actually implement it; direct-storage redirects remain subject to the destination's capabilities.
Acceptance tests
416.If-Rangevalidators.HEADnever sends a body.