toolhq.io

All posts
5 min readby Jameel Haider

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 headerMeaning
bytes=0-1023the first 1024 bytes
bytes=1024-from byte 1024 to the end
bytes=-500the last 500 bytes
bytes=0-0,-1the 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.