Passa al contenuto principale

6. Mappatura e utilizzo dei flussi (Stream Mapping and Usage)

Un flusso QUIC fornisce la consegna affidabile e ordinata di byte, ma non garantisce l'ordine di consegna rispetto ai byte su altri flussi. Nella versione 1 di QUIC, i dati del flusso contenenti frame HTTP sono trasportati da frame QUIC STREAM, ma questo framing è invisibile al livello di framing HTTP. Il livello di trasporto bufferizza e ordina i dati del flusso ricevuti, esponendo un flusso di byte affidabile all'applicazione. Sebbene QUIC permetta la consegna fuori ordine all'interno di un flusso, HTTP/3 non utilizza questa funzionalità.

I flussi QUIC possono essere unidirezionali, trasportando dati solo dall'iniziatore al ricevitore, o bidirezionali, trasportando dati in entrambe le direzioni. I flussi possono essere avviati dal client o dal server. Per maggiori dettagli sui flussi QUIC, vedere la sezione 2 di [QUIC-TRANSPORT].

Quando i campi e i dati HTTP vengono inviati su QUIC, il livello QUIC gestisce la maggior parte della gestione dei flussi. HTTP non ha bisogno di effettuare alcun multiplexing separato quando utilizza QUIC: i dati inviati su un flusso QUIC vengono sempre mappati a una particolare transazione HTTP o all'intero contesto di connessione HTTP/3.

6.1. Flussi bidirezionali (Bidirectional Streams)

Tutti i flussi bidirezionali avviati dal client vengono utilizzati per richieste e risposte HTTP. Un flusso bidirezionale garantisce che la risposta possa essere facilmente correlata alla richiesta. Questi flussi sono chiamati flussi di richiesta (Request Streams).

Ciò significa che la prima richiesta del client si verifica sul flusso QUIC 0, con le richieste successive sui flussi 4, 8 e così via. Per consentire l'apertura di questi flussi, un server HTTP/3 DOVREBBE (SHOULD) configurare valori minimi non nulli per il numero di flussi consentiti e la finestra di controllo del flusso iniziale. Per non limitare inutilmente il parallelismo, almeno 100 flussi di richiesta DOVREBBERO (SHOULD) essere consentiti contemporaneamente.

HTTP/3 non utilizza flussi bidirezionali avviati dal server, sebbene un'estensione potrebbe definire un uso per questi flussi. I client DEVONO (MUST) trattare la ricezione di un flusso bidirezionale avviato dal server come un errore di connessione di tipo H3_STREAM_CREATION_ERROR a meno che tale estensione non sia stata negoziata.

6.2. Flussi unidirezionali (Unidirectional Streams)

I flussi unidirezionali, in entrambe le direzioni, vengono utilizzati per una serie di scopi. Lo scopo è indicato da un tipo di flusso (Stream Type), che viene inviato come intero a lunghezza variabile all'inizio del flusso. Il formato e la struttura dei dati che seguono questo intero sono determinati dal tipo di flusso.

Unidirectional Stream Header {
Stream Type (i),
}

Figura 1: Intestazione del flusso unidirezionale

In questo documento sono definiti due tipi di flusso: flussi di controllo (Control Streams) (sezione 6.2.1) e flussi push (Push Streams) (sezione 6.2.2). [QPACK] definisce due tipi di flusso aggiuntivi. Altri tipi di flusso possono essere definiti da estensioni a HTTP/3; vedere la sezione 9 per maggiori dettagli. Alcuni tipi di flusso sono riservati (sezione 6.2.3).

Le prestazioni delle connessioni HTTP/3 nella fase iniziale della loro vita sono sensibili alla creazione e allo scambio di dati su flussi unidirezionali. Gli endpoint che limitano eccessivamente il numero di flussi o la finestra di controllo del flusso di questi flussi aumenteranno la possibilità che il peer remoto raggiunga il limite presto e diventi bloccato. In particolare, le implementazioni dovrebbero considerare che i peer remoti potrebbero voler esercitare il comportamento del flusso riservato (sezione 6.2.3) con alcuni dei flussi unidirezionali che sono autorizzati a utilizzare.

Ogni endpoint deve creare almeno un flusso unidirezionale per il flusso di controllo HTTP. QPACK richiede due flussi unidirezionali aggiuntivi e altre estensioni potrebbero richiedere ulteriori flussi. Pertanto, i parametri di trasporto inviati sia dai client che dai server DEVONO (MUST) consentire al peer di creare almeno tre flussi unidirezionali. Questi parametri di trasporto DOVREBBERO (SHOULD) anche fornire almeno 1.024 byte di credito di controllo del flusso a ciascun flusso unidirezionale.

Si noti che un endpoint non è tenuto a concedere crediti aggiuntivi per creare più flussi unidirezionali se il suo peer consuma tutti i crediti iniziali prima di creare i flussi unidirezionali critici. Gli endpoint DOVREBBERO (SHOULD) creare il flusso di controllo HTTP e i flussi unidirezionali richiesti dalle estensioni obbligatorie (come i flussi encoder e decoder QPACK) per primi, e quindi creare flussi aggiuntivi come consentito dal loro peer.

Se l'intestazione del flusso indica un tipo di flusso che non è supportato dal destinatario, il resto del flusso non può essere consumato poiché la semantica è sconosciuta. I destinatari di tipi di flusso sconosciuti DEVONO (MUST) interrompere la lettura del flusso o scartare i dati in arrivo senza ulteriore elaborazione. Se la lettura viene interrotta, il destinatario DOVREBBE (SHOULD) utilizzare il codice di errore H3_STREAM_CREATION_ERROR o un codice di errore riservato (sezione 8.1). Il destinatario NON DEVE (MUST NOT) considerare i tipi di flusso sconosciuti come un errore di connessione di alcun tipo.

Poiché alcuni tipi di flusso possono influenzare lo stato della connessione, un destinatario NON DOVREBBE (SHOULD NOT) scartare i dati dai flussi unidirezionali in arrivo prima di leggere il tipo di flusso.

Le implementazioni POSSONO (MAY) inviare tipi di flusso prima di sapere se il peer li supporta. Tuttavia, i tipi di flusso che potrebbero modificare lo stato o la semantica dei componenti di protocollo esistenti, inclusi QPACK o altre estensioni, NON DEVONO (MUST NOT) essere inviati finché non è noto che il peer li supporta.

Un mittente può chiudere o reimpostare un flusso unidirezionale salvo diversa indicazione. Un ricevitore DEVE (MUST) tollerare che i flussi unidirezionali vengano chiusi o reimpostati prima della ricezione dell'intestazione del flusso unidirezionale.

6.2.1. Flussi di controllo (Control Streams)

Un flusso di controllo è indicato da un tipo di flusso di 0x00. I dati su questo flusso sono costituiti da frame HTTP/3, come definito nella sezione 7.2.

Ciascun lato DEVE (MUST) avviare un singolo flusso di controllo all'inizio della connessione e inviare il proprio frame SETTINGS come primo frame su questo flusso. Se il primo frame del flusso di controllo è qualsiasi altro tipo di frame, questo DEVE (MUST) essere trattato come un errore di connessione di tipo H3_MISSING_SETTINGS. È consentito un solo flusso di controllo per peer; la ricezione di un secondo flusso che dichiara di essere un flusso di controllo DEVE (MUST) essere trattata come un errore di connessione di tipo H3_STREAM_CREATION_ERROR. Il mittente NON DEVE (MUST NOT) chiudere il flusso di controllo e il ricevitore NON DEVE (MUST NOT) richiedere che il mittente chiuda il flusso di controllo. Se uno dei flussi di controllo viene chiuso in qualsiasi momento, questo DEVE (MUST) essere trattato come un errore di connessione di tipo H3_CLOSED_CRITICAL_STREAM. Gli errori di connessione sono descritti nella sezione 8.

Poiché i contenuti del flusso di controllo vengono utilizzati per gestire il comportamento di altri flussi, gli endpoint DOVREBBERO (SHOULD) fornire credito di controllo del flusso sufficiente per impedire che il flusso di controllo del peer diventi bloccato.

Viene utilizzata una coppia di flussi unidirezionali anziché un singolo flusso bidirezionale. Ciò consente a entrambi i peer di inviare dati non appena sono in grado. A seconda che 0-RTT sia disponibile sulla connessione QUIC, il client o il server potrebbero essere in grado di inviare prima i dati del flusso.

6.2.2. Flussi push (Push Streams)

Il push del server (Server Push) è una funzionalità opzionale introdotta in HTTP/2 che consente a un server di avviare una risposta prima che sia stata effettuata una richiesta. Vedere la sezione 4.6 per maggiori dettagli.

Un flusso push è indicato da un tipo di flusso di 0x01, seguito dall'ID push (Push ID) della promessa che soddisfa, codificato come intero a lunghezza variabile. I dati rimanenti su questo flusso sono costituiti da frame HTTP/3, come definito nella sezione 7.2, e soddisfano un push del server promesso da zero o più risposte HTTP provvisorie seguite da una singola risposta HTTP finale, come definito nella sezione 4.1. Il push del server e gli ID push sono descritti nella sezione 4.6.

Solo i server possono effettuare push; se un server riceve un flusso push avviato dal client, questo DEVE (MUST) essere trattato come un errore di connessione di tipo H3_STREAM_CREATION_ERROR.

Push Stream Header {
Stream Type (i) = 0x01,
Push ID (i),
}

Figura 2: Intestazione del flusso push

Un client NON DOVREBBE (SHOULD NOT) interrompere la lettura su un flusso push prima di leggere l'intestazione del flusso push, poiché ciò potrebbe portare a disaccordo tra client e server su quali ID push sono già stati consumati.

Ogni ID push DEVE (MUST) essere utilizzato solo una volta in un'intestazione del flusso push. Se un client rileva che un'intestazione del flusso push include un ID push che è stato utilizzato in un'altra intestazione del flusso push, il client DEVE (MUST) trattare questo come un errore di connessione di tipo H3_ID_ERROR.

6.2.3. Tipi di flusso riservati (Reserved Stream Types)

I tipi di flusso del formato 0x1f * N + 0x21 per valori interi non negativi di N sono riservati per esercitare il requisito che i tipi sconosciuti vengano ignorati. Questi flussi non hanno semantica e possono essere inviati quando è desiderato il padding a livello di applicazione. POSSONO (MAY) anche essere inviati su connessioni in cui non vengono attualmente trasferiti dati. Gli endpoint NON DEVONO (MUST NOT) considerare che questi flussi abbiano alcun significato alla ricezione.

Il payload e la lunghezza del flusso vengono selezionati in qualsiasi modo scelga l'implementazione mittente. Quando si invia un tipo di flusso riservato, l'implementazione PUÒ (MAY) terminare il flusso in modo pulito o reimpostarlo. Quando si reimposta il flusso, DOVREBBE (SHOULD) essere utilizzato il codice di errore H3_NO_ERROR o un codice di errore riservato (sezione 8.1).