Don’t re-download the whole file — ask the server for just the bytes you’re missing.
A normal GET hands you the whole file with 200 OK. But if the file is large and your connection drops halfway, you don’t want to start over. HTTP/1.1 byte-range requests (RFC 7233) let the client say Range: bytes=400-999, and the server replies 206 Partial Content with only those bytes plus a Content-Range header naming exactly which slice you got.
Ranges are zero-indexed and inclusive on both ends, so bytes=0-99 is the first 100 bytes. This one mechanism powers resumable downloads, video seeking, and parallel chunked downloads.
The client advertises nothing special on the first try — a plain GET. The server replies 200 OK and includes Accept-Ranges: bytes to advertise that ranges are supported. After the transfer dies at byte 400, the client re-requests starting where it left off. The server answers 206 with a Content-Range that pins the exact slice and total size.
--- attempt 2: resume after stalling at byte 400 ---
GET /movie.mp4 HTTP/1.1
Host: example.com
Range: bytes=400-999
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 400-999/1000
Content-Length: 600
<bytes 400 through 999, inclusive>
The client appends those 600 bytes to the 400 it already holds and the file is whole. Content-Range: bytes 400-999/1000 reads as “here are bytes 400 through 999 of a 1000-byte file.”
Only the requested bytes cross the wire — nothing already received is re-sent. That single property unlocks three big wins.
| Use | How range helps |
|---|---|
| Resume | Re-request from the first missing byte; the rest stays put. |
| Seek / stream | Jump to a video timestamp by fetching only that region. |
| Parallel | Split a file into chunks, fetch each with its own range, stitch. |
| Counting | Bytes returned = end - start + 1 (inclusive), so 400-999 is 600. |
bytes=0-0 returns exactly 1 byte, and bytes=0-99 returns 100, not 99.bytes=-500 is a suffix range — it means the last 500 bytes, not “everything except the last 500.” Open-ended bytes=500- means byte 500 to the end.Range entirely and send 200 OK with the whole body. Always handle both 200 and 206; never assume you got a partial response.start >= total (e.g. bytes=2000-3000 on a 1,000-byte file), you get 416 Range Not Satisfiable — no bytes, just the rejection.ETag or Last-Modified (via If-Range); if the file changed between requests you’d stitch mismatched versions. Asking for several ranges at once comes back as multipart/byteranges.You’re downloading a 1,000-byte file and the connection dies after byte 400 lands. You already hold bytes 0..399 (that’s 400 bytes). The next byte you need is byte 400, and the last byte is 999 (a 1,000-byte file is indexed 0..999).
resume range = bytes=400-999
status = 206 Partial Content
Content-Range = bytes 400-999/1000
bytes returned = 999 - 400 + 1 = 600
400 already on disk + 600 just fetched = 1,000. Done, without re-sending a single byte you already had. Now picture bytes=2000-3000 instead: 2000 is past the end, so the server replies 416 and sends no bytes at all.
How many bytes does Range: bytes=0-99 return from a large file?
Which status code means “the server gave you only part of the file”?