HTTP 417 Expectation Failed

Cos'e HTTP 417 Expectation Failed

Il codice HTTP 417 Expectation Failed e emesso dal server quando non puo soddisfare l'aspettativa espressa dal client tramite l'header Expect:. Nella pratica, l'aspettativa quasi sempre usata e Expect: 100-continue: il client chiede al server di confermare che e disposto ad accettare il body prima di inviarlo.

Il flusso Expect: 100-continue

Senza Expect: 100-continue, ogni POST/PUT invia immediatamente headers + body. Se il server poi rifiuta (autenticazione, payload troppo grande, ecc), il body e stato trasmesso inutilmente. Con Expect:

  1. Client invia headers con Expect: 100-continue ma NON il body.
  2. Server valuta headers e decide:
    • Accetta: risponde HTTP/1.1 100 Continue. Client invia il body.
    • Rifiuta: risponde direttamente con 4xx (es. 401, 413, 417).
  3. Dopo aver ricevuto il body, il server invia la risposta finale.

Esempio pratico

PUT /large-upload.bin HTTP/1.1
Host: api.example.com
Content-Length: 500000000
Authorization: Bearer xyz
Expect: 100-continue

# Server valuta headers...

HTTP/1.1 100 Continue

# Client invia il body 500MB

HTTP/1.1 201 Created

Quando si emette 417

Il server emette 417 quando:

  • L'aspettativa Expect e diversa da 100-continue e il server non la supporta.
  • Il server non implementa affatto il meccanismo Expect (rara).
  • Estensioni custom dell'header Expect non riconosciute.

Tecnicamente, se Expect contiene solo 100-continue e il server vuole rifiutare, dovrebbe usare il codice di errore appropriato (es. 413 per body troppo grande), non 417. Il 417 e per aspettative semanticamente non comprensibili.

Esempio

POST /api/resource HTTP/1.1
Expect: payment-required, 100-continue

HTTP/1.1 417 Expectation Failed
Content-Type: text/plain

This server does not understand the "payment-required" expectation.

Vantaggi del 100-continue

  • Risparmio banda: body grandi non vengono inviati se il server rifiuterebbe.
  • Failure fast: errori di auth/permessi rilevati prima del trasferimento.
  • UX migliore: client puo cancellare l'upload precocemente.
  • Risparmio server: meno I/O su body destinati a essere scartati.

Comportamento dei client

Diversi client gestiscono Expect: 100-continue diversamente:

  • curl: lo invia automaticamente per body > 1KB. Disabilitabile con -H "Expect:".
  • Java HttpURLConnection: opt-in via setChunkedStreamingMode + properties.
  • Python requests: non lo invia di default, va aggiunto manualmente.
  • Browser: non lo usano nelle fetch standard.
  • libcurl: default per body > 1KB su HTTP/1.1.

Timeout client

I client che inviano Expect aspettano un breve timeout (tipicamente 1-3 secondi) per la risposta 100. Se non arriva, inviano comunque il body. Questo previene deadlock con server che non capiscono Expect ma non rispondono 417.

Server side: implementazione

Apache HTTPD: gestisce 100-continue automaticamente. Per disabilitarlo: SetEnvIf Expect "100-continue" expect-100-disable.

Nginx: dalla versione 1.13.10 supporta nativamente http2_idle_timeout e gestisce Expect automaticamente per HTTP/1.1.

Application-level (Node, PHP): tipicamente il web server o reverse proxy gestisce, ma alcune fasi (es. autenticazione custom) potrebbero richiedere logica esplicita.

Workaround per server che non supportano 100-continue

Se un proxy intermedio rompe Expect, alcuni client (curl, libcurl) cadono in fallback: inviano comunque il body dopo il timeout. Per evitare overhead, disabilita Expect quando sai che il server non lo supporta:

curl --header "Expect:" -F "file=@bigfile.bin" https://example.com/upload

HTTP/2 e Expect

HTTP/2 ha meccanismi nativi per la stream prioritization e il flow control che rendono Expect: 100-continue meno necessario. Alcuni server HTTP/2 lo gestiscono comunque per retrocompatibilita, altri lo ignorano e procedono direttamente.

Errori comuni

  • Proxy intermedi (Nginx, HAProxy, Apache come reverse) che dimenticano di propagare Expect al backend.
  • Application code che non sa rispondere 100, lasciando il client appeso.
  • Confusione tra 417 e 412 Precondition Failed (sono cose diverse: 412 e per If-Match etc.).

Diagnostica

curl -v -H "Expect: 100-continue" -d "test=1" https://example.com/api/endpoint

# Cerca nella verbose output:
< HTTP/1.1 100 Continue
# oppure
< HTTP/1.1 417 Expectation Failed

Quando il client invia Expect

libcurl invia Expect: 100-continue automaticamente quando body > 1KB. Comportamento configurabile via CURLOPT_HTTPHEADER con Expect: vuoto. Disabilitare quando si parla con server che non lo supportano (timeout aggiunto inutile).

Server che non rispondono 100

Alcuni server vecchi o configurazioni proxy errate ignorano completamente Expect e attendono direttamente il body. Client moderni hanno timeout (es. libcurl: 1 secondo) e inviano body comunque dopo timeout. Risultato: piccolo overhead di latenza, ma transazione completa.

Body grandi e auth fallita

Lo use case ideale: client vuole inviare 1GB ma il server richiede auth. Senza Expect, client uploaderebbe 1GB poi riceverebbe 401. Con Expect, riceve 401 immediatamente, risparmiando banda.

HTTP/2 e 100 Continue

HTTP/2 non usa il 100 Continue come HTTP/1.1: la stream prioritization e flow control nativi gestiscono il problema senza bisogno di un round trip esplicito. Alcuni server H2 (Nginx, Apache) emettono comunque 100 Continue per retrocompatibilita con tooling.

417 nel cloud

Servizi cloud (AWS API Gateway, GCP Cloud Endpoints) tipicamente strippano l'header Expect: 100-continue per semplicità. I client inviano direttamente. Per uploads grandi, raccomandati S3 presigned URL o equivalenti, bypassando il problema.

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.

Hai trovato utile quest'articolo?