Range

Downloading an entire resource is wasteful when only a portion is needed. The Range request header specifies which byte ranges the server returns in the response.

Usage

The Range header enables partial retrieval of a resource. A client includes this header to request specific byte ranges instead of downloading the entire resource. This is essential for resuming interrupted downloads, Streaming media with seek support, and loading large files in parallel segments.

Before sending a range request, a client verifies server support by checking the Accept-Ranges header in a prior response. A value of bytes confirms the server handles byte-range requests. A value of none indicates the server does not accept range requests.

When a range request succeeds, the server responds with 206 Partial Content and includes the Content-Range header indicating the byte positions and total resource size. Multiple ranges in a single request produce a multipart response with each part carrying its own Content-Range and Content-Type headers.

If the requested range falls outside the resource boundaries, the server returns 416 Range Not Satisfiable. In some cases, the server ignores the Range header entirely and delivers the full resource with a 200 status.

Values

unit

The unit specifies the measurement for ranges. bytes is the standard unit defined in the HTTP specification. Custom range units are permitted but rarely used.

range-start and range-end

The range-start value is the zero-based byte offset where the range begins (required). The range-end value is the zero-based byte offset where the range ends (optional). Omitting range-end requests all bytes from range-start to the end of the resource.

suffix-length

The suffix-length form requests the last N bytes of a resource. The format -N retrieves the final N bytes without needing to know the total resource size.

Example

A client requests the first 1,000 bytes of a large image file. The server responds with 206 Partial Content and specifies the byte range and total file size in the Content-Range header.

GET /photo.jpg HTTP/1.1
Host: cdn.example.re
Range: bytes=0-999
HTTP/1.1 206 Partial Content
Content-Type: image/jpeg
Content-Length: 1000
Content-Range: bytes 0-999/250000

A client resumes a download starting at byte 50,000. Omitting the end value requests everything from the given offset to the end of the resource.

Range: bytes=50000-

A client requests the last 500 bytes of a file. The suffix form is useful when the total file size is unknown to the client.

Range: bytes=-500

A client requests two separate byte ranges in a single request. The server returns a multipart response with each segment as a separate body part.

Range: bytes=0-499, 1000-1499

Servers are free to ignore the header

Range handling is defined for GET alone, and a server ignoring the header entirely remains conformant, answering with a full 200. Clients depending on a 206, or on a 416 for an unsatisfiable range, break against perfectly valid servers.

Preconditions run first. A conditional request resolving to 304 never reaches range evaluation, and If-Range exists to collapse the two-step dance into one request: parts when the representation is unchanged, the full body otherwise, compared by exact match rather than date arithmetic.

Ranges apply to the encoded bytes. A response compressed with gzip or Brotli is sliced after compression, so byte positions name compressed offsets, and nginx sidesteps the confusion by disabling ranges wherever on-the-fly compression runs.

Multiple ranges as an attack surface

Overlapping range lists once crashed servers. A single request naming hundreds of overlapping ranges cost the attacker a short header and the server memory and CPU per part, taking down unpatched Apache installations in 2011 (CVE-2011-3192).

The permanent defense became configuration. Apache caps multipart behavior through three directives, each falling back to a full 200 when exceeded:

Directive Default
MaxRanges 200
MaxRangeOverlaps 20
MaxRangeReversals 20

nginx bounds the same surface with max_ranges, unlimited by default, where max_ranges 0 disables byte ranges entirely and max_ranges 1 rules out multipart responses. The specification itself blesses rejection, permitting servers to refuse overlapping, descending, or excessive range lists outright.

Cloudflare Workers remove the question from application code: the platform strips Range before invoking a Worker, caches the full response the Worker returns, and slices the requested bytes at the edge, answering later range requests from cache without the Worker running.

See also

Last updated: August 17, 2026