HTTP range requests explained
A range request is how you download the last megabyte of a file without fetching the first ninety nine, how a paused download resumes from where it stopped, and how a video seeks to the middle without buffering from the start. The whole mechanism rests on two headers and one status code.
The server advertises support
A server signals that it accepts range requests with a response header on the full resource:
Accept-Ranges: bytes
The value bytes means the client may request arbitrary byte ranges. A value of none, or the header's absence, means the client must take the whole thing. Static file servers and object stores advertise bytes. A dynamically generated response usually does not, because there is no stable byte layout to index into.
The client asks for a slice
The client requests a portion with the Range header, counting bytes from zero:
Range: bytes=0-1023
That asks for the first 1024 bytes. The forms you will see:
| Range header | Meaning |
|---|---|
bytes=0-1023 | the first 1024 bytes |
bytes=1024- | from byte 1024 to the end |
bytes=-500 | the last 500 bytes |
bytes=0-0,-1 | the first and last byte, a multipart request |
The server replies with 206
If the server honors the range, it responds with 206 Partial Content, not 200 OK, and includes a Content-Range header stating exactly which bytes it sent and the total size:
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/146800
Content-Length: 1024
Content-Length here is the size of the slice, not the whole file. The total after the slash is the full resource size, or * if the server does not know it. A client reading 206 knows it received a fragment and can place it correctly in the file it is assembling.
Resumable downloads
This is the feature most people have relied on without knowing the mechanism. A download client records how many bytes it has saved. If the connection drops at byte 5,000,000, it reconnects and sends Range: bytes=5000000-. The server returns 206 with the rest of the file, and the client appends it to what it already has. No bytes are refetched. A download manager that resumes cleanly is doing exactly this, and a server that lacks Accept-Ranges: bytes forces a restart from zero on every interruption.
Media seeking
When you drag a video's scrubber to the halfway point, the player estimates the byte offset for that timestamp and sends a range request for bytes starting there. The server returns 206 from that offset, and playback begins without downloading the earlier portion. This is why seeking works instantly on a well configured video host and stalls on one that serves the file without range support, where the whole thing must stream from the beginning.
Multipart ranges and errors
A client can request several discontinuous ranges in one request. The server then returns 206 with a multipart/byteranges body, each part carrying its own Content-Range and separated by a boundary string. This is less common and more complex to parse, so many clients stick to single ranges.
Two error cases matter. If the requested range lies entirely beyond the file, for example byte 500000 of a 1000 byte file, the server returns 416 Range Not Satisfiable with a Content-Range: bytes */1000 telling the client the real size. And if the server ignores the Range header and returns 200 with the full body, the client must accept the whole response rather than assume a partial one.
To check whether a server sends Accept-Ranges: bytes and responds with 206, the HTTP Header Checker shows you the response headers for any URL.