5. Streams and Multiplexing (Flussi e Multiplexing)
Uno "stream (flusso)" è 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 intero. Gli identificatori di stream vengono assegnati agli stream dall'endpoint che avvia lo stream.
5.1. Stream States (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: l'endpoint invia questo frame
recv: l'endpoint riceve questo frame
H: frame HEADERS (con frame CONTINUATION impliciti)
PP: frame PUSH_PROMISE (con frame CONTINUATION impliciti)
ES: flag END_STREAM
R: frame RST_STREAM
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 comportano transizioni di stato e sono effettivamente parte degli HEADERS o PUSH_PROMISE che seguono. Ai fini delle transizioni di stato, il flag END_STREAM viene elaborato come evento separato dal frame che lo porta; 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 uno degli 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 (inattivo): 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 inattivo 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 inattivo 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 inattivo ma fa riferimento al nuovo stream 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) (riservato (locale)): Uno stream nello stato "reserved (local)" è uno che è stato promesso inviando un frame PUSH_PROMISE. Un frame PUSH_PROMISE riserva uno stream inattivo associando lo stream a uno stream aperto 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 diventare lo stream "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) (riservato (remoto)): 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 diventare lo stream "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 (aperto): 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 il flag END_STREAM impostato, facendo passare lo stream 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) (semi-chiuso (locale)): Uno stream 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) (semi-chiuso (remoto)): Uno stream "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 in questo stato, DEVE rispondere con un errore di stream (Sezione 5.4.2) di tipo STREAM_CLOSED.
Uno stream "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 (chiuso): 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 trattarlo 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 trattarlo 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 a seguito dell'invio di un frame RST_STREAM, il peer che riceve 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 in errore.
I frame controllati dal flusso (cioè DATA) ricevuti dopo l'invio di RST_STREAM vengono conteggiati nella finestra di controllo di flusso della connessione. Anche se questi frame potrebbero essere ignorati, poiché vengono inviati prima che il mittente riceva RST_STREAM, il mittente considererà i frame come 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, è necessario un RST_STREAM per chiudere uno stream promesso indesiderato.
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 la cui 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 di 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. Stream Identifiers (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 dispari; quelli avviati dal server DEVONO utilizzare identificatori di stream pari. Un identificatore di stream di 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 avrebbero potuto essere 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 comportare l'esaurimento dell'intervallo disponibile di identificatori di stream da parte di un endpoint. 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. Stream Concurrency (Concorrenza degli Stream)
Un peer può limitare il numero di stream attivi simultaneamente utilizzando il parametro SETTINGS_MAX_CONCURRENT_STREAMS (vedere Sezione 6.5.2) all'interno di un frame SETTINGS. L'impostazione massima degli stream concorrenti è specifica per ciascun endpoint e si applica solo al peer che riceve l'impostazione. Cioè, i client specificano il numero massimo di stream concorrenti che il server può avviare e i server specificano il numero massimo di stream concorrenti che il client può avviare.
Gli stream che sono 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 qualsiasi 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 limite di stream concorrenti annunciato DEVE trattarlo 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 corrente di stream aperti può chiudere gli stream che superano il nuovo valore o consentire agli stream di completarsi.
5.2. Flow Control (Controllo di Flusso)
L'uso di stream per il multiplexing introduce una contesa sull'uso della connessione TCP, con conseguente blocco degli stream. Uno schema di controllo di flusso garantisce che gli stream sulla stessa connessione non interferiscano in modo distruttivo tra loro. Il controllo di flusso viene utilizzato sia per i singoli stream che per la connessione nel suo insieme.
HTTP/2 fornisce il controllo di flusso attraverso l'uso del frame WINDOW_UPDATE (Sezione 6.9).
5.2.1. Flow-Control Principles (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:
-
Il controllo di flusso è specifico per una connessione. Il controllo di flusso HTTP/2 opera tra gli endpoint di un singolo hop e non su tutto il percorso end-to-end.
-
Il controllo di flusso si basa sui frame WINDOW_UPDATE. I ricevitori annunciano quanti ottetti sono pronti a ricevere su uno stream e per l'intera connessione. Questo è uno schema basato sul credito.
-
Il controllo di flusso è direzionale con controllo generale fornito dal ricevitore. Un ricevitore PUÒ scegliere di impostare qualsiasi dimensione di finestra desideri 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.
-
Il valore iniziale per la finestra di controllo di flusso è 65.535 ottetti sia per i nuovi stream che per l'intera connessione.
-
Il tipo di frame determina se il controllo di flusso si applica a un frame. Dei 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.
-
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.
-
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 sono in grado di selezionare qualsiasi algoritmo adatto 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. Appropriate Use of Flow Control (Uso Appropriato del Controllo di Flusso)
Il controllo di flusso è definito per proteggere gli endpoint che operano con 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 limitate (ad esempio, memoria) possono utilizzare 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 del prodotto larghezza di banda × ritardo corrente, 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. Il mancato lettura tempestiva potrebbe portare a un deadlock quando frame critici, come WINDOW_UPDATE, non vengono letti e agiti. Leggere i frame tempestivamente 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. Flow-Control Performance (Prestazioni del Controllo di Flusso)
Se un endpoint non può garantire che il suo peer abbia sempre uno spazio disponibile della finestra di controllo di flusso maggiore del prodotto larghezza di banda × ritardo del peer su questa connessione, il suo throughput di ricezione sarà limitato dal controllo di flusso HTTP/2. Questo comporterà prestazioni degradate.
L'invio tempestivo di frame WINDOW_UPDATE 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. Prioritization (Prioritizzazione)
In un protocollo multiplexato come HTTP/2, dare priorità all'allocazione delle risorse di larghezza di banda e calcolo agli stream può essere fondamentale per ottenere buone prestazioni. Uno schema di prioritizzazione scadente può far sì che HTTP/2 fornisca prestazioni scadenti. Senza parallelismo a livello TCP, le prestazioni potrebbero essere significativamente peggiori di HTTP/1.1.
Uno schema di prioritizzazione efficace beneficia dell'applicazione di conoscenze contestuali come il contenuto delle risorse, il modo in cui le risorse sono correlate e il modo in cui tali risorse saranno utilizzate da un peer. In particolare, i client possono possedere conoscenze sulla priorità delle richieste rilevanti per la prioritizzazione del server. In questi casi, far fornire ai client informazioni sulla priorità può migliorare le prestazioni.
5.3.1. Background on Priority in RFC 7540 (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, implementare il supporto generico per lo schema era complesso. L'implementazione delle priorità era irregolare sia nei client che nei server. Molte distribuzioni di server ignoravano i segnali dei client quando davano priorità alla gestione delle richieste.
In breve, la segnalazione di prioritizzazione in RFC 7540 [RFC7540] non ha avuto successo.
5.3.2. Priority Signaling in This Document (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à di 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 trarre vantaggio dall'applicazione di tali informazioni. In particolare, le implementazioni che consumano questi segnali non trarrebbero vantaggio dallo scartare questi segnali di priorità in assenza di alternative.
I server DOVREBBERO utilizzare altre informazioni contestuali nel determinare la 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. Error Handling (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 (connection error).
-
Un errore in un singolo stream è un errore di stream (stream error).
Un elenco di codici di errore è incluso nella Sezione 7.
È possibile che un endpoint incontri frame che causerebbero più errori. Le implementazioni POSSONO scoprire più errori 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 determinato stream impedisce la segnalazione di altri errori su quello stream. In confronto, il protocollo consente più frame GOAWAY, sebbene un endpoint DOVREBBE segnalare solo un tipo di errore di connessione a meno che non si verifichi un errore durante lo spegnimento 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 più errori diversi, PUÒ scegliere di segnalare uno qualsiasi di questi errori. Se un frame causa un errore di connessione, tale 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. Connection Error Handling (Gestione degli Errori di Connessione)
Un errore di connessione è qualsiasi errore che impedisce l'ulteriore elaborazione del livello 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 best-effort di comunicare con il peer sul motivo per cui la connessione viene terminata.
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. Stream Error Handling (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 pronto 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 della connessione (come lo stato mantenuto per la compressione della sezione del 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 round-trip. Questo comportamento è consentito per affrontare implementazioni che si comportano male.
Per evitare loop, un endpoint NON DEVE inviare un RST_STREAM in risposta a un frame RST_STREAM.
5.4.3. Connection Termination (Terminazione della Connessione)
Se la connessione TCP viene chiusa o reimpostata mentre gli stream rimangono negli stati "open" o "half-closed", allora gli stream interessati non possono essere ritentati automaticamente (vedere Sezione 8.7 per i dettagli).
5.5. Extending HTTP/2 (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 la gestione di 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 i frame che hanno tipi sconosciuti o non supportati. Ciò significa che uno 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 gli elementi del protocollo definiti in questo documento o gli elementi per i quali non è definito alcun meccanismo di estensione. Ciò 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-intestazione, 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 del protocollo esistenti o lo stato 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 questo è accettabile. In questo caso, potrebbe anche essere necessario coordinare quando il layout rivisto entra in vigore. Ad esempio, trattare i frame diversi dai frame DATA come controllati dal flusso richiede una modifica della 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 per tale scopo. Se entrambi i peer impostano un valore che indica la disponibilità a 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!