Download protocol boundaries

HTTP Range and Content-Range: exact bytes, 206, 416 and safe resume boundaries

A Range value describes requested bytes, not a promise of a partial response. Use the local tester to check arithmetic, then verify the actual response and representation separately.

Content updated: · Maintained by Hung Chi-Hsueh · corrections

Endpoints are inclusive; offsets start at zero

For a 1,000-byte representation, bytes=0-99 requests 100 bytes, not 99. bytes=995-1200 clips to 995-999, or five bytes. bytes=998- means the last two bytes, and bytes=-3 means 997-999. A suffix larger than the representation selects the entire representation; a zero suffix is unsatisfiable.

A set can remain satisfiable when some members are out of bounds. The tester preserves every member, including duplicates and overlaps, without silently merging or adding lengths. Multiple returned ranges normally use multipart/byteranges: each part has its own Content-Range, and boundaries and part headers make the whole body longer than the sum of payload bytes.

Bytes belong to the selected encoded representation

HTTP byte ranges use the representation's encoded byte sequence. They are not character positions, Unicode code points, or offsets in automatically decompressed text. If Content-Encoding is gzip, do not combine an encoded Range offset with the decoded text length displayed by a browser.

Resume requires the same selected representation and compatible validators. Content negotiation, encoding or the resource itself can change between requests. A saved file length alone does not establish that appending newly received bytes will produce a valid file.

206 and 416 are modeled outcomes, not server promises

The tester assumes a GET request whose ordinary preconditions would otherwise permit 200. Real servers may ignore Range, coalesce members, return only some satisfiable ranges, or reject inefficient overlapping sets. Accept-Ranges: bytes is advice, not proof that a later request will return 206. Unknown range units are unsupported by this tool; its error does not prescribe a server status.

For a handled but unsatisfiable byte-range set, the model shows 416 and Content-Range: bytes */length. This length describes the selected representation, not the size of any error body. The first version deliberately does not model Range requests for an empty representation; RFC 9110 has special zero-length suffix semantics, so an unsupported result must not be read as an invalid HTTP request.

Check Content-Range without inventing missing evidence

bytes 0-99/1000 describes 100 bytes and a known total; bytes 5-9/* describes five bytes with an unknown total. Require start ≤ end and, when known, total > end. bytes */0 is valid unsatisfied-range syntax. bytes */* is not supported syntax.

The optional body-byte comparison checks only a supplied number against an inclusive satisfied range. It never reads a real body. Leave it blank for bytes */length: a 416 error body has its own length. A valid Content-Range does not authenticate bytes or establish a response's status; its HTTP meaning depends on the response context.

If-Range mismatch means full handling, not 412

A matching strong If-Range ETag allows the chosen Range-handling model to continue. A different current tag, a weak current tag, or an unavailable tag cannot establish a strong match, so Range is ignored. The normal full representation is modeled as 200; no second 412 precondition engine is introduced.

This first version accepts only a single quoted strong If-Range ETag, not weak tags, wildcards, lists or HTTP dates. Date validators require additional strong-validator and exact-date rules. Ordinary If-Match / If-None-Match and date preconditions are covered by the separate conditional-request tool; if they would return 304, Range is not evaluated as though 200 had already passed.

Bounded local input and exact exports

The tool accepts field values, not complete header blocks or URLs. Each field is limited to 4 KiB, each integer to 30 decimal digits, the Range set to 16 members and JSON output to 64 KiB. Tabs, empty list members and controls are explicitly outside this strict input subset; these product limits are not new HTTP protocol rules.

Byte values use BigInt arithmetic and decimal-string JSON, so values above Number.MAX_SAFE_INTEGER remain exact. The graph is only a visual aid and rounds tiny ranges; the table and exported strings are authoritative. Inputs and reports stay in page / Worker memory, with no upload, persistence or URL sharing. Editing a field clears old output and exports. Review ETags and all report content before sharing.

Example
Representation: 1000 bytes
Range: bytes=995-1200, -3
Member 1: 995–999 = 5 bytes
Member 2: 997–999 = 3 bytes (overlaps member 1; not summed)

Content-Range: bytes 0-99/1000
Inclusive length: 100 bytes

Data provenance

Sources