HTTP Range Requests
Range requests allow a client to request a specific portion of a resource rather than the entire representation. A video player seeking to a timestamp, a download manager resuming an interrupted transfer, or a PDF viewer loading a single page all rely on range requests to fetch only the bytes they need.
Range requests are part of HTTP semantics. The mechanism works through the Range request header, the Content-Range response header, and the 206 status code.
Usage
Range requests are not universally supported. A
server advertises support by including the
Accept-Ranges response header with
a value indicating the supported range unit.
Currently bytes is the only range unit registered
with IANA and in widespread use.
Accept-Ranges: bytes
A value of none explicitly declares range
requests unsupported. When
Accept-Ranges is absent, the
client has no guarantee either way.
When a server supports range requests and receives a valid Range header, the response uses the 206 status code with the requested portion of the resource. If the requested range falls outside the bounds of the resource, the server responds with 416. A server is also free to ignore the Range header entirely and return 200 with the full resource.
Checking for support
Before requesting partial content, a client sends an HTTP HEAD request to check whether the server supports range requests. The Accept-Ranges header in the response confirms support, and Content-Length reveals the total size of the resource.
Request
HEAD /large-image.jpg HTTP/1.1
Host: www.example.re
Response
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 25000
Accept-Ranges: bytes
The server accepts byte range requests and the total file size is 25,000 bytes.
Single range requests
A single range request retrieves one contiguous byte sequence. The Range header specifies the start and end byte positions, both inclusive.
Request
GET /large-image.jpg HTTP/1.1
Host: www.example.re
Range: bytes=0-999
Response
HTTP/1.1 206 Partial Content
Content-Type: image/jpeg
Content-Length: 1000
Content-Range: bytes 0-999/25000
(1000 bytes of image data)
Content-Length in range responses
The Content-Length header in a 206 response reflects the number of bytes in the message body (the partial content), not the total size of the resource. The total size appears after the slash in the Content-Range header.
The Range header supports three formats:
bytes=0-999retrieves bytes 0 through 999 (the first 1,000 bytes)bytes=5000-retrieves from byte 5,000 to the end of the resourcebytes=-500retrieves the last 500 bytes
Multipart range requests
Multiple byte ranges are requested in a single Range header by separating ranges with commas.
Range: bytes=0-999, 2000-2499, 5000-5999
The server responds with
Content-Type: multipart/byteranges and a boundary
string. Each part in the message body includes its
own Content-Type and
Content-Range headers.
Request
GET /large-image.jpg HTTP/1.1
Host: www.example.re
Range: bytes=0-999, 2000-2499, 5000-5999
Response
HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=range_divider
Content-Length: 2712
--range_divider
Content-Type: image/jpeg
Content-Range: bytes 0-999/25000
(1000 bytes of image data)
--range_divider
Content-Type: image/jpeg
Content-Range: bytes 2000-2499/25000
(500 bytes of image data)
--range_divider
Content-Type: image/jpeg
Content-Range: bytes 5000-5999/25000
(1000 bytes of image data)
--range_divider--
The top-level Content-Type is
multipart/byteranges with the boundary parameter.
Each body part starts with a boundary delimiter and
contains its own headers describing the specific
byte range.
Merged ranges
A server is free to merge overlapping or adjacent
ranges. Two ranges like bytes=0-500, 400-999
are coalesced into a single bytes 0-999 part.
The response is valid as long as all requested
bytes are covered, even if the number of parts
differs from the number of ranges requested.
Unsatisfiable ranges
When the requested range falls entirely outside the resource boundaries, the server returns 416 Range Not Satisfiable. The response includes a Content-Range header with the total size of the resource so the client knows the valid range.
HTTP/1.1 416 Range Not Satisfiable
Content-Range: bytes */25000
A range like bytes=30000-40000 on a 25,000-byte
resource triggers this response.
Conditional range requests
Resuming a download introduces a risk: the resource on the server changed since the last partial transfer. The If-Range header addresses this by combining a conditional request with a range request in a single round-trip.
If-Range accepts either an ETag or a Last-Modified date as the validator.
Using an ETag
GET /large-image.jpg HTTP/1.1
Host: www.example.re
Range: bytes=1000-1999
If-Range: "abc123"
Using a Last-Modified date
GET /large-image.jpg HTTP/1.1
Host: www.example.re
Range: bytes=1000-1999
If-Range: Sun, 01 Jan 2023 12:00:00 GMT
If the validator matches, the server returns 206 with the requested range. If the resource changed (the validator no longer matches), the server ignores the Range header and returns 200 with the full resource. This avoids the extra round-trip separate If-Match and Range headers require.
Resumable downloads
Download managers and HTTP clients store the ETag or Last-Modified value from the initial response. On retry, the client sends If-Range with the stored validator and a Range starting from the last received byte. This pattern handles both the resume case (resource unchanged, 206) and the restart case (resource changed, 200) without needing an extra request.
Takeaway
Range requests enable partial content retrieval
through the Range request header and the
206 response status. A single request retrieves
one byte range. Multiple ranges arrive in a
multipart/byteranges response. The
If-Range header combines conditional
validation with range selection, making resumable
downloads safe against mid-transfer resource
changes.
See also
- RFC 9110: Range Requests
- Conditional-Requests
- Caching
- Accept-Ranges
- Range
- Content-Range
- If-Range
- 206
- 416
- 200
- HTTP headers