4. HTTP Frames (Trames HTTP)
Une fois la connexion HTTP/2 établie, les points de terminaison peuvent commencer à échanger des trames.
4.1. Frame Format (Format de trame)
Toutes les trames commencent par un en-tête fixe de 9 octets suivi d'une charge utile de trame (Frame Payload) de longueur variable.
HTTP Frame {
Length (24),
Type (8),
Flags (8),
Reserved (1),
Stream Identifier (31),
Frame Payload (..),
}
Figure 1 : Disposition de la trame
Les champs de l'en-tête de trame sont définis comme suit :
Length (Longueur) : La longueur de la charge utile de la trame exprimée sous forme d'entier non signé de 24 bits en unités d'octets. Les valeurs supérieures à 2^14 (16 384) ne doivent pas (MUST NOT) être envoyées à moins que le récepteur n'ait défini une valeur plus grande pour SETTINGS_MAX_FRAME_SIZE.
Les 9 octets de l'en-tête de trame ne sont pas inclus dans cette valeur.
Type : Le type 8 bits de la trame. Le type de trame détermine le format et la sémantique de la trame. Les trames définies dans ce document sont listées dans la section 6. Les implémentations doivent (MUST) ignorer et rejeter les trames de types inconnus.
Flags (Drapeaux) : Un champ de 8 bits réservé aux drapeaux booléens spécifiques au type de trame.
Les drapeaux se voient attribuer une sémantique spécifique au type de trame indiqué. Les drapeaux non utilisés sont ceux qui n'ont pas de sémantique définie pour un type de trame particulier. Les drapeaux non utilisés doivent (MUST) être ignorés à la réception et doivent (MUST) rester non définis (0x00) lors de l'envoi.
Reserved (Réservé) : Un champ réservé de 1 bit. La sémantique de ce bit n'est pas définie, et le bit doit (MUST) rester non défini (0x00) lors de l'envoi et doit (MUST) être ignoré lors de la réception.
Stream Identifier (Identifiant de flux) : Un identifiant de flux (voir section 5.1.1) exprimé sous forme d'entier non signé de 31 bits. La valeur 0x00 est réservée pour les trames associées à la connexion dans son ensemble par opposition à un flux individuel.
La structure et le contenu de la charge utile de la trame dépendent entièrement du type de trame.
4.2. Frame Size (Taille de trame)
La taille de la charge utile d'une trame est limitée par la taille maximale qu'un récepteur annonce dans le paramètre SETTINGS_MAX_FRAME_SIZE. Ce paramètre peut avoir n'importe quelle valeur entre 2^14 (16 384) et 2^24-1 (16 777 215) octets, inclus.
Toutes les implémentations doivent (MUST) être capables de recevoir et de traiter au minimum des trames d'une longueur maximale de 2^14 octets, plus l'en-tête de trame de 9 octets (section 4.1). La taille de l'en-tête de trame n'est pas incluse lors de la description des tailles de trame.
Note : Certains types de trames, tels que PING (section 6.7), imposent des limites supplémentaires sur la quantité de données de charge utile de trame autorisée.
Un point de terminaison doit (MUST) envoyer un code d'erreur FRAME_SIZE_ERROR si une trame dépasse la taille définie dans SETTINGS_MAX_FRAME_SIZE, dépasse toute limite définie pour le type de trame, ou est trop petite pour contenir des données de trame obligatoires. Une erreur de taille de trame dans une trame qui pourrait modifier l'état de l'ensemble de la connexion doit (MUST) être traitée comme une erreur de connexion (section 5.4.1) ; cela inclut toute trame transportant un bloc de champs (Field Block, section 4.3) (c'est-à-dire HEADERS, PUSH_PROMISE et CONTINUATION), une trame SETTINGS et toute trame avec un identifiant de flux de 0.
Les points de terminaison ne sont pas obligés d'utiliser tout l'espace disponible dans une trame. La réactivité peut être améliorée en utilisant des trames plus petites que la taille maximale autorisée. L'envoi de grandes trames peut entraîner des retards dans l'envoi de trames sensibles au temps (telles que RST_STREAM, WINDOW_UPDATE ou PRIORITY), qui, si elles sont bloquées par la transmission d'une grande trame, pourraient affecter les performances.
4.3. Field Section Compression and Decompression (Compression et décompression de section de champs)
La compression de section de champs (Field Section Compression) est le processus de compression d'un ensemble de lignes de champs (section 5.2 de [HTTP]) pour former un bloc de champs (Field Block). La décompression de section de champs (Field Section Decompression) est le processus de décodage d'un bloc de champs en un ensemble de lignes de champs. Les détails de la compression et de la décompression de section de champs HTTP/2 sont définis dans [COMPRESSION], qui, pour des raisons historiques, fait référence à ces processus comme compression et décompression d'en-tête.
Chaque bloc de champs transporte toutes les lignes de champs compressées d'une seule section de champs. Les sections d'en-tête incluent également des données de contrôle associées au message sous forme de champs d'en-tête pseudo (Pseudo-Header Fields, section 8.3) qui utilisent le même format qu'une ligne de champ.
Note : RFC 7540 [RFC7540] utilisait le terme "bloc d'en-tête (Header Block)" à la place du terme plus générique "bloc de champs (Field Block)".
Les blocs de champs transportent des données de contrôle et des sections d'en-tête pour les requêtes, les réponses, les requêtes promises et les réponses poussées (voir section 8.4). Tous ces messages, à l'exception des réponses intermédiaires et des requêtes contenues dans les trames PUSH_PROMISE (section 6.6), peuvent éventuellement inclure un bloc de champs qui transporte une section de trailer.
Une section de champs est une collection de lignes de champs. Chacune des lignes de champs d'un bloc de champs transporte une seule valeur. Le bloc de champs sérialisé est ensuite divisé en une ou plusieurs séquences d'octets, appelées fragments de bloc de champs (Field Block Fragments). Le premier fragment de bloc de champs est transmis dans la charge utile de trame de HEADERS (section 6.2) ou PUSH_PROMISE (section 6.6), chacun pouvant être suivi de trames CONTINUATION (section 6.10) pour transporter les fragments de bloc de champs suivants.
Le champ d'en-tête Cookie [COOKIE] est traité spécialement par le mappage HTTP (voir section 8.2.3).
Un point de terminaison récepteur réassemble le bloc de champs en concaténant ses fragments, puis décompresse le bloc pour reconstruire la section de champs.
Une section de champs complète consiste en :
-
une seule trame HEADERS ou PUSH_PROMISE, avec le drapeau END_HEADERS défini, ou
-
une trame HEADERS ou PUSH_PROMISE avec le drapeau END_HEADERS non défini et une ou plusieurs trames CONTINUATION, où la dernière trame CONTINUATION a le drapeau END_HEADERS défini.
Chaque bloc de champs est traité comme une unité discrète. Les blocs de champs doivent (MUST) être transmis comme une séquence contiguë de trames, sans trames entrelacées d'aucun autre type ou d'aucun autre flux. La dernière trame d'une séquence de trames HEADERS ou CONTINUATION a le drapeau END_HEADERS défini. La dernière trame d'une séquence de trames PUSH_PROMISE ou CONTINUATION a le drapeau END_HEADERS défini. Cela permet à un bloc de champs d'être logiquement équivalent à une seule trame.
Les fragments de bloc de champs ne peuvent être envoyés que comme charge utile de trame des trames HEADERS, PUSH_PROMISE ou CONTINUATION car ces trames transportent des données qui peuvent modifier le contexte de compression maintenu par un récepteur. Un point de terminaison recevant des trames HEADERS, PUSH_PROMISE ou CONTINUATION doit réassembler les blocs de champs et effectuer la décompression même si les trames doivent être rejetées. Un récepteur doit (MUST) terminer la connexion avec une erreur de connexion (section 5.4.1) de type COMPRESSION_ERROR s'il ne décompresse pas un bloc de champs.
Une erreur de décodage dans un bloc de champs doit (MUST) être traitée comme une erreur de connexion (section 5.4.1) de type COMPRESSION_ERROR.
4.3.1. Compression State (État de compression)
La compression de champs est avec état. Chaque point de terminaison a un contexte d'encodeur HPACK et un contexte de décodeur HPACK qui sont utilisés pour encoder et décoder tous les blocs de champs sur une connexion. La section 4 de [COMPRESSION] définit la table dynamique, qui est l'état principal pour chaque contexte.
La table dynamique a une taille maximale définie par un décodeur HPACK. Un point de terminaison communique la taille choisie par son contexte de décodeur HPACK en utilisant le paramètre SETTINGS_HEADER_TABLE_SIZE ; voir section 6.5.2. Lorsqu'une connexion est établie, la taille de la table dynamique pour le décodeur et l'encodeur HPACK aux deux points de terminaison commence à 4 096 octets, la valeur initiale du paramètre SETTINGS_HEADER_TABLE_SIZE.
Toute modification de la valeur maximale définie en utilisant SETTINGS_HEADER_TABLE_SIZE prend effet lorsque le point de terminaison accuse réception des paramètres (section 6.5.3). L'encodeur HPACK à ce point de terminaison peut définir la table dynamique à n'importe quelle taille jusqu'à la valeur maximale définie par le décodeur. Un encodeur HPACK déclare la taille de la table dynamique avec une instruction de mise à jour de taille de table dynamique (Dynamic Table Size Update, section 6.3 de [COMPRESSION]).
Une fois qu'un point de terminaison accuse réception d'une modification de SETTINGS_HEADER_TABLE_SIZE qui réduit le maximum en dessous de la taille actuelle de la table dynamique, son encodeur HPACK doit (MUST) commencer le bloc de champs suivant par une instruction de mise à jour de taille de table dynamique qui définit la table dynamique à une taille inférieure ou égale au maximum réduit ; voir section 4.2 de [COMPRESSION]. Un point de terminaison doit (MUST) traiter un bloc de champs qui suit un accusé de réception de la réduction de la taille maximale de la table dynamique comme une erreur de connexion (section 5.4.1) de type COMPRESSION_ERROR s'il ne commence pas par une instruction de mise à jour de taille de table dynamique conforme.
Note : Les implémenteurs sont informés que la réduction de la valeur de SETTINGS_HEADER_TABLE_SIZE n'est pas largement interopérable. L'utilisation de la préface de connexion pour réduire la valeur en dessous de la valeur initiale de 4 096 est quelque peu mieux prise en charge, mais cela pourrait échouer avec certaines implémentations.