Passa al contenuto principale

5. Stream e Multiplexing

Uno "stream" è una sequenza indipendente e bidirezionale di frame scambiati tra client e server all'interno di una connessione HTTP/2. Gli stream hanno diverse caratteristiche importanti:

  • Una singola connessione HTTP/2 può contenere più stream aperti contemporaneamente, con entrambi gli endpoint che intercalano frame da più stream.

  • Gli stream possono essere stabiliti e utilizzati unilateralmente o condivisi dal client o dal server.

  • Gli stream possono essere chiusi da entrambi gli endpoint.

  • L'ordine in cui i frame vengono inviati su uno stream è significativo. I destinatari elaborano i frame nell'ordine in cui vengono ricevuti. In particolare, l'ordine dei frame HEADERS e DATA è semanticamente significativo.

  • Gli stream sono identificati da un numero intero. Gli identificatori di stream sono assegnati agli stream dall'endpoint che avvia lo stream.

5.1. Stati degli Stream

Il ciclo di vita di uno stream è mostrato nella Figura 2.

                             +--------+
send PP | | recv PP
,--------+ idle +--------.
/ | | \
v +--------+ v
+----------+ | +----------+
| | | send H / | |
,-----+ reserved | | recv H | reserved +-----.
| | (local) | | | (remote) | |
| +---+------+ v +------+---+ |
| | +--------+ | |
| | recv ES | | send ES | |
| send H | ,-------+ open +-------. | recv H |
| | / | | \ | |
| v v +---+----+ v v |
| +----------+ | +----------+ |
| | half- | | | half- | |
| | closed | | send R / | closed | |
| | (remote) | | recv R | (local) | |
| +----+-----+ | +-----+----+ |
| | | | |
| | send ES / | recv ES / | |
| | send R / v send R / | |
| | recv R +--------+ recv R | |
| send R / `----------->| |<-----------' send R / |
| recv R | closed | recv R |
`----------------------->| |<----------------------'
+--------+

send: endpoint sends this frame
recv: endpoint receives this frame

H: HEADERS frame (with implied CONTINUATION frames)
PP: PUSH_PROMISE frame (with implied CONTINUATION frames)
ES: END_STREAM flag
R: RST_STREAM frame

Figura 2: Stati degli Stream

Si noti che questo diagramma mostra solo le transizioni di stato degli stream e i frame e flag che influenzano tali cambiamenti di stato. A questo riguardo, i frame CONTINUATION non causano transizioni di stato e sono effettivamente parte del frame HEADERS o PUSH_PROMISE che seguono. Ai fini delle transizioni di stato, il flag END_STREAM viene elaborato come un evento separato dal frame che lo contiene; un frame HEADERS con il flag END_STREAM impostato può causare due transizioni di stato.

Entrambi gli endpoint hanno una visione soggettiva dello stato di uno stream che potrebbe essere diversa quando i frame sono in transito. Gli endpoint non coordinano la creazione degli stream; vengono creati unilateralmente da entrambi gli endpoint. Le conseguenze negative di una discrepanza negli stati sono limitate allo stato "closed" dopo l'invio di RST_STREAM, dove i frame potrebbero essere ricevuti per qualche tempo dopo la chiusura.

Gli stream hanno i seguenti stati:

idle: Tutti gli stream iniziano nello stato "idle".

Le seguenti transizioni sono valide da questo stato:

  • L'invio o la ricezione di un frame HEADERS fa sì che lo stream diventi "open". L'identificatore di stream viene selezionato come descritto nella Sezione 5.1.1. Lo stesso frame HEADERS può anche far sì che uno stream diventi immediatamente "half-closed".

  • L'invio di un frame PUSH_PROMISE su un altro stream riserva lo stream idle identificato per un uso successivo. Lo stato dello stream per lo stream riservato passa a "reserved (local)".

  • La ricezione di un frame PUSH_PROMISE su un altro stream riserva uno stream idle identificato per un uso successivo. Lo stato dello stream per lo stream riservato passa a "reserved (remote)".

  • Si noti che il frame PUSH_PROMISE non viene inviato sullo stream idle ma fa riferimento allo stream appena riservato nel campo Promised Stream ID.

La ricezione di qualsiasi frame diverso da HEADERS o PRIORITY su uno stream in questo stato DEVE essere trattata come un errore di connessione (Sezione 5.4.1) di tipo PROTOCOL_ERROR.

reserved (local): Uno stream nello stato "reserved (local)" è uno che è stato promesso inviando un frame PUSH_PROMISE. Un frame PUSH_PROMISE riserva uno stream idle associando lo stream a uno stream aperto che è stato avviato dal peer remoto (vedere Sezione 8.4).

In questo stato, sono possibili solo le seguenti transizioni:

  • L'endpoint può inviare un frame HEADERS. Questo fa sì che lo stream si apra in uno stato "half-closed (remote)".

  • Entrambi gli endpoint possono inviare un frame RST_STREAM per far sì che lo stream diventi "closed". Questo rilascia la prenotazione dello stream.

Un endpoint NON DEVE inviare alcun tipo di frame diverso da HEADERS, RST_STREAM o PRIORITY in questo stato.

Un frame PRIORITY o WINDOW_UPDATE PUÒ essere ricevuto in questo stato. La ricezione di qualsiasi tipo di frame diverso da RST_STREAM, PRIORITY o WINDOW_UPDATE su uno stream in questo stato DEVE essere trattata come un errore di connessione (Sezione 5.4.1) di tipo PROTOCOL_ERROR.

reserved (remote): Uno stream nello stato "reserved (remote)" è stato riservato da un peer remoto.

In questo stato, sono possibili solo le seguenti transizioni:

  • La ricezione di un frame HEADERS fa sì che lo stream passi a "half-closed (local)".

  • Entrambi gli endpoint possono inviare un frame RST_STREAM per far sì che lo stream diventi "closed". Questo rilascia la prenotazione dello stream.

Un endpoint PUÒ inviare un frame PRIORITY in questo stato per ripriorizzare lo stream riservato. Un endpoint NON DEVE inviare alcun tipo di frame diverso da RST_STREAM, WINDOW_UPDATE o PRIORITY in questo stato.

La ricezione di qualsiasi tipo di frame diverso da HEADERS, RST_STREAM o PRIORITY su uno stream in questo stato DEVE essere trattata come un errore di connessione (Sezione 5.4.1) di tipo PROTOCOL_ERROR.

open: Uno stream nello stato "open" può essere utilizzato da entrambi i peer per inviare frame di qualsiasi tipo. In questo stato, i peer mittenti osservano i limiti di controllo di flusso a livello di stream annunciati (Sezione 5.2).

Da questo stato, entrambi gli endpoint possono inviare un frame con un flag END_STREAM impostato, che fa sì che lo stream passi in uno degli stati "half-closed". Un endpoint che invia un flag END_STREAM fa sì che lo stato dello stream diventi "half-closed (local)"; un endpoint che riceve un flag END_STREAM fa sì che lo stato dello stream diventi "half-closed (remote)".

Entrambi gli endpoint possono inviare un frame RST_STREAM da questo stato, facendolo passare immediatamente a "closed".

half-closed (local): Uno stream che si trova nello stato "half-closed (local)" non può essere utilizzato per inviare frame diversi da WINDOW_UPDATE, PRIORITY e RST_STREAM.

Uno stream passa da questo stato a "closed" quando viene ricevuto un frame con il flag END_STREAM impostato o quando uno dei peer invia un frame RST_STREAM.

Un endpoint può ricevere qualsiasi tipo di frame in questo stato. Fornire credito di controllo di flusso utilizzando frame WINDOW_UPDATE è necessario per continuare a ricevere frame controllati dal flusso. In questo stato, un ricevitore può ignorare i frame WINDOW_UPDATE, che potrebbero arrivare per un breve periodo dopo l'invio di un frame con il flag END_STREAM impostato.

I frame PRIORITY ricevuti in questo stato vengono utilizzati per ripriorizzare gli stream che dipendono dallo stream identificato.

half-closed (remote): Uno stream che è "half-closed (remote)" non viene più utilizzato dal peer per inviare frame. In questo stato, un endpoint non è più obbligato a mantenere una finestra di controllo di flusso del ricevitore.

Se un endpoint riceve frame aggiuntivi, diversi da WINDOW_UPDATE, PRIORITY o RST_STREAM, per uno stream che si trova in questo stato, DEVE rispondere con un errore di stream (Sezione 5.4.2) di tipo STREAM_CLOSED.

Uno stream che è "half-closed (remote)" può essere utilizzato dall'endpoint per inviare frame di qualsiasi tipo. In questo stato, l'endpoint continua a osservare i limiti di controllo di flusso a livello di stream annunciati (Sezione 5.2).

Uno stream può passare da questo stato a "closed" inviando un frame con il flag END_STREAM impostato o quando uno dei peer invia un frame RST_STREAM.

closed: Lo stato "closed" è lo stato terminale.

Un endpoint NON DEVE inviare frame diversi da PRIORITY su uno stream chiuso. Un endpoint che riceve qualsiasi frame diverso da PRIORITY dopo aver ricevuto un RST_STREAM DEVE trattare ciò come un errore di stream (Sezione 5.4.2) di tipo STREAM_CLOSED. Allo stesso modo, un endpoint che riceve frame dopo aver ricevuto un frame con il flag END_STREAM impostato DEVE trattare ciò come un errore di connessione (Sezione 5.4.1) di tipo STREAM_CLOSED, a meno che il frame non sia consentito come descritto di seguito.

I frame WINDOW_UPDATE o RST_STREAM possono essere ricevuti in questo stato per un breve periodo dopo l'invio di un frame DATA o HEADERS contenente un flag END_STREAM. Fino a quando il peer remoto non riceve ed elabora RST_STREAM o il frame che porta il flag END_STREAM, potrebbe inviare frame di questi tipi. Gli endpoint DEVONO ignorare i frame WINDOW_UPDATE o RST_STREAM ricevuti in questo stato, sebbene gli endpoint POSSANO scegliere di trattare i frame che arrivano un tempo significativo dopo l'invio di END_STREAM come un errore di connessione (Sezione 5.4.1) di tipo PROTOCOL_ERROR.

I frame PRIORITY possono essere inviati su stream chiusi per dare priorità agli stream che dipendono dallo stream chiuso. Gli endpoint DOVREBBERO elaborare i frame PRIORITY, sebbene possano essere ignorati se lo stream è stato rimosso dall'albero delle dipendenze (vedere Sezione 5.3.3 di [RFC7540]).

Se questo stato viene raggiunto come risultato dell'invio di un frame RST_STREAM, il peer che riceve il RST_STREAM potrebbe aver già inviato -- o messo in coda per l'invio -- frame sullo stream che non possono essere ritirati. Un endpoint DEVE ignorare i frame che riceve su stream chiusi dopo aver inviato un frame RST_STREAM. Un endpoint PUÒ scegliere di limitare il periodo durante il quale ignora i frame e trattare i frame che arrivano dopo questo tempo come errori.

I frame controllati dal flusso (cioè DATA) ricevuti dopo l'invio di RST_STREAM sono conteggiati nella finestra di controllo di flusso della connessione. Anche se questi frame potrebbero essere ignorati, poiché vengono inviati prima che il mittente riceva il RST_STREAM, il mittente considererà i frame conteggiati rispetto alla finestra di controllo di flusso.

Un endpoint potrebbe ricevere un frame PUSH_PROMISE dopo aver inviato RST_STREAM. PUSH_PROMISE fa sì che uno stream diventi "reserved" anche se lo stream associato è stato reimpostato. Pertanto, un RST_STREAM è necessario per chiudere uno stream promesso non desiderato.

In assenza di regole più specifiche, le implementazioni DOVREBBERO trattare la ricezione di un frame che non è espressamente consentito nella descrizione di uno stato come un errore di connessione (Sezione 5.4.1) di tipo PROTOCOL_ERROR. Si noti che PRIORITY può essere inviato e ricevuto in qualsiasi stato dello stream.

Le regole in questa sezione si applicano solo ai frame definiti in questo documento. La ricezione di frame di cui la semantica è sconosciuta non può essere trattata come un errore, poiché anche le condizioni per l'invio e la ricezione di tali frame sono sconosciute; vedere Sezione 5.5.

Un esempio delle transizioni di stato per uno scambio richiesta/risposta HTTP può essere trovato nella Sezione 8.8. Un esempio delle transizioni di stato per il push del server può essere trovato nelle Sezioni 8.4.1 e 8.4.2.

5.1.1. Identificatori di Stream

Gli stream sono identificati da un intero senza segno a 31 bit. Gli stream avviati da un client DEVONO utilizzare identificatori di stream con numeri dispari; quelli avviati dal server DEVONO utilizzare identificatori di stream con numeri pari. Un identificatore di stream pari a zero (0x00) viene utilizzato per i messaggi di controllo della connessione; l'identificatore di stream zero non può essere utilizzato per stabilire un nuovo stream.

L'identificatore di uno stream appena stabilito DEVE essere numericamente maggiore di tutti gli stream che l'endpoint iniziatore ha aperto o riservato. Questo regola gli stream aperti utilizzando un frame HEADERS e gli stream riservati utilizzando PUSH_PROMISE. Un endpoint che riceve un identificatore di stream inaspettato DEVE rispondere con un errore di connessione (Sezione 5.4.1) di tipo PROTOCOL_ERROR.

Un frame HEADERS farà passare lo stream avviato dal client identificato dall'identificatore di stream nell'intestazione del frame da "idle" a "open". Un frame PUSH_PROMISE farà passare lo stream avviato dal server identificato dal campo Promised Stream ID nel payload del frame da "idle" a "reserved (local)" o "reserved (remote)". Quando uno stream passa dallo stato "idle", tutti gli stream nello stato "idle" che potrebbero essere stati aperti dal peer con un identificatore di stream di valore inferiore passano immediatamente a "closed". Cioè, un endpoint può saltare un identificatore di stream, con l'effetto che lo stream saltato viene immediatamente chiuso.

Gli identificatori di stream non possono essere riutilizzati. Le connessioni di lunga durata possono portare un endpoint ad esaurire l'intervallo disponibile di identificatori di stream. Un client che non è in grado di stabilire un nuovo identificatore di stream può stabilire una nuova connessione per nuovi stream. Un server che non è in grado di stabilire un nuovo identificatore di stream può inviare un frame GOAWAY in modo che il client sia costretto ad aprire una nuova connessione per nuovi stream.

5.1.2. Concorrenza degli Stream

Un peer può limitare il numero di stream attivi contemporaneamente utilizzando il parametro SETTINGS_MAX_CONCURRENT_STREAMS (vedere Sezione 6.5.2) all'interno di un frame SETTINGS. L'impostazione massima degli stream simultanei è specifica per ciascun endpoint e si applica solo al peer che riceve l'impostazione. Cioè, i client specificano il numero massimo di stream simultanei che il server può avviare, e i server specificano il numero massimo di stream simultanei che il client può avviare.

Gli stream che si trovano nello stato "open" o in uno degli stati "half-closed" contano verso il numero massimo di stream che un endpoint è autorizzato ad aprire. Gli stream in uno di questi tre stati contano verso il limite annunciato nell'impostazione SETTINGS_MAX_CONCURRENT_STREAMS. Gli stream in uno degli stati "reserved" non contano verso il limite di stream.

Gli endpoint NON DEVONO superare il limite impostato dal loro peer. Un endpoint che riceve un frame HEADERS che causa il superamento del suo limite di stream simultanei annunciato DEVE trattare ciò come un errore di stream (Sezione 5.4.2) di tipo PROTOCOL_ERROR o REFUSED_STREAM. La scelta del codice di errore determina se l'endpoint desidera abilitare il nuovo tentativo automatico (vedere Sezione 8.7 per i dettagli).

Un endpoint che desidera ridurre il valore di SETTINGS_MAX_CONCURRENT_STREAMS a un valore inferiore al numero attuale di stream aperti può chiudere gli stream che superano il nuovo valore o consentire agli stream di completarsi.

5.2. Controllo di Flusso

L'uso di stream per il multiplexing introduce contesa sull'uso della connessione TCP, con conseguenti stream bloccati. Uno schema di controllo di flusso garantisce che gli stream sulla stessa connessione non interferiscano distruttivamente tra loro. Il controllo di flusso viene utilizzato sia per i singoli stream che per la connessione nel suo complesso.

HTTP/2 fornisce il controllo di flusso attraverso l'uso del frame WINDOW_UPDATE (Sezione 6.9).

5.2.1. Principi del Controllo di Flusso

Il controllo di flusso degli stream HTTP/2 mira a consentire l'uso di una varietà di algoritmi di controllo di flusso senza richiedere modifiche al protocollo. Il controllo di flusso in HTTP/2 ha le seguenti caratteristiche:

  1. Il controllo di flusso è specifico per una connessione. Il controllo di flusso HTTP/2 opera tra gli endpoint di un singolo hop e non sull'intero percorso end-to-end.

  2. Il controllo di flusso si basa su frame WINDOW_UPDATE. I ricevitori annunciano quanti ottetti sono preparati a ricevere su uno stream e per l'intera connessione. Questo è uno schema basato sul credito.

  3. Il controllo di flusso è direzionale con controllo complessivo fornito dal ricevitore. Un ricevitore PUÒ scegliere di impostare qualsiasi dimensione di finestra che desidera per ogni stream e per l'intera connessione. Un mittente DEVE rispettare i limiti di controllo di flusso imposti da un ricevitore. Client, server e intermediari annunciano tutti indipendentemente la loro finestra di controllo di flusso come ricevitore e rispettano i limiti di controllo di flusso impostati dal loro peer durante l'invio.

  4. Il valore iniziale per la finestra di controllo di flusso è 65.535 ottetti sia per i nuovi stream che per l'intera connessione.

  5. Il tipo di frame determina se il controllo di flusso si applica a un frame. Tra i frame specificati in questo documento, solo i frame DATA sono soggetti al controllo di flusso; tutti gli altri tipi di frame non consumano spazio nella finestra di controllo di flusso annunciata. Questo garantisce che i frame di controllo importanti non vengano bloccati dal controllo di flusso.

  6. Un endpoint può scegliere di disabilitare il proprio controllo di flusso, ma un endpoint non può ignorare i segnali di controllo di flusso dal suo peer.

  7. HTTP/2 definisce solo il formato e la semantica del frame WINDOW_UPDATE (Sezione 6.9). Questo documento non stabilisce come un ricevitore decide quando inviare questo frame o il valore che invia, né specifica come un mittente sceglie di inviare pacchetti. Le implementazioni possono selezionare qualsiasi algoritmo che si adatti alle loro esigenze.

Le implementazioni sono anche responsabili della prioritizzazione dell'invio di richieste e risposte, della scelta di come evitare il blocco head-of-line per le richieste e della gestione della creazione di nuovi stream. Le scelte algoritmiche per questi potrebbero interagire con qualsiasi algoritmo di controllo di flusso.

5.2.2. Uso Appropriato del Controllo di Flusso

Il controllo di flusso è definito per proteggere gli endpoint che operano sotto vincoli di risorse. Ad esempio, un proxy deve condividere la memoria tra molte connessioni e potrebbe anche avere una connessione upstream lenta e una connessione downstream veloce. Il controllo di flusso affronta i casi in cui il ricevitore non è in grado di elaborare i dati su uno stream ma desidera continuare a elaborare altri stream sulla stessa connessione.

Le distribuzioni che non richiedono questa capacità possono annunciare una finestra di controllo di flusso della dimensione massima (2^31-1) e possono mantenere questa finestra inviando un frame WINDOW_UPDATE quando vengono ricevuti dati. Questo disabilita effettivamente il controllo di flusso per quel ricevitore. Al contrario, un mittente è sempre soggetto alla finestra di controllo di flusso annunciata dal ricevitore.

Le distribuzioni con risorse vincolate (ad esempio, memoria) possono impiegare il controllo di flusso per limitare la quantità di memoria che un peer può consumare. Si noti, tuttavia, che questo può portare a un uso non ottimale delle risorse di rete disponibili se il controllo di flusso è abilitato senza conoscenza del prodotto larghezza di banda * ritardo (vedere [RFC7323]).

Anche con piena consapevolezza dell'attuale prodotto larghezza di banda * ritardo, l'implementazione del controllo di flusso può essere difficile. Gli endpoint DEVONO leggere ed elaborare i frame HTTP/2 dal buffer di ricezione TCP non appena i dati sono disponibili. La mancata lettura tempestiva potrebbe portare a un deadlock quando frame critici, come WINDOW_UPDATE, non vengono letti e agiti. La lettura tempestiva dei frame non espone gli endpoint ad attacchi di esaurimento delle risorse, poiché il controllo di flusso HTTP/2 limita gli impegni di risorse.

5.2.3. Prestazioni del Controllo di Flusso

Se un endpoint non può garantire che il suo peer abbia sempre spazio disponibile nella finestra di controllo di flusso superiore al prodotto larghezza di banda * ritardo del peer su questa connessione, il suo throughput di ricezione sarà limitato dal controllo di flusso HTTP/2. Questo risulterà in prestazioni degradate.

L'invio di frame WINDOW_UPDATE tempestivi può migliorare le prestazioni. Gli endpoint vorranno bilanciare la necessità di migliorare il throughput di ricezione con la necessità di gestire i rischi di esaurimento delle risorse e dovrebbero prendere attenta nota della Sezione 10.5 nel definire la loro strategia per gestire le dimensioni delle finestre.

5.3. Prioritizzazione

In un protocollo multiplexed come HTTP/2, la prioritizzazione dell'allocazione della larghezza di banda e delle risorse di calcolo agli stream può essere critica per ottenere buone prestazioni. Uno schema di prioritizzazione scarso può portare HTTP/2 a fornire prestazioni scadenti. Senza parallelismo a livello TCP, le prestazioni potrebbero essere significativamente peggiori di HTTP/1.1.

Un buon schema di prioritizzazione beneficia dell'applicazione di conoscenze contestuali come il contenuto delle risorse, come le risorse sono correlate tra loro e come tali risorse verranno utilizzate da un peer. In particolare, i client possono possedere conoscenze sulla priorità delle richieste che sono rilevanti per la prioritizzazione del server. In quei casi, avere i client che forniscono informazioni sulla priorità può migliorare le prestazioni.

5.3.1. Contesto sulla Priorità in RFC 7540

RFC 7540 ha definito un sistema ricco per segnalare la priorità delle richieste. Tuttavia, questo sistema si è rivelato complesso e non è stato implementato uniformemente.

Lo schema flessibile significava che era possibile per i client esprimere le priorità in modi molto diversi, con poca coerenza negli approcci adottati. Per i server, l'implementazione del supporto generico per lo schema era complessa. L'implementazione delle priorità era irregolare sia nei client che nei server. Molte distribuzioni di server hanno ignorato i segnali dei client quando prioritizzavano la gestione delle richieste.

In breve, la segnalazione di prioritizzazione in RFC 7540 [RFC7540] non ha avuto successo.

5.3.2. Segnalazione di Priorità in Questo Documento

Questo aggiornamento a HTTP/2 depreca la segnalazione di priorità definita in RFC 7540 [RFC7540]. La maggior parte del testo relativo ai segnali di priorità non è inclusa in questo documento. La descrizione dei campi del frame e parte della gestione obbligatoria sono mantenute per garantire che le implementazioni di questo documento rimangano interoperabili con le implementazioni che utilizzano la segnalazione di priorità descritta in RFC 7540.

Una descrizione approfondita dello schema di priorità RFC 7540 rimane nella Sezione 5.3 di [RFC7540].

La segnalazione di informazioni sulla priorità è necessaria per ottenere buone prestazioni in molti casi. Dove la segnalazione di informazioni sulla priorità è importante, gli endpoint sono incoraggiati a utilizzare uno schema alternativo, come lo schema descritto in [HTTP-PRIORITY].

Sebbene la segnalazione di priorità da RFC 7540 non sia stata ampiamente adottata, le informazioni che fornisce possono ancora essere utili in assenza di informazioni migliori. Gli endpoint che ricevono segnali di priorità nei frame HEADERS o PRIORITY possono beneficiare dell'applicazione di tali informazioni. In particolare, le implementazioni che consumano questi segnali non trarrebbero beneficio dall'eliminazione di questi segnali di priorità in assenza di alternative.

I server DOVREBBERO utilizzare altre informazioni contestuali nella determinazione della priorità delle richieste in assenza di segnali di priorità. I server POSSONO interpretare l'assenza completa di segnali come un'indicazione che il client non ha implementato la funzionalità. I valori predefiniti descritti nella Sezione 5.3.5 di [RFC7540] sono noti per avere prestazioni scadenti nella maggior parte delle condizioni, e il loro uso è improbabile che sia deliberato.

5.4. Gestione degli Errori

Il framing HTTP/2 consente due classi di errori:

  • Una condizione di errore che rende l'intera connessione inutilizzabile è un errore di connessione.

  • Un errore in un singolo stream è un errore di stream.

Un elenco di codici di errore è incluso nella Sezione 7.

È possibile che un endpoint incontri frame che causerebbero errori multipli. Le implementazioni POSSONO scoprire errori multipli durante l'elaborazione, ma DOVREBBERO segnalare al massimo un errore di stream e un errore di connessione di conseguenza.

Il primo errore di stream segnalato per un dato stream impedisce che altri errori su quello stream vengano segnalati. In confronto, il protocollo consente frame GOAWAY multipli, sebbene un endpoint DOVREBBE segnalare solo un tipo di errore di connessione a meno che non si verifichi un errore durante l'arresto graduale. Se ciò si verifica, un endpoint PUÒ inviare un frame GOAWAY aggiuntivo con il nuovo codice di errore, oltre a qualsiasi GOAWAY precedente che conteneva NO_ERROR.

Se un endpoint rileva errori multipli diversi, PUÒ scegliere di segnalare uno qualsiasi di questi errori. Se un frame causa un errore di connessione, quell'errore DEVE essere segnalato. Inoltre, un endpoint PUÒ utilizzare qualsiasi codice di errore applicabile quando rileva una condizione di errore; un codice di errore generico (come PROTOCOL_ERROR o INTERNAL_ERROR) può sempre essere utilizzato al posto di codici di errore più specifici.

5.4.1. Gestione degli Errori di Connessione

Un errore di connessione è qualsiasi errore che impedisce l'ulteriore elaborazione del livello di frame o corrompe qualsiasi stato di connessione.

Un endpoint che incontra un errore di connessione DOVREBBE prima inviare un frame GOAWAY (Sezione 6.8) con l'identificatore di stream dell'ultimo stream che ha ricevuto con successo dal suo peer. Il frame GOAWAY include un codice di errore (Sezione 7) che indica perché la connessione sta terminando. Dopo aver inviato il frame GOAWAY per una condizione di errore, l'endpoint DEVE chiudere la connessione TCP.

È possibile che il GOAWAY non venga ricevuto in modo affidabile dall'endpoint ricevente. In caso di errore di connessione, GOAWAY fornisce solo un tentativo al meglio per comunicare con il peer sul motivo per cui la connessione sta terminando.

Un endpoint può terminare una connessione in qualsiasi momento. In particolare, un endpoint PUÒ scegliere di trattare un errore di stream come un errore di connessione. Gli endpoint DOVREBBERO inviare un frame GOAWAY quando terminano una connessione, a condizione che le circostanze lo consentano.

5.4.2. Gestione degli Errori di Stream

Un errore di stream è un errore relativo a uno stream specifico che non influisce sull'elaborazione di altri stream.

Un endpoint che rileva un errore di stream invia un frame RST_STREAM (Sezione 6.4) che contiene l'identificatore di stream dello stream in cui si è verificato l'errore. Il frame RST_STREAM include un codice di errore che indica il tipo di errore.

Un RST_STREAM è l'ultimo frame che un endpoint può inviare su uno stream. Il peer che invia il frame RST_STREAM DEVE essere preparato a ricevere tutti i frame che sono stati inviati o messi in coda per l'invio dal peer remoto. Questi frame possono essere ignorati, tranne quando modificano lo stato di connessione (come lo stato mantenuto per la compressione della sezione di campo (Sezione 4.3) o il controllo di flusso).

Normalmente, un endpoint NON DOVREBBE inviare più di un frame RST_STREAM per qualsiasi stream. Tuttavia, un endpoint PUÒ inviare frame RST_STREAM aggiuntivi se riceve frame su uno stream chiuso dopo più di un tempo di andata e ritorno. Questo comportamento è consentito per gestire implementazioni mal comportate.

Per evitare loop, un endpoint NON DEVE inviare un RST_STREAM in risposta a un frame RST_STREAM.

5.4.3. Terminazione della Connessione

Se la connessione TCP viene chiusa o reimpostata mentre gli stream rimangono negli stati "open" o "half-closed", gli stream interessati non possono essere riprovati automaticamente (vedere Sezione 8.7 per i dettagli).

5.5. Estensione di HTTP/2

HTTP/2 consente l'estensione del protocollo. Entro i limiti descritti in questa sezione, le estensioni del protocollo possono essere utilizzate per fornire servizi aggiuntivi o alterare qualsiasi aspetto del protocollo. Le estensioni sono efficaci solo nell'ambito di una singola connessione HTTP/2.

Questo si applica agli elementi del protocollo definiti in questo documento. Questo non influisce sulle opzioni esistenti per estendere HTTP, come la definizione di nuovi metodi, codici di stato o campi (vedere Sezione 16 di [HTTP]).

Le estensioni sono autorizzate a utilizzare nuovi tipi di frame (Sezione 4.1), nuove impostazioni (Sezione 6.5) o nuovi codici di errore (Sezione 7). I registri per gestire questi punti di estensione sono definiti nella Sezione 11 di [RFC7540].

Le implementazioni DEVONO ignorare valori sconosciuti o non supportati in tutti gli elementi del protocollo estensibili. Le implementazioni DEVONO scartare frame che hanno tipi sconosciuti o non supportati. Questo significa che qualsiasi di questi punti di estensione può essere utilizzato in modo sicuro dalle estensioni senza accordo o negoziazione preventiva. Tuttavia, i frame di estensione che appaiono nel mezzo di un blocco di campo (Sezione 4.3) non sono consentiti; questi DEVONO essere trattati come un errore di connessione (Sezione 5.4.1) di tipo PROTOCOL_ERROR.

Le estensioni DOVREBBERO evitare di modificare elementi del protocollo definiti in questo documento o elementi per i quali non è definito alcun meccanismo di estensione. Questo include modifiche al layout dei frame, aggiunte o modifiche al modo in cui i frame sono composti in messaggi HTTP (Sezione 8.1), la definizione di campi pseudo-header o modifiche a qualsiasi elemento del protocollo che un endpoint conforme potrebbe trattare come un errore di connessione (Sezione 5.4.1).

Un'estensione che modifica elementi o stati del protocollo esistenti DEVE essere negoziata prima di essere utilizzata. Ad esempio, un'estensione che modifica il layout del frame HEADERS non può essere utilizzata fino a quando il peer non ha dato un segnale positivo che ciò è accettabile. In questo caso, potrebbe anche essere necessario coordinare quando il layout rivisto entra in vigore. Ad esempio, trattare frame diversi dai frame DATA come controllati dal flusso richiede un cambiamento nella semantica che entrambi gli endpoint devono comprendere, quindi questo può essere fatto solo attraverso la negoziazione.

Questo documento non impone un metodo specifico per negoziare l'uso di un'estensione, ma nota che un'impostazione (Sezione 6.5.2) potrebbe essere utilizzata a tale scopo. Se entrambi i peer impostano un valore che indica la volontà di utilizzare l'estensione, allora l'estensione può essere utilizzata. Se un'impostazione viene utilizzata per la negoziazione dell'estensione, il valore iniziale DEVE essere definito in modo tale che l'estensione sia inizialmente disabilitata.


Capitolo 5 completato!