Resume an interrupted download by requesting only the bytes after what you already have, using the `Range` header and 206 Partial Content.
Resume an interrupted download by requesting only the bytes after what you already have, using the `Range` header and 206 Partial Content.
# resume a partially downloaded file automatically:
curl -C - -O https://example.com/big.iso
# or request an explicit byte range:
curl -r 1048576- -o part.bin https://example.com/big.iso
# -> 206 Partial Content// fetch bytes starting at an offset (e.g. after 1 MiB already saved)
const res = await fetch('https://example.com/big.iso', {
headers: { Range: 'bytes=1048576-' }
});
console.log(res.status); // 206 Partial Content
console.log(res.headers.get('Content-Range')); // bytes 1048576-.../<total>import os, requests
path, url = 'big.iso', 'https://example.com/big.iso'
have = os.path.getsize(path) if os.path.exists(path) else 0
headers = {'Range': f'bytes={have}-'}
with requests.get(url, headers=headers, stream=True) as r:
r.raise_for_status() # 206 if resumed, 200 if server ignores Range
with open(path, 'ab') as f: # append mode
for chunk in r.iter_content(8192):
f.write(chunk)curl's `-C -` inspects the local file size and computes the resume offset automatically. To specify it yourself use `-r start-end` (e.g. `-r 1048576-`) or `Range: bytes=<start>-`. If the server supports partial requests it returns 206 with a `Content-Range: bytes start-end/total` header.
Check whether the server supports ranges via `Accept-Ranges: bytes` in the response. If it does not, it ignores Range and sends 200 with the whole file, so your client must branch: on a 200, save from scratch (overwrite, not append).
If the source changes mid-resume, the pieces won't line up and the file corrupts. Prevent this with `If-Range: "<etag>"`: unchanged resources continue with 206, changed ones are re-sent in full with 200, preserving integrity. A range beyond the file size yields 416 Range Not Satisfiable.