Cos'e HTTP 416 Range Not Satisfiable
Il codice HTTP 416 Range Not Satisfiable (in passato "Requested Range Not Satisfiable") indica che il server non puo soddisfare l'header Range della richiesta perché i valori specificati sono fuori dai limiti della risorsa. E lo specchio del 206 Partial Content: se il 206 e successo parziale, il 416 e fallimento del range.
Cause tipiche
- Range che chiede byte oltre la dimensione del file (es.
bytes=99999-su file da 1000 byte). - Range invertito (es.
bytes=500-100). - Multipli range malformati o sovrapposti.
- Risorsa modificata dopo If-Range: il range originario non e più valido.
- Server che non supporta range su quel tipo di risorsa.
Esempio classico
GET /video.mp4 HTTP/1.1
Range: bytes=99999999-
HTTP/1.1 416 Range Not Satisfiable
Content-Range: bytes */12345678
Content-Length: 0
L'header Content-Range: bytes */dimensione e obbligatorio nelle risposte 416 e indica al client la dimensione totale della risorsa, così puo correggere la sua richiesta.
Sintassi corretta dei Range
Range: bytes=0-499 # primi 500 byte
Range: bytes=500-999 # byte 500-999
Range: bytes=-500 # ultimi 500 byte
Range: bytes=9500- # dal byte 9500 alla fine
Range: bytes=0-499,1000-1499 # multi-range
Se il client invia formati invalidi o byte oltre il limite, il server risponde 416.
Range invertito o overflow
Server stricti rifiutano:
Range: bytes=500-100(start > end).Range: bytes=abc-xyz(non numerici).Range: bytes=0-0-100(sintassi rotta).
Scenario streaming video
Un player HTML5 che cerca di andare oltre la durata del video potrebbe generare un 416. Tipicamente i player gestiscono questo eseguendo prima un'HEAD per conoscere la dimensione, poi calcolando range validi. Quando capita un 416 in produzione su streaming, spesso indica:
- File parzialmente uploadato (size reported incorrect).
- Trascoding in corso che cambia dimensione del file.
- CDN cache stantio con vecchia size.
Implementazione corretta server-side
def serve_range(filename, range_header):
file_size = os.path.getsize(filename)
match = re.match(r'bytes=(\d*)-(\d*)', range_header)
if not match:
return response_416(file_size)
start = int(match.group(1)) if match.group(1) else 0
end = int(match.group(2)) if match.group(2) else file_size - 1
if start >= file_size or end >= file_size or start > end:
return response_416(file_size)
return response_206(filename, start, end, file_size)
def response_416(file_size):
return Response(
status=416,
headers={'Content-Range': f'bytes */{file_size}'}
)
If-Range gestione
Il client puo combinare Range con If-Range: "scaricami questo range, ma solo se la risorsa non e cambiata":
GET /file.zip HTTP/1.1
Range: bytes=500000-
If-Range: "etag-v1"
Comportamenti:
- ETag corrente == "etag-v1": server risponde 206 con il range.
- ETag diverso: server risponde 200 con intero file (NON 416, perché il client e disposto a riprendere da capo).
Cache CDN e 416
I CDN che cacheano range request devono evitare di restituire 416 stantii. Se la origin aggiorna il file e la sua dimensione cambia, le cache devono invalidare i range vecchi. Cloudflare e Fastly gestiscono questo via ETag + Vary.
Differenza con 200 Full Content
Un server che non supporta affatto range request risponde sempre con 200 e l'intero file, ignorando l'header Range. Risponde con 416 solo quando supporta range ma quello specifico non e soddisfacibile. Il client distingue questi casi con Accept-Ranges: bytes nella risposta.
Diagnostica
curl -H "Range: bytes=1000000000-" -I https://example.com/file.mp4
HTTP/1.1 416 Range Not Satisfiable
Content-Range: bytes */5242880
Verifica nella risposta:
- Header Content-Range presente con sintassi
bytes */totale. - Content-Length zero o body vuoto.
- Connection puo essere closed dal server.
Errori comuni client
Download manager mal scritti che continuano a chiedere range oltre EOF generano loop infiniti di 416. Player video che usano integer overflow (es. seek a Number.MAX_SAFE_INTEGER) mostrano lo stesso problema. Validare sempre i range lato client prima di inviarli.
Sicurezza
Server vulnerabili al "range header DoS" (CVE-2011-3192, "Apache killer") potevano essere mandati in OOM con multi-range overlap. Le versioni moderne di Apache, Nginx limitano i range multipli a un numero ragionevole (es. 10) per prevenirlo.
Range syntax dettagli
La sintassi formale del Range header (RFC 7233): bytes=range-set dove range-set e una lista di range separati da virgola. Esempi validi: bytes=0-499, bytes=-500 (suffix range, ultimi 500 byte), bytes=500- (open-ended), bytes=0-0,-1 (primo e ultimo byte). Combinazioni invalide generano 416.
416 con file dinamici
Per risorse generate dinamicamente (es. PDF report con timestamp corrente), la dimensione non e nota a priori. Server puo: (a) usare chunked encoding senza range, (b) generare prima il file completo in cache temp, poi servirlo con range. La strategia (b) supporta 416 quando il range richiesto e fuori limiti.
Caching multi-tier
Quando origin emette nuova versione del file (size cambia), CDN deve invalidare i range caching. Strategia migliore: ETag-based caching, dove CDN valida con origin (304 vs 200) e invalida le cache se ETag cambia. Senza questo, rischi 416 servito da cache stale anche se origin avrebbe risposto 206.
Player video gestione 416
HTML5 video tag gestisce 416 chiudendo lo stream. Player avanzati (HLS.js, dash.js) hanno logica di retry: se 416, riprovano con HEAD per leggere current size, poi rifanno range nei limiti. Per server che spesso restituiscono 416, considerare error logging e capacity tuning.
Apache mod_security
Il modulo WAF mod_security puo bloccare richieste con range "sospetti" (es. multi-range con molti pezzi piccoli, potenziale DoS). Configurazione: SecRule REQUEST_HEADERS:Range "@rx ^bytes=.{500,}$" "deny,id:1001". Bilanciare sicurezza vs legittimo uso da player.
Range request gone wrong
Bug famoso del 2011: CVE-2011-3192 ("Apache Killer") permetteva di mandare in DoS Apache con multiple range overlapping. Fix: Apache limita ora il numero di range a 200 e poi nega. Esempio attack: Range: bytes=0-,5-,1-,3-,2-,... per centinaia di range.
Player video robust handling
HLS.js, Video.js, dash.js implementano retry logic per 416: dopo errore, fanno HEAD per verificare size attuale, poi ritentano con range valido. Per server che spesso restituiscono 416, considerare logging tabellare per individuare pattern (e.g., file con size in flux).
Suffix range edge case
Range bytes=-500 chiede gli ultimi 500 byte. Se il file e più piccolo di 500 byte, il server deve servire l'intero file con 206 (non 416). Bug comune: server emette 416 perché fa calcolo end > file_size senza handling del suffix.
Performance considerations
Range request su file molto grandi (multi-GB video) richiedono fseek efficiente. Filesystem moderni (ext4, xfs, NTFS, APFS) supportano sparse seek nativo. Storage object (S3) supportano range request via API HTTP, performant.
Hai bisogno di aiuto?
Se il tuo sito mostra errori HTTP, il team di G Tech Group puo aiutarti. Contattaci tramite il modulo di contatto.