fix(api): bytes head entity headers - #5551
Conversation
| @@ -794,6 +794,10 @@ func (s *Service) downloadHandler(logger log.Logger, w http.ResponseWriter, r *h | |||
| w.Header().Add(AccessControlExposeHeaders, ContentDispositionHeader) | |||
|
|
|||
| if headersOnly { | |||
There was a problem hiding this comment.
Early-returning 200 OK here bypasses Go's http.ServeContent, which causes HEAD requests containing a Range header (e.g. HEAD /bytes/ with Range: bytes=0-99) to return 200 OK with the total content length and no Content-Range header.
In contrast, a GET request with Range: bytes=0-99 returns 206 Partial Content with Content-Range: bytes 0-99/ and Content-Length: 100.
According to RFC 9110 Section 9.3.2, HEAD requests must return identical entity headers to GET. Conditional HEAD requests (If-None-Match, If-Modified-Since) also fail to return 304 Not Modified for the same reason.
There was a problem hiding this comment.
Could we add a test case to TestBytesHead for HEAD requests with a Range header (e.g. Range: bytes=0-10)?
Checklist
Description
HEAD /bytes/<ref>did not return usable entity headers. Three separate defects:Content-Length. The redundancy level is packed into the most significant byte of the root chunk span (redundancy.EncodeLevel), so reading the span asint64yielded a negative number for any upload with redundancy level >= 1 spanning more than one chunk. Bee sentContent-Length: -9151314442816647872; curl rejects that and aborts header parsing (exit 8), which is why the response looked like it had no headers at all.Accept-Rangeswas never sent on HEAD, for/bytesor/bzz, even though both serve ranged GETs.bytesHeadHandlernow delegates todownloadHandlerwithheadersOnly, the same pathbzzHeadHandleralready uses. HEAD and GET therefore share one implementation and the length comes from the joiner, which strips the encoded redundancy level and splits an encrypted reference into address and key.Accept-Rangesis set on that shared header-only branch, so both endpoints are covered.Behavior change worth noting: HEAD now reports the same status as GET for references that cannot be served, where it previously always returned 404. Pinned by
TestBytesHeadErrorsMatchGet.Open API Spec Version Changes (if applicable)
Documented
Accept-Ranges,ETagand the500response onHEAD /bytes/{address}andHEAD /bzz/{address}.info.versionleft at 8.1.0. The added response headers are additive, but the HEAD status change above is arguably breaking — happy to bump if you would rather record it.Motivation and Context (Optional)
Size-then-range is how generic HTTP clients read a large remote object: HEAD for the length, then ranged GETs. Bee's ranged GET support already works, so the missing HEAD headers were the only thing blocking that whole class of client (
nbdkit,rclone,aria2, anything on libcurl's remote-file handling).Related Issue (Optional)
Closes #5545
Screenshots (if appropriate):
AI Disclosure