Content-Range header explained (bytes start-end/total)
Content-Range is the label on a parcel that holds only part of a file: which bytes are inside, and how big the whole thing is.
The format
Content-Range: bytes <first>-<last>/<complete-length>
Content-Range: bytes */<complete-length> (in a 416 reply)
Content-Range: bytes <first>-<last>/* (length unknown)
Worked examples for a 5000-byte file
| Request header | Content-Range in the reply | Content-Length |
|---|---|---|
Range: bytes=0-999 | bytes 0-999/5000 | 1000 |
Range: bytes=1000- (from 1000 to the end) | bytes 1000-4999/5000 | 4000 |
Range: bytes=-500 (the last 500 bytes) | bytes 4500-4999/5000 | 500 |
Range: bytes=4000-9999 (end past the file) | bytes 4000-4999/5000 | 1000 |
Range: bytes=6000- (start past the file) | 416 with bytes */5000 | — |
An end beyond the file is not an error: the server just stops at the last byte. A start at or beyond the size is what triggers 416.
The off-by-one trap
The last byte of a 5000-byte file is number 4999, not 5000. Code that builds the header as bytes {start}-{start+chunk}/{size} sends one byte too many in every chunk. Use start + chunk − 1, and never let the end go past size − 1. A mismatch between Content-Range and Content-Length makes clients and proxies reject or truncate the reply.
Several ranges at once
A client may ask for Range: bytes=0-99,500-599. A server that agrees replies with 206 and Content-Type: multipart/byteranges; boundary=…. There is then no Content-Range on the outer response; each part carries its own Content-Range line. Many servers simply return the whole file or only the first range instead, which is allowed.
Upload APIs use it too
Some resumable upload APIs (Google’s resumable uploads, for example) ask the client to send Content-Range on each chunk it uploads, using the same bytes first-last/total format, and reply with how far they got. The arithmetic and the off-by-one rule are identical.
Quick sanity check with curl
curl -s -o /dev/null -D - -H "Range: bytes=0-99" https://example.com/file.bin
# look for: HTTP/2 206, content-range: bytes 0-99/<size>, content-length: 100
Related
HTTP 206 Partial Content · 416 Range Not Satisfiable · Accept-Ranges header · Range request returns 200 · Number base converter
Questions
What does Content-Range: bytes 0-1023/5000 mean?
The body holds bytes 0 to 1023, inclusive, of a resource that is 5000 bytes long. That is 1024 bytes.
Is the end of Content-Range inclusive?
Yes. Both numbers count from zero and the last one is included, so the length of the body is end minus start plus one.
What does bytes */5000 mean?
It is sent with 416 Range Not Satisfiable to tell the client the real size, 5000 bytes, because the requested range could not be served.
What is the difference between Content-Range and Content-Length?
Content-Length is the size of this body. Content-Range says which slice of the whole resource the body is, and how big the whole resource is.
Can Content-Range have an unknown total?
Yes. bytes 0-1023/* means the server sent those bytes but does not know or will not say the full length.
Published .