RFC 9114 - HTTP/3
- Statut: Proposed Standard
- Publié: June 2022
- Stream: IETF
- Errata: Pas d'errata
Résumé (Abstract)
Le protocole de transport QUIC (QUIC Transport Protocol) possède plusieurs fonctionnalités souhaitables pour un transport HTTP, telles que le multiplexage de flux (Stream Multiplexing), le contrôle de flux par flux (Per-Stream Flow Control) et l'établissement de connexion à faible latence (Low-Latency Connection Establishment). Ce document décrit un mappage de la sémantique HTTP sur QUIC. Ce document identifie également les fonctionnalités HTTP/2 qui sont englobées par QUIC et décrit comment les extensions HTTP/2 peuvent être portées vers HTTP/3.
Statut de ce mémo (Status of This Memo)
Il s'agit d'un document de piste de normes Internet.
Ce document est un produit du groupe de travail sur l'ingénierie Internet (IETF). Il représente le consensus de la communauté IETF. Il a fait l'objet d'un examen public et a été approuvé pour publication par le groupe de pilotage de l'ingénierie Internet (IESG). De plus amples informations sur les normes Internet sont disponibles dans la section 2 de la RFC 7841.
Des informations sur l'état actuel de ce document, les errata et la manière de fournir des commentaires peuvent être obtenues à l'adresse https://www.rfc-editor.org/info/rfc9114.
Table des matières (Table of Contents)
Chapitres principaux
- 1. Introduction
- 2. HTTP/3 Protocol Overview (Aperçu du protocole HTTP/3)
- 3. Connection Setup and Management (Configuration et gestion de la connexion)
- 4. Expressing HTTP Semantics in HTTP/3 (Expression de la sémantique HTTP dans HTTP/3)
- 5. Connection Closure (Fermeture de connexion)
- 6. Stream Mapping and Usage (Mappage et utilisation des flux)
- 7. HTTP Framing Layer (Couche de tramage HTTP)
- 8. Error Handling (Gestion des erreurs)
- 9. Extensions to HTTP/3 (Extensions à HTTP/3)
- 10. Security Considerations (Considérations de sécurité)
- 11. IANA Considerations (Considérations IANA)
- 12. References (Références)
Annexes
Ressources connexes
- Texte officiel : RFC 9114
- Page officielle : RFC 9114 DataTracker
- Errata : RFC Editor Errata
1. Introduction
La sémantique HTTP (HTTP Semantics) ([HTTP]) est utilisée pour une large gamme de services sur Internet. Cette sémantique a été le plus couramment utilisée avec HTTP/1.1 et HTTP/2. HTTP/1.1 a été utilisé sur une variété de couches de transport et de session, tandis que HTTP/2 a été principalement utilisé avec TLS sur TCP. HTTP/3 prend en charge la même sémantique sur un nouveau protocole de transport : QUIC.
1.1. Prior Versions of HTTP (Versions antérieures de HTTP)
HTTP/1.1 ([HTTP/1.1]) utilise des champs de texte délimités par des espaces pour transmettre les messages HTTP. Bien que ces échanges soient lisibles par l'homme, l'utilisation d'espaces pour le formatage des messages entraîne une complexité d'analyse et une tolérance excessive des comportements variants.
Parce que HTTP/1.1 n'inclut pas de couche de multiplexage (Multiplexing Layer), plusieurs connexions TCP sont souvent utilisées pour traiter les requêtes en parallèle. Cependant, cela a un impact négatif sur le contrôle de congestion (Congestion Control) et l'efficacité du réseau, car TCP ne partage pas le contrôle de congestion entre plusieurs connexions.
HTTP/2 ([HTTP/2]) a introduit une couche de tramage binaire (Binary Framing) et de multiplexage pour améliorer la latence sans modifier la couche de transport. Cependant, comme la nature parallèle du multiplexage de HTTP/2 n'est pas visible pour les mécanismes de récupération de perte de TCP (Loss Recovery Mechanisms), un paquet perdu ou réordonné provoque un blocage (Stall) de toutes les transactions actives, que cette transaction ait été directement impactée par le paquet perdu ou non.
1.2. Delegation to QUIC (Délégation à QUIC)
Le protocole de transport QUIC (QUIC Transport Protocol) intègre le multiplexage de flux (Stream Multiplexing) et le contrôle de flux par flux (Per-Stream Flow Control), similaire à celui fourni par la couche de tramage HTTP/2. En fournissant une fiabilité (Reliability) au niveau du flux et un contrôle de congestion sur l'ensemble de la connexion, QUIC a la capacité d'améliorer les performances de HTTP par rapport à un mappage TCP. QUIC intègre également TLS 1.3 ([TLS]) au niveau de la couche de transport, offrant une confidentialité (Confidentiality) et une intégrité (Integrity) comparables à l'exécution de TLS sur TCP, avec la latence d'établissement de connexion améliorée de TCP Fast Open ([TFO]).
Ce document définit HTTP/3 : un mappage de la sémantique HTTP sur le protocole de transport QUIC, s'appuyant fortement sur la conception de HTTP/2. HTTP/3 s'appuie sur QUIC pour fournir la confidentialité et la protection de l'intégrité des données, l'authentification des pairs (Peer Authentication) et une livraison fiable, ordonnée et par flux. Tout en déléguant les problèmes de durée de vie des flux (Stream Lifetime) et de contrôle de flux à QUIC, un tramage binaire similaire au tramage HTTP/2 est utilisé sur chaque flux. Certaines fonctionnalités HTTP/2 sont subsumées par QUIC, tandis que d'autres fonctionnalités sont implémentées au-dessus de QUIC.
QUIC est décrit dans [QUIC-TRANSPORT]. Pour une description complète de HTTP/2, voir [HTTP/2].
2. HTTP/3 Protocol Overview (Aperçu du protocole HTTP/3)
HTTP/3 fournit un transport pour la sémantique HTTP en utilisant le protocole de transport QUIC (QUIC Transport Protocol) et une couche de tramage interne (Framing Layer) similaire à HTTP/2.
Une fois qu'un client sait qu'un serveur HTTP/3 existe à un certain point de terminaison, il ouvre une connexion QUIC. QUIC fournit la négociation de protocole (Protocol Negotiation), le multiplexage basé sur les flux (Stream-Based Multiplexing) et le contrôle de flux (Flow Control). La découverte d'un point de terminaison HTTP/3 est décrite dans la section 3.1.
Dans chaque flux, l'unité de base de communication HTTP/3 est une trame (Frame) (section 7.2). Chaque type de trame a un objectif différent. Par exemple, les trames HEADERS et DATA forment la base des requêtes et réponses HTTP (section 4.1). Les trames qui s'appliquent à l'ensemble de la connexion sont transmises sur un flux de contrôle dédié (Control Stream).
Le multiplexage des requêtes est effectué en utilisant l'abstraction de flux QUIC (Stream Abstraction), qui est décrite dans la section 2 de [QUIC-TRANSPORT]. Chaque paire requête-réponse consomme un seul flux QUIC. Les flux sont indépendants les uns des autres, de sorte qu'un flux bloqué ou subissant une perte de paquets n'empêche pas la progression des autres flux.
Le push serveur (Server Push) est un mode d'interaction introduit dans HTTP/2 ([HTTP/2]) qui permet à un serveur de pousser un échange requête-réponse vers un client en anticipation de la requête indiquée par le client. Cela fait un compromis entre l'utilisation du réseau et un gain de latence potentiel. Plusieurs trames HTTP/3 sont utilisées pour gérer le push serveur, telles que PUSH_PROMISE, MAX_PUSH_ID et CANCEL_PUSH.
Comme dans HTTP/2, les champs de requête et de réponse (Fields) sont compressés pour la transmission. Parce que HPACK ([HPACK]) s'appuie sur la transmission ordonnée des sections de champs compressés (Field Sections) (une garantie non fournie par QUIC), HTTP/3 remplace HPACK par QPACK ([QPACK]). QPACK utilise des flux unidirectionnels séparés pour modifier et suivre l'état de la table de champs (Field Table State), tandis que les sections de champs encodées font référence à l'état de la table sans le modifier.
2.1. Document Organization (Organisation du document)
Les sections suivantes fournissent un aperçu détaillé du cycle de vie d'une connexion HTTP/3 :
-
"Connection Setup and Management" (Configuration et gestion de la connexion) (section 3) couvre la manière dont un point de terminaison HTTP/3 est découvert et une connexion HTTP/3 est établie.
-
"Expressing HTTP Semantics in HTTP/3" (Expression de la sémantique HTTP dans HTTP/3) (section 4) décrit comment la sémantique HTTP est exprimée à l'aide de trames.
-
"Connection Closure" (Fermeture de connexion) (section 5) décrit comment les connexions HTTP/3 sont terminées, soit gracieusement, soit brusquement.
Les détails du protocole filaire (Wire Protocol) et les interactions avec le transport sont décrits dans les sections suivantes :
-
"Stream Mapping and Usage" (Mappage et utilisation des flux) (section 6) décrit la manière dont les flux QUIC sont utilisés.
-
"HTTP Framing Layer" (Couche de tramage HTTP) (section 7) décrit les trames utilisées sur la plupart des flux.
-
"Error Handling" (Gestion des erreurs) (section 8) décrit comment les conditions d'erreur sont traitées et exprimées, soit sur un flux particulier, soit pour la connexion dans son ensemble.
Des ressources supplémentaires sont fournies dans les sections finales :
-
"Extensions to HTTP/3" (Extensions à HTTP/3) (section 9) décrit comment de nouvelles capacités peuvent être ajoutées dans de futurs documents.
-
Une comparaison plus détaillée entre HTTP/2 et HTTP/3 peut être trouvée dans l'annexe A.
2.2. Conventions and Terminology (Conventions et terminologie)
Les mots-clés "MUST" (doit), "MUST NOT" (ne doit pas), "REQUIRED" (requis), "SHALL" (doit), "SHALL NOT" (ne doit pas), "SHOULD" (devrait), "SHOULD NOT" (ne devrait pas), "RECOMMENDED" (recommandé), "NOT RECOMMENDED" (non recommandé), "MAY" (peut) et "OPTIONAL" (optionnel) dans ce document doivent être interprétés comme décrit dans BCP 14 [RFC2119] [RFC8174] quand, et seulement quand, ils apparaissent en majuscules, comme indiqué ici.
Ce document utilise l'encodage d'entiers de longueur variable (Variable-Length Integer Encoding) de [QUIC-TRANSPORT].
Les termes suivants sont utilisés :
abort (interruption) : Une terminaison abrupte d'une connexion ou d'un flux, éventuellement due à une condition d'erreur.
client : Le point de terminaison qui initie une connexion HTTP/3. Les clients envoient des requêtes HTTP et reçoivent des réponses HTTP.
connection (connexion) : Une connexion de couche transport entre deux points de terminaison utilisant QUIC comme protocole de transport.
connection error (erreur de connexion) : Une erreur qui affecte l'ensemble de la connexion HTTP/3.
endpoint (point de terminaison) : Le client ou le serveur de la connexion.
frame (trame) : La plus petite unité de communication sur un flux dans HTTP/3, composée d'un en-tête et d'une séquence d'octets de longueur variable structurée selon le type de trame.
Des éléments de protocole appelés "trames" existent à la fois dans ce document et dans [QUIC-TRANSPORT]. Lorsque des trames de [QUIC-TRANSPORT] sont référencées, le nom de la trame sera préfixé par "QUIC". Par exemple, "QUIC CONNECTION_CLOSE frames". Les références sans ce préfixe font référence aux trames définies dans la section 7.2.
HTTP/3 connection (connexion HTTP/3) : Une connexion QUIC où le protocole d'application négocié est HTTP/3.
peer (pair) : Un point de terminaison. Lors de la discussion d'un point de terminaison particulier, "peer" fait référence au point de terminaison distant du sujet principal de discussion.
receiver (récepteur) : Un point de terminaison qui reçoit des trames.
sender (émetteur) : Un point de terminaison qui transmet des trames.
server (serveur) : Le point de terminaison qui accepte une connexion HTTP/3. Les serveurs reçoivent des requêtes HTTP et envoient des réponses HTTP.
stream (flux) : Un flux d'octets bidirectionnel ou unidirectionnel (Bytestream) fourni par le transport QUIC. Tous les flux au sein d'une connexion HTTP/3 peuvent être considérés comme des "flux HTTP/3", mais plusieurs types de flux sont définis dans HTTP/3.
stream error (erreur de flux) : Une erreur au niveau de l'application sur le flux individuel.
Le terme "content" (contenu) est défini dans la section 6.4 de [HTTP].
Enfin, les termes "resource" (ressource), "message", "user agent" (agent utilisateur), "origin server" (serveur d'origine), "gateway" (passerelle), "intermediary" (intermédiaire), "proxy" et "tunnel" sont définis dans la section 3 de [HTTP].
Les diagrammes de paquets (Packet Diagrams) dans ce document utilisent le format défini dans la section 1.3 de [QUIC-TRANSPORT] pour illustrer l'ordre et la taille des champs.
3. Connection Setup and Management (Configuration et gestion de la connexion)
3.1. Discovering an HTTP/3 Endpoint (Découverte d'un point de terminaison HTTP/3)
HTTP repose sur la notion de réponse autoritaire (Authoritative Response) : une réponse qui a été déterminée comme étant la réponse la plus appropriée pour cette requête, compte tenu de l'état de la ressource cible au moment de l'origine du message de réponse par (ou sous la direction de) le serveur d'origine identifié dans l'URI cible. La localisation d'un serveur autoritaire pour un URI HTTP est discutée dans la section 4.3 de [HTTP].
Le schéma "https" associe l'autorité à la possession d'un certificat que le client considère comme digne de confiance pour l'hôte identifié par le composant d'autorité (Authority Component) de l'URI. Lors de la réception d'un certificat de serveur dans la poignée de main TLS, le client doit (MUST) vérifier que le certificat est une correspondance acceptable pour le serveur d'origine (Origin Server) de l'URI en utilisant le processus décrit dans la section 4.3.4 de [HTTP]. Si le certificat ne peut pas être vérifié par rapport au serveur d'origine de l'URI, le client ne doit pas (MUST NOT) considérer le serveur comme autoritaire pour cette origine.
Un client peut (MAY) tenter d'accéder à une ressource avec un URI "https" en résolvant l'identifiant d'hôte en une adresse IP, en établissant une connexion QUIC à cette adresse sur le port indiqué (y compris la validation du certificat de serveur comme décrit ci-dessus), et en envoyant un message de requête HTTP/3 ciblant l'URI au serveur via cette connexion sécurisée. À moins qu'un autre mécanisme ne soit utilisé pour sélectionner HTTP/3, le jeton "h3" est utilisé dans l'extension de négociation de protocole de couche application (Application-Layer Protocol Negotiation, ALPN ; voir [RFC7301]) pendant la poignée de main TLS.
Les problèmes de connectivité (par exemple, le blocage d'UDP) peuvent entraîner un échec d'établissement d'une connexion QUIC ; les clients devraient (SHOULD) tenter d'utiliser des versions basées sur TCP de HTTP dans ce cas.
Les serveurs peuvent (MAY) servir HTTP/3 sur n'importe quel port UDP ; une annonce de service alternatif (Alternative Service Advertisement) inclut toujours un port explicite, et les URI contiennent soit un port explicite, soit un port par défaut associé au schéma.
3.1.1. HTTP Alternative Services (Services alternatifs HTTP)
Une origine HTTP peut annoncer la disponibilité d'un point de terminaison HTTP/3 équivalent via le champ d'en-tête de réponse HTTP Alt-Svc ou la trame HTTP/2 ALTSVC ([ALTSVC]) en utilisant le jeton ALPN "h3".
Par exemple, une origine pourrait indiquer dans une réponse HTTP que HTTP/3 était disponible sur le port UDP 50781 au même nom d'hôte en incluant le champ d'en-tête suivant :
Alt-Svc: h3=":50781"
À la réception d'un enregistrement Alt-Svc indiquant le support HTTP/3, un client peut (MAY) tenter d'établir une connexion QUIC vers l'hôte et le port indiqués ; si cette connexion réussit, le client peut envoyer des requêtes HTTP en utilisant le mappage décrit dans ce document.
3.1.2. Other Schemes (Autres schémas)
Bien que HTTP soit indépendant du protocole de transport, le schéma "http" associe l'autorité à la capacité de recevoir des connexions TCP sur le port indiqué de tout hôte identifié dans le composant d'autorité. Parce que HTTP/3 n'utilise pas TCP, HTTP/3 ne peut pas être utilisé pour un accès direct au serveur autoritaire pour une ressource identifiée par un URI "http". Cependant, des extensions de protocole telles que [ALTSVC] permettent au serveur autoritaire d'identifier d'autres services qui sont également autoritaires et qui pourraient être accessibles via HTTP/3.
Avant de faire des requêtes pour une origine dont le schéma n'est pas "https", le client doit (MUST) s'assurer que le serveur est disposé à servir ce schéma. Pour les origines dont le schéma est "http", une méthode expérimentale pour accomplir cela est décrite dans [RFC8164]. D'autres mécanismes pourraient être définis pour divers schémas à l'avenir.
3.2. Connection Establishment (Établissement de la connexion)
HTTP/3 s'appuie sur QUIC version 1 comme transport sous-jacent. L'utilisation d'autres versions de transport QUIC avec HTTP/3 peut (MAY) être définie par des spécifications futures.
QUIC version 1 utilise TLS version 1.3 ou supérieure comme protocole de poignée de main (Handshake Protocol). Les clients HTTP/3 doivent (MUST) prendre en charge un mécanisme pour indiquer l'hôte cible au serveur pendant la poignée de main TLS. Si le serveur est identifié par un nom de domaine ([DNS-TERMS]), les clients doivent (MUST) envoyer l'extension TLS d'indication du nom de serveur (Server Name Indication, SNI ; [RFC6066]) sauf si un mécanisme alternatif pour indiquer l'hôte cible est utilisé.
Les connexions QUIC sont établies comme décrit dans [QUIC-TRANSPORT]. Pendant l'établissement de la connexion, le support HTTP/3 est indiqué en sélectionnant le jeton ALPN "h3" dans la poignée de main TLS. Le support d'autres protocoles de couche application peut (MAY) être offert dans la même poignée de main.
Alors que les options de niveau connexion relatives au protocole QUIC de base sont définies dans la poignée de main cryptographique initiale, les paramètres spécifiques à HTTP/3 sont transmis dans la trame SETTINGS. Après l'établissement de la connexion QUIC, une trame SETTINGS doit (MUST) être envoyée par chaque point de terminaison en tant que trame initiale de leur flux de contrôle HTTP (HTTP Control Stream) respectif.
3.3. Connection Reuse (Réutilisation de la connexion)
Les connexions HTTP/3 sont persistantes sur plusieurs requêtes. Pour de meilleures performances, on s'attend à ce que les clients ne ferment pas les connexions jusqu'à ce qu'il soit déterminé qu'aucune communication supplémentaire avec un serveur n'est nécessaire (par exemple, lorsqu'un utilisateur quitte une page Web particulière) ou jusqu'à ce que le serveur ferme la connexion.
Une fois qu'une connexion à un point de terminaison de serveur existe, cette connexion peut (MAY) être réutilisée pour des requêtes avec plusieurs composants d'autorité URI différents. Pour utiliser une connexion existante pour une nouvelle origine, les clients doivent (MUST) valider le certificat présenté par le serveur pour le nouveau serveur d'origine en utilisant le processus décrit dans la section 4.3.4 de [HTTP]. Cela implique que les clients devront conserver le certificat de serveur et toute information supplémentaire nécessaire pour vérifier ce certificat ; les clients qui ne le font pas seront incapables de réutiliser la connexion pour des origines supplémentaires.
Si le certificat n'est pas acceptable pour la nouvelle origine pour quelque raison que ce soit, la connexion ne doit pas (MUST NOT) être réutilisée et une nouvelle connexion devrait (SHOULD) être établie pour la nouvelle origine. Si la raison pour laquelle le certificat ne peut pas être vérifié pourrait s'appliquer à d'autres origines déjà associées à la connexion, le client devrait (SHOULD) revalider le certificat de serveur pour ces origines. Par exemple, si la validation d'un certificat échoue parce que le certificat a expiré ou été révoqué, cela pourrait être utilisé pour invalider toutes les autres origines pour lesquelles ce certificat a été utilisé pour établir l'autorité.
Les clients ne devraient pas (SHOULD NOT) ouvrir plus d'une connexion HTTP/3 vers une adresse IP et un port UDP donnés, où l'adresse IP et le port pourraient être dérivés d'un URI, d'un service alternatif sélectionné ([ALTSVC]), d'un proxy configuré, ou de la résolution de nom de l'un de ceux-ci. Un client peut (MAY) ouvrir plusieurs connexions HTTP/3 vers la même adresse IP et le même port UDP en utilisant différentes configurations de transport ou TLS mais devrait (SHOULD) éviter de créer plusieurs connexions avec la même configuration.
Les serveurs sont encouragés à maintenir les connexions HTTP/3 ouvertes aussi longtemps que possible mais sont autorisés à terminer les connexions inactives (Idle Connections) si nécessaire. Lorsque l'un ou l'autre point de terminaison choisit de fermer la connexion HTTP/3, le point de terminaison qui termine devrait (SHOULD) d'abord envoyer une trame GOAWAY (section 5.2) afin que les deux points de terminaison puissent déterminer de manière fiable si les trames précédemment envoyées ont été traitées et terminer ou achever gracieusement toutes les tâches restantes nécessaires.
Un serveur qui ne souhaite pas que les clients réutilisent les connexions HTTP/3 pour une origine particulière peut indiquer qu'il n'est pas autoritaire pour une requête en envoyant un code d'état 421 (Misdirected Request, Requête mal dirigée) en réponse à la requête ; voir section 7.4 de [HTTP].
4. Expression de la sémantique HTTP dans HTTP/3 (Expressing HTTP Semantics in HTTP/3)
4.1. Encadrement des messages HTTP (HTTP Message Framing)
Un client envoie une requête HTTP sur un flux de requête (Request Stream), qui est un flux QUIC bidirectionnel initié par le client ; voir la section 6.1. Un client DOIT (MUST) envoyer une seule requête sur un flux donné. Un serveur envoie zéro ou plusieurs réponses HTTP intermédiaires (Interim HTTP Responses) sur le même flux que la requête, suivies d'une seule réponse HTTP finale (Final HTTP Response), comme détaillé ci-dessous. Voir la section 15 de [HTTP] pour une description des réponses HTTP intermédiaires et finales.
Les réponses poussées (Pushed Responses) sont envoyées sur un flux QUIC unidirectionnel initié par le serveur ; voir la section 6.2.2. Un serveur envoie zéro ou plusieurs réponses HTTP intermédiaires, suivies d'une seule réponse HTTP finale, de la même manière qu'une réponse standard. Le push est décrit plus en détail dans la section 4.6.
Sur un flux donné, la réception de plusieurs requêtes ou la réception d'une réponse HTTP supplémentaire suivant une réponse HTTP finale DOIT (MUST) être traitée comme malformée (Malformed).
Un message HTTP (requête ou réponse) se compose de :
-
la section d'en-tête (Header Section), incluant les données de contrôle du message, envoyée comme une seule trame HEADERS,
-
optionnellement, le contenu (Content), s'il est présent, envoyé comme une série de trames DATA, et
-
optionnellement, la section de fin (Trailer Section), si présente, envoyée comme une seule trame HEADERS.
Les sections d'en-tête et de fin sont décrites dans les sections 6.3 et 6.5 de [HTTP] ; le contenu est décrit dans la section 6.4 de [HTTP].
La réception d'une séquence de trames invalide DOIT (MUST) être traitée comme une erreur de connexion (Connection Error) de type H3_FRAME_UNEXPECTED. En particulier, une trame DATA avant toute trame HEADERS, ou une trame HEADERS ou DATA après la trame HEADERS de fin, est considérée comme invalide. D'autres types de trames, en particulier les types de trames inconnus, peuvent être autorisés sous réserve de leurs propres règles ; voir la section 9.
Un serveur PEUT (MAY) envoyer une ou plusieurs trames PUSH_PROMISE avant, après ou entrelacées avec les trames d'un message de réponse. Ces trames PUSH_PROMISE ne font pas partie de la réponse ; voir la section 4.6 pour plus de détails. Les trames PUSH_PROMISE ne sont pas autorisées sur les flux de push ; une réponse poussée qui inclut des trames PUSH_PROMISE DOIT (MUST) être traitée comme une erreur de connexion de type H3_FRAME_UNEXPECTED.
Les trames de types inconnus (section 9), y compris les trames réservées (Reserved Frames) (section 7.2.8), PEUVENT (MAY) être envoyées sur un flux de requête ou de push avant, après ou entrelacées avec les autres trames décrites dans cette section.
Les trames HEADERS et PUSH_PROMISE peuvent faire référence à des mises à jour de la table dynamique QPACK (Dynamic Table). Bien que ces mises à jour ne fassent pas directement partie de l'échange de messages, elles doivent être reçues et traitées avant que le message puisse être consommé. Voir la section 4.2 pour plus de détails.
Les codages de transfert (Transfer Codings) (voir la section 7 de [HTTP/1.1]) ne sont pas définis pour HTTP/3 ; le champ d'en-tête Transfer-Encoding NE DOIT PAS (MUST NOT) être utilisé.
Une réponse PEUT (MAY) se composer de plusieurs messages si et seulement si une ou plusieurs réponses intermédiaires (1xx ; voir la section 15.2 de [HTTP]) précèdent une réponse finale à la même requête. Les réponses intermédiaires ne contiennent pas de contenu ni de sections de fin.
Un échange de requête/réponse HTTP consomme entièrement un flux QUIC bidirectionnel initié par le client. Après l'envoi d'une requête, un client DOIT (MUST) fermer le flux pour l'envoi. Sauf utilisation de la méthode CONNECT (voir la section 4.4), les clients NE DOIVENT PAS (MUST NOT) rendre la fermeture du flux dépendante de la réception d'une réponse à leur requête. Après l'envoi d'une réponse finale, le serveur DOIT (MUST) fermer le flux pour l'envoi. À ce stade, le flux QUIC est entièrement fermé.
Lorsqu'un flux est fermé, cela indique la fin du message HTTP final. Étant donné que certains messages sont volumineux ou non bornés, les points de terminaison DEVRAIENT (SHOULD) commencer à traiter les messages HTTP partiels une fois qu'une partie suffisante du message a été reçue pour progresser. Si un flux initié par le client se termine sans suffisamment de message HTTP pour fournir une réponse complète, le serveur DEVRAIT (SHOULD) interrompre son flux de réponse avec le code d'erreur H3_REQUEST_INCOMPLETE.
Un serveur peut envoyer une réponse complète avant que le client n'envoie une requête entière si la réponse ne dépend d'aucune partie de la requête qui n'a pas été envoyée et reçue. Lorsque le serveur n'a pas besoin de recevoir le reste de la requête, il PEUT (MAY) interrompre la lecture du flux de requête, envoyer une réponse complète et fermer proprement la partie envoi du flux. Le code d'erreur H3_NO_ERROR DEVRAIT (SHOULD) être utilisé lors de la demande au client d'arrêter d'envoyer sur le flux de requête. Les clients NE DOIVENT PAS (MUST NOT) rejeter les réponses complètes à la suite de l'interruption abrupte de leur requête, bien que les clients puissent toujours rejeter les réponses à leur discrétion pour d'autres raisons. Si le serveur envoie une réponse partielle ou complète mais n'interrompt pas la lecture de la requête, les clients DEVRAIENT (SHOULD) continuer à envoyer le contenu de la requête et fermer le flux normalement.
4.1.1. Annulation et rejet de requête (Request Cancellation and Rejection)
Une fois qu'un flux de requête a été ouvert, la requête PEUT (MAY) être annulée par l'un ou l'autre des points de terminaison. Les clients annulent les requêtes si la réponse ne présente plus d'intérêt ; les serveurs annulent les requêtes s'ils ne peuvent pas ou choisissent de ne pas répondre. Lorsque cela est possible, il est RECOMMANDÉ (RECOMMENDED) que les serveurs envoient une réponse HTTP avec un code d'état approprié plutôt que d'annuler une requête dont le traitement a déjà commencé.
Les implémentations DEVRAIENT (SHOULD) annuler les requêtes en terminant brusquement toutes les directions d'un flux qui sont encore ouvertes. Pour ce faire, une implémentation réinitialise les parties d'envoi des flux et interrompt la lecture sur les parties de réception des flux ; voir la section 2.4 de [QUIC-TRANSPORT].
Lorsque le serveur annule une requête sans effectuer de traitement d'application, la requête est considérée comme "rejetée" (Rejected). Le serveur DEVRAIT (SHOULD) interrompre son flux de réponse avec le code d'erreur H3_REQUEST_REJECTED. Dans ce contexte, "traité" (Processed) signifie que certaines données du flux ont été transmises à une couche logicielle supérieure qui pourrait avoir pris des mesures en conséquence. Le client peut traiter les requêtes rejetées par le serveur comme si elles n'avaient jamais été envoyées, ce qui permet de les réessayer plus tard.
Les serveurs NE DOIVENT PAS (MUST NOT) utiliser le code d'erreur H3_REQUEST_REJECTED pour les requêtes qui ont été partiellement ou entièrement traitées. Lorsqu'un serveur abandonne une réponse après un traitement partiel, il DEVRAIT (SHOULD) interrompre son flux de réponse avec le code d'erreur H3_REQUEST_CANCELLED.
Le client DEVRAIT (SHOULD) utiliser le code d'erreur H3_REQUEST_CANCELLED pour annuler les requêtes. À la réception de ce code d'erreur, un serveur PEUT (MAY) terminer brusquement la réponse en utilisant le code d'erreur H3_REQUEST_REJECTED si aucun traitement n'a été effectué. Les clients NE DOIVENT PAS (MUST NOT) utiliser le code d'erreur H3_REQUEST_REJECTED, sauf lorsqu'un serveur a demandé la fermeture du flux de requête avec ce code d'erreur.
Si un flux est annulé après avoir reçu une réponse complète, le client PEUT (MAY) ignorer l'annulation et utiliser la réponse. Cependant, si un flux est annulé après avoir reçu une réponse partielle, la réponse NE DEVRAIT PAS (SHOULD NOT) être utilisée. Seules les actions idempotentes (Idempotent Actions) telles que GET, PUT ou DELETE peuvent être réessayées en toute sécurité ; un client NE DEVRAIT PAS (SHOULD NOT) réessayer automatiquement une requête avec une méthode non idempotente à moins qu'il n'ait un moyen de savoir que la sémantique de la requête est idempotente indépendamment de la méthode ou un moyen de détecter que la requête originale n'a jamais été appliquée. Voir la section 9.2.2 de [HTTP] pour plus de détails.
4.1.2. Requêtes et réponses malformées (Malformed Requests and Responses)
Une requête ou une réponse malformée est une séquence de trames par ailleurs valide mais invalide en raison de :
-
la présence de champs interdits ou de champs de pseudo-en-tête (Pseudo-Header Fields),
-
l'absence de champs de pseudo-en-tête obligatoires,
-
des valeurs invalides pour les champs de pseudo-en-tête,
-
des champs de pseudo-en-tête après les champs,
-
une séquence invalide de messages HTTP,
-
l'inclusion de noms de champs en majuscules, ou
-
l'inclusion de caractères invalides dans les noms ou valeurs de champs.
Une requête ou une réponse définie comme ayant du contenu lorsqu'elle contient un champ d'en-tête Content-Length (section 8.6 de [HTTP]) est malformée si la valeur du champ d'en-tête Content-Length n'est pas égale à la somme des longueurs des trames DATA reçues. Une réponse définie comme n'ayant jamais de contenu, même lorsqu'un Content-Length est présent, peut avoir un champ d'en-tête Content-Length non nul même si aucun contenu n'est inclus dans les trames DATA.
Les intermédiaires qui traitent les requêtes ou réponses HTTP (c'est-à-dire tout intermédiaire n'agissant pas comme un tunnel) NE DOIVENT PAS (MUST NOT) transférer une requête ou une réponse malformée. Les requêtes ou réponses malformées détectées DOIVENT (MUST) être traitées comme une erreur de flux (Stream Error) de type H3_MESSAGE_ERROR.
Pour les requêtes malformées, un serveur PEUT (MAY) envoyer une réponse HTTP indiquant l'erreur avant de fermer ou de réinitialiser le flux. Les clients NE DOIVENT PAS (MUST NOT) accepter une réponse malformée. Notez que ces exigences visent à protéger contre plusieurs types d'attaques courantes contre HTTP ; elles sont délibérément strictes car être permissif peut exposer les implémentations à ces vulnérabilités.
4.2. Champs HTTP (HTTP Fields)
Les messages HTTP transportent des métadonnées sous forme d'une série de paires clé-valeur appelées "champs HTTP" (HTTP Fields) ; voir les sections 6.3 et 6.5 de [HTTP]. Pour une liste des champs HTTP enregistrés, voir le "Registre des noms de champs du protocole de transfert hypertexte (HTTP)" (Hypertext Transfer Protocol (HTTP) Field Name Registry) maintenu à https://www.iana.org/assignments/http-fields/. Comme HTTP/2, HTTP/3 a des considérations supplémentaires liées à l'utilisation de caractères dans les noms de champs, au champ d'en-tête Connection et aux champs de pseudo-en-tête.
Les noms de champs sont des chaînes contenant un sous-ensemble de caractères ASCII. Les propriétés des noms et valeurs de champs HTTP sont discutées plus en détail dans la section 5.1 de [HTTP]. Les caractères dans les noms de champs DOIVENT (MUST) être convertis en minuscules avant leur encodage. Une requête ou une réponse contenant des caractères majuscules dans les noms de champs DOIT (MUST) être traitée comme malformée.
HTTP/3 n'utilise pas le champ d'en-tête Connection pour indiquer les champs spécifiques à la connexion ; dans ce protocole, les métadonnées spécifiques à la connexion sont transmises par d'autres moyens. Un point de terminaison NE DOIT PAS (MUST NOT) générer une section de champ HTTP/3 contenant des champs spécifiques à la connexion ; tout message contenant des champs spécifiques à la connexion DOIT (MUST) être traité comme malformé.
La seule exception à cela est le champ d'en-tête TE, qui PEUT (MAY) être présent dans un en-tête de requête HTTP/3 ; lorsqu'il l'est, il NE DOIT PAS (MUST NOT) contenir d'autre valeur que "trailers".
Un intermédiaire transformant un message HTTP/1.x en HTTP/3 DOIT (MUST) supprimer les champs d'en-tête spécifiques à la connexion comme discuté dans la section 7.6.1 de [HTTP], sinon leurs messages seront traités par d'autres points de terminaison HTTP/3 comme malformés.
4.2.1. Compression des champs (Field Compression)
[QPACK] décrit une variation de HPACK qui donne à un encodeur un certain contrôle sur la quantité de blocage en tête de ligne (Head-of-Line Blocking) pouvant être causée par la compression. Cela permet à un encodeur d'équilibrer l'efficacité de compression avec la latence. HTTP/3 utilise QPACK pour compresser les sections d'en-tête et de fin, y compris les données de contrôle présentes dans la section d'en-tête.
Pour permettre une meilleure efficacité de compression, le champ d'en-tête Cookie ([COOKIES]) PEUT (MAY) être divisé en lignes de champ séparées, chacune avec une ou plusieurs paires de cookies (Cookie-Pairs), avant la compression. Si une section de champ décompressée contient plusieurs lignes de champ de cookie, celles-ci DOIVENT (MUST) être concaténées en une seule chaîne d'octets en utilisant le délimiteur de deux octets "; " (ASCII 0x3b, 0x20) avant d'être transmises dans un contexte autre que HTTP/2 ou HTTP/3, tel qu'une connexion HTTP/1.1 ou une application serveur HTTP générique.
4.2.2. Contraintes de taille d'en-tête (Header Size Constraints)
Une implémentation HTTP/3 PEUT (MAY) imposer une limite sur la taille maximale de l'en-tête de message qu'elle acceptera sur un message HTTP individuel. Un serveur qui reçoit une section d'en-tête plus grande que ce qu'il est disposé à traiter peut envoyer un code d'état HTTP 431 (Champs d'en-tête de requête trop grands) (Request Header Fields Too Large) ([RFC6585]). Un client peut rejeter les réponses qu'il ne peut pas traiter. La taille d'une liste de champs est calculée en fonction de la taille non compressée des champs, y compris la longueur du nom et de la valeur en octets plus une surcharge de 32 octets pour chaque champ.
Si une implémentation souhaite informer son pair de cette limite, elle peut être transmise sous forme de nombre d'octets dans le paramètre SETTINGS_MAX_FIELD_SECTION_SIZE. Une implémentation qui a reçu ce paramètre NE DEVRAIT PAS (SHOULD NOT) envoyer un en-tête de message HTTP qui dépasse la taille indiquée, car le pair refusera probablement de le traiter. Cependant, un message HTTP peut traverser un ou plusieurs intermédiaires avant d'atteindre le serveur d'origine ; voir la section 3.7 de [HTTP]. Étant donné que cette limite est appliquée séparément par chaque implémentation qui traite le message, les messages en dessous de cette limite ne sont pas garantis d'être acceptés.
4.3. Données de contrôle HTTP (HTTP Control Data)
Comme HTTP/2, HTTP/3 utilise une série de champs de pseudo-en-tête (Pseudo-Header Fields), où le nom du champ commence par le caractère : (ASCII 0x3a). Ces champs de pseudo-en-tête transmettent les données de contrôle du message ; voir la section 6.2 de [HTTP].
Les champs de pseudo-en-tête ne sont pas des champs HTTP. Les points de terminaison NE DOIVENT PAS (MUST NOT) générer de champs de pseudo-en-tête autres que ceux définis dans ce document. Cependant, une extension pourrait négocier une modification de cette restriction ; voir la section 9.
Les champs de pseudo-en-tête ne sont valides que dans le contexte dans lequel ils sont définis. Les champs de pseudo-en-tête définis pour les requêtes NE DOIVENT PAS (MUST NOT) apparaître dans les réponses ; les champs de pseudo-en-tête définis pour les réponses NE DOIVENT PAS (MUST NOT) apparaître dans les requêtes. Les champs de pseudo-en-tête NE DOIVENT PAS (MUST NOT) apparaître dans les sections de fin. Les points de terminaison DOIVENT (MUST) traiter une requête ou une réponse contenant des champs de pseudo-en-tête non définis ou invalides comme malformée.
Tous les champs de pseudo-en-tête DOIVENT (MUST) apparaître dans la section d'en-tête avant les champs d'en-tête réguliers. Toute requête ou réponse contenant un champ de pseudo-en-tête qui apparaît dans une section d'en-tête après un champ d'en-tête régulier DOIT (MUST) être traitée comme malformée.
4.3.1. Champs de pseudo-en-tête de requête (Request Pseudo-Header Fields)
Les champs de pseudo-en-tête suivants sont définis pour les requêtes :
":method" : Contient la méthode HTTP (HTTP Method) (section 9 de [HTTP])
":scheme" : Contient la partie scheme de l'URI cible (section 3.1 de [URI]).
Le pseudo-en-tête :scheme n'est pas limité aux URI avec les schemes "http" et "https". Un proxy ou une passerelle peut traduire les requêtes pour des schemes non-HTTP, permettant l'utilisation de HTTP pour interagir avec des services non-HTTP.
Voir la section 3.1.2 pour des conseils sur l'utilisation d'un scheme autre que "https".
":authority" : Contient la partie authority de l'URI cible (section 3.2 de [URI]). L'authority NE DOIT PAS (MUST NOT) inclure le sous-composant userinfo obsolète pour les URI de scheme "http" ou "https".
Pour garantir que la ligne de requête HTTP/1.1 peut être reproduite avec précision, ce champ de pseudo-en-tête DOIT (MUST) être omis lors de la traduction à partir d'une requête HTTP/1.1 qui a une cible de requête sous forme spécifique à la méthode ; voir la section 7.1 de [HTTP]. Les clients qui génèrent directement des requêtes HTTP/3 DEVRAIENT (SHOULD) utiliser le champ de pseudo-en-tête :authority au lieu du champ d'en-tête Host. Un intermédiaire qui convertit une requête HTTP/3 en HTTP/1.1 DOIT (MUST) créer un champ Host s'il n'est pas présent dans une requête en copiant la valeur du champ de pseudo-en-tête :authority.
":path" : Contient les parties path et query de l'URI cible (la production "path-absolute" et éventuellement un caractère ? (ASCII 0x3f) suivi de la production "query" ; voir les sections 3.3 et 3.4 de [URI]).
Ce champ de pseudo-en-tête NE DOIT PAS (MUST NOT) être vide pour les URI "http" ou "https" ; les URI "http" ou "https" qui ne contiennent pas de composant path DOIVENT (MUST) inclure une valeur de / (ASCII 0x2f). Une requête OPTIONS qui ne contient pas de composant path inclut la valeur * (ASCII 0x2a) pour le champ de pseudo-en-tête :path ; voir la section 7.1 de [HTTP].
Toutes les requêtes HTTP/3 DOIVENT (MUST) inclure exactement une valeur pour les champs de pseudo-en-tête :method, :scheme et :path, sauf si la requête est une requête CONNECT ; voir la section 4.4.
Si le champ de pseudo-en-tête :scheme identifie un scheme qui a un composant authority obligatoire (y compris "http" et "https"), la requête DOIT (MUST) contenir soit un champ de pseudo-en-tête :authority, soit un champ d'en-tête Host. Si ces champs sont présents, ils NE DOIVENT PAS (MUST NOT) être vides. Si les deux champs sont présents, ils DOIVENT (MUST) contenir la même valeur. Si le scheme n'a pas de composant authority obligatoire et qu'aucun n'est fourni dans la cible de requête, la requête NE DOIT PAS (MUST NOT) contenir le pseudo-en-tête :authority ou les champs d'en-tête Host.
Une requête HTTP qui omet des champs de pseudo-en-tête obligatoires ou contient des valeurs invalides pour ces champs de pseudo-en-tête est malformée.
HTTP/3 ne définit pas de moyen de transporter l'identifiant de version qui est inclus dans la ligne de requête HTTP/1.1. Les requêtes HTTP/3 ont implicitement une version de protocole "3.0".
4.3.2. Champs de pseudo-en-tête de réponse (Response Pseudo-Header Fields)
Pour les réponses, un seul champ de pseudo-en-tête ":status" est défini qui transporte le code d'état HTTP ; voir la section 15 de [HTTP]. Ce champ de pseudo-en-tête DOIT (MUST) être inclus dans toutes les réponses ; sinon, la réponse est malformée (voir la section 4.1.2).
HTTP/3 ne définit pas de moyen de transporter la version ou la phrase de raison (Reason Phrase) qui est incluse dans une ligne d'état HTTP/1.1. Les réponses HTTP/3 ont implicitement une version de protocole "3.0".
4.4. La méthode CONNECT (The CONNECT Method)
La méthode CONNECT demande au destinataire d'établir un tunnel (Tunnel) vers le serveur d'origine de destination identifié par la cible de requête ; voir la section 9.3.6 de [HTTP]. Elle est principalement utilisée avec les proxies HTTP pour établir une session TLS avec un serveur d'origine dans le but d'interagir avec des ressources "https".
Dans HTTP/1.x, CONNECT est utilisé pour convertir une connexion HTTP entière en un tunnel vers un hôte distant. Dans HTTP/2 et HTTP/3, la méthode CONNECT est utilisée pour établir un tunnel sur un seul flux.
Une requête CONNECT DOIT (MUST) être construite comme suit :
-
Le champ de pseudo-en-tête :method est défini sur "CONNECT"
-
Les champs de pseudo-en-tête :scheme et :path sont omis
-
Le champ de pseudo-en-tête :authority contient l'hôte et le port auxquels se connecter (équivalent à la forme authority de la cible de requête des requêtes CONNECT ; voir la section 7.1 de [HTTP]).
Le flux de requête reste ouvert à la fin de la requête pour transporter les données à transférer. Une requête CONNECT qui ne respecte pas ces restrictions est malformée.
Un proxy qui prend en charge CONNECT établit une connexion TCP ([RFC0793]) vers le serveur identifié dans le champ de pseudo-en-tête :authority. Une fois cette connexion établie avec succès, le proxy envoie une trame HEADERS contenant un code d'état de série 2xx au client, tel que défini dans la section 15.3 de [HTTP].
Toutes les trames DATA sur le flux correspondent aux données envoyées ou reçues sur la connexion TCP. La charge utile de toute trame DATA envoyée par le client est transmise par le proxy au serveur TCP ; les données reçues du serveur TCP sont empaquetées dans des trames DATA par le proxy. Notez que la taille et le nombre de segments TCP ne sont pas garantis de correspondre de manière prévisible à la taille et au nombre de trames HTTP DATA ou QUIC STREAM.
Une fois que la méthode CONNECT est terminée, seules les trames DATA sont autorisées à être envoyées sur le flux. Les trames d'extension PEUVENT (MAY) être utilisées si elles sont spécifiquement autorisées par la définition de l'extension. La réception de tout autre type de trame connu DOIT (MUST) être traitée comme une erreur de connexion de type H3_FRAME_UNEXPECTED.
La connexion TCP peut être fermée par l'un ou l'autre des pairs. Lorsque le client termine le flux de requête (c'est-à-dire que le flux de réception au niveau du proxy entre dans l'état "Data Recvd"), le proxy définira le bit FIN sur sa connexion au serveur TCP. Lorsque le proxy reçoit un paquet avec le bit FIN défini, il fermera le flux d'envoi qu'il envoie au client. Les connexions TCP qui restent semi-fermées (Half-Closed) dans une seule direction ne sont pas invalides, mais sont souvent mal gérées par les serveurs, de sorte que les clients NE DEVRAIENT PAS (SHOULD NOT) fermer un flux pour l'envoi tant qu'ils s'attendent encore à recevoir des données de la cible du CONNECT.
Une erreur de connexion TCP est signalée en terminant brusquement le flux. Un proxy traite toute erreur dans la connexion TCP, qui inclut la réception d'un segment TCP avec le bit RST défini, comme une erreur de flux de type H3_CONNECT_ERROR.
En conséquence, si un proxy détecte une erreur avec le flux ou la connexion QUIC, il DOIT (MUST) fermer la connexion TCP. Si le proxy détecte que le client a réinitialisé le flux ou interrompu la lecture du flux, il DOIT (MUST) fermer la connexion TCP. Si le flux est réinitialisé ou si la lecture est interrompue par le client, un proxy DEVRAIT (SHOULD) effectuer la même opération dans l'autre direction afin de garantir que les deux directions du flux sont annulées. Dans tous ces cas, si l'implémentation TCP sous-jacente le permet, le proxy DEVRAIT (SHOULD) envoyer un segment TCP avec le bit RST défini.
Étant donné que CONNECT crée un tunnel vers un serveur arbitraire, les proxies qui prennent en charge CONNECT DEVRAIENT (SHOULD) restreindre son utilisation à un ensemble de ports connus ou à une liste de cibles de requête sûres ; voir la section 9.3.6 de [HTTP] pour plus de détails.
4.5. Mise à niveau HTTP (HTTP Upgrade)
HTTP/3 ne prend pas en charge le mécanisme de mise à niveau HTTP (HTTP Upgrade Mechanism) (section 7.8 de [HTTP]) ou le code d'état informatif 101 (Changement de protocoles) (Switching Protocols) (section 15.2.2 de [HTTP]).
4.6. Push serveur (Server Push)
Le push serveur (Server Push) est un mode d'interaction qui permet à un serveur de pousser un échange requête-réponse vers un client en prévision de la requête du client. Un client peut désactiver le push serveur en définissant SETTINGS_ENABLE_PUSH sur 0 dans une trame SETTINGS. Un serveur NE DOIT PAS (MUST NOT) envoyer un push à un client qui a défini SETTINGS_ENABLE_PUSH sur 0 ; un comportement serveur qui viole cela DOIT (MUST) être traité comme une erreur de connexion de type H3_SETTINGS_ERROR.
Comme HTTP/2, le serveur initie un push en envoyant une trame PUSH_PROMISE (section 7.2.5) sur un flux de requête initié par le client. L'ID de push (Push ID) est utilisé pour identifier un push serveur (voir la section 4.6.1). L'ID de push est transporté dans la trame PUSH_PROMISE, qui inclut également une section d'en-tête de requête attribuée à la requête générée par le serveur, comme décrit dans la section 15 de [HTTP].
Le serveur envoie la réponse à partir d'un flux de push qu'il initie (section 6.2.2). La livraison de la réponse poussée est identique à celle d'une réponse à une requête régulière. La section d'en-tête de réponse pour la réponse poussée est transportée dans une trame HEADERS comme décrit dans la section 7.2.4. Un serveur peut annuler un push promis en envoyant une trame CANCEL_PUSH avec l'ID de push sur le flux de push.
Les clients contrôlent le nombre de push que le serveur peut promettre en utilisant la trame MAX_PUSH_ID (section 7.2.7). Un serveur NE DOIT PAS (MUST NOT) envoyer une trame PUSH_PROMISE ou une trame CANCEL_PUSH avec un ID de push supérieur à l'ID de push maximum que le client a fourni pour la connexion. Les clients DOIVENT (MUST) traiter une tentative de le faire comme une erreur de connexion de type H3_ID_ERROR.
Une fois qu'un flux de push a été ouvert ou réservé par une trame PUSH_PROMISE, le flux de push peut être utilisé tant que le client n'a pas annulé le push. Une fois qu'un client reçoit une trame CANCEL_PUSH du flux de contrôle ou une terminaison de flux du flux de push, le push est annulé. Si le flux de push se termine sans CANCEL_PUSH, le push est toujours considéré comme terminé avec succès.
Les clients peuvent interrompre un push en envoyant une trame CANCEL_PUSH. Après que le serveur l'ait reçue, le serveur DOIT (MUST) interrompre l'envoi du push si le push n'est pas encore terminé. Les clients peuvent également interrompre un push en réinitialisant le flux de push. Dans les deux cas, le destinataire peut en toute sécurité rejeter tout état de réponse de push qui a été reçu.
Une fois qu'un flux de requête se ferme, les implémentations peuvent choisir de mettre en mémoire tampon uniquement une référence à la réponse de push ou de supprimer entièrement la référence à la réponse de push. Si une réponse de push est reçue avec un flux de requête associé fermé, cela n'indique pas un échec du push.
Les flux de push sont toujours référencés par un ID de push. Le destinataire d'une trame PUSH_PROMISE associe l'ID de push à un flux initié par le client, et un client recevant une trame HEADERS sur un flux de push fait correspondre l'ID de push avec un push reçu.
4.6.1. ID de push (Push IDs)
Les ID de push sont des entiers non signés de 62 bits (voir la section 16 de [QUIC-TRANSPORT]) utilisés pour identifier un push serveur. Les ID de push sont uniques pour la durée de vie de la connexion.
L'espace d'ID de push commence à zéro et est un sous-ensemble de l'espace entier ; par conséquent, les ID de push ne peuvent pas apparaître dans des contextes qui nécessitent un ID de flux ou un ID de requête. En particulier, les ID de push ne sont pas autorisés à apparaître dans les trames GOAWAY (voir la section 5.2).
Les ID de push sont utilisés dans une seule trame PUSH_PROMISE (voir la section 7.2.5) et un seul flux de push (voir les sections 4.6 et 6.2.2). Ces utilisations DOIVENT (MUST) référencer le même push promis effectué par le serveur pendant la durée de vie de la connexion.
Après l'envoi d'une réponse de push sur un flux de push, l'ID de push ne peut pas être réutilisé. Si un client reçoit un autre en-tête de flux de push ou un autre PUSH_PROMISE sur le même ID de push à partir de différents flux, cela DOIT (MUST) être traité comme une erreur de connexion de type H3_ID_ERROR.
5. Fermeture de connexion (Connection Closure)
Une fois établie, une connexion HTTP/3 peut être utilisée pour de nombreuses requêtes et réponses au fil du temps jusqu'à ce que la connexion soit fermée. La fermeture de connexion peut se produire de plusieurs manières différentes.
5.1. Connexions inactives (Idle Connections)
Chaque point de terminaison QUIC déclare un délai d'inactivité (Idle Timeout) pendant la négociation. Si la connexion QUIC reste inactive (aucun paquet reçu) pendant une durée supérieure à cette durée, le pair supposera que la connexion a été fermée. Les implémentations HTTP/3 devront ouvrir une nouvelle connexion HTTP/3 pour de nouvelles requêtes si la connexion existante a été inactive pendant une durée supérieure au délai d'inactivité négocié pendant la négociation QUIC, et elles DEVRAIENT (SHOULD) le faire si elles approchent du délai d'inactivité ; voir la section 10.1 de [QUIC-TRANSPORT].
Les clients HTTP sont censés demander que le transport maintienne les connexions ouvertes tant qu'il y a des réponses en attente pour les requêtes ou les push serveur, comme décrit dans la section 10.1.2 de [QUIC-TRANSPORT]. Si le client n'attend pas de réponse du serveur, il est préférable de laisser une connexion inactive expirer plutôt que de dépenser des efforts pour maintenir une connexion qui pourrait ne pas être nécessaire. Une passerelle PEUT (MAY) maintenir des connexions en prévision du besoin plutôt que d'encourir le coût de latence de l'établissement de connexion aux serveurs. Les serveurs NE DEVRAIENT PAS (SHOULD NOT) maintenir activement les connexions ouvertes.
5.2. Arrêt de connexion (Connection Shutdown)
Même lorsqu'une connexion n'est pas inactive, l'un ou l'autre point de terminaison peut décider d'arrêter d'utiliser la connexion et d'initier une fermeture de connexion gracieuse (Graceful Connection Close). Les points de terminaison initient l'arrêt gracieux d'une connexion HTTP/3 en envoyant une trame GOAWAY. La trame GOAWAY contient un identifiant qui indique au récepteur la plage de requêtes ou de push qui ont été ou pourraient être traités dans cette connexion. Le serveur envoie un ID de flux bidirectionnel initié par le client ; le client envoie un ID de push. Les requêtes ou les push avec l'identifiant indiqué ou supérieur sont rejetés (section 4.1.1) par l'expéditeur du GOAWAY. Cet identifiant PEUT (MAY) être zéro si aucune requête ou push n'a été traité.
Les informations dans la trame GOAWAY permettent à un client et à un serveur de convenir des requêtes ou des push qui ont été acceptés avant l'arrêt de la connexion HTTP/3. Lors de l'envoi d'une trame GOAWAY, le point de terminaison DEVRAIT (SHOULD) annuler explicitement (voir les sections 4.1.1 et 7.2.3) toutes les requêtes ou push ayant des identifiants supérieurs ou égaux à celui indiqué, afin de nettoyer l'état de transport pour les flux affectés. Le point de terminaison DEVRAIT (SHOULD) continuer à le faire à mesure que davantage de requêtes ou de push arrivent.
Les points de terminaison NE DOIVENT PAS (MUST NOT) initier de nouvelles requêtes ou promettre de nouveaux push sur la connexion après réception d'une trame GOAWAY du pair. Les clients PEUVENT (MAY) établir une nouvelle connexion pour envoyer des requêtes supplémentaires.
Certaines requêtes ou push peuvent déjà être en transit :
-
À la réception d'une trame GOAWAY, si le client a déjà envoyé des requêtes avec un ID de flux supérieur ou égal à l'identifiant contenu dans la trame GOAWAY, ces requêtes ne seront pas traitées. Les clients peuvent réessayer en toute sécurité les requêtes non traitées sur une connexion HTTP différente. Un client incapable de réessayer les requêtes perd toutes les requêtes en transit lorsque le serveur ferme la connexion.
Les requêtes sur des ID de flux inférieurs à l'ID de flux dans une trame GOAWAY du serveur ont peut-être été traitées ; leur statut ne peut être connu jusqu'à ce qu'une réponse soit reçue, que le flux soit réinitialisé individuellement, qu'un autre GOAWAY soit reçu avec un ID de flux inférieur à celui de la requête en question, ou que la connexion se termine.
Les serveurs PEUVENT (MAY) rejeter des requêtes individuelles sur des flux en dessous de l'ID indiqué si ces requêtes n'ont pas été traitées.
-
Si un serveur reçoit une trame GOAWAY après avoir promis des push avec un ID de push supérieur ou égal à l'identifiant contenu dans la trame GOAWAY, ces push ne seront pas acceptés.
Les serveurs DEVRAIENT (SHOULD) envoyer une trame GOAWAY lorsque la fermeture d'une connexion est connue à l'avance, même si le préavis est court, afin que le pair distant puisse savoir si une requête a été partiellement traitée ou non. Par exemple, si un client HTTP envoie un POST au même moment où un serveur ferme une connexion QUIC, le client ne peut pas savoir si le serveur a commencé à traiter cette requête POST si le serveur n'envoie pas de trame GOAWAY pour indiquer sur quels flux il a pu agir.
Un point de terminaison PEUT (MAY) envoyer plusieurs trames GOAWAY indiquant différents identifiants, mais l'identifiant dans chaque trame NE DOIT PAS (MUST NOT) être supérieur à l'identifiant dans toute trame précédente, car les clients ont peut-être déjà réessayé des requêtes non traitées sur une autre connexion HTTP. Recevoir un GOAWAY contenant un identifiant plus grand que celui reçu précédemment DOIT (MUST) être traité comme une erreur de connexion de type H3_ID_ERROR.
Un point de terminaison qui tente d'arrêter gracieusement une connexion peut envoyer une trame GOAWAY avec une valeur définie sur la valeur maximale possible (2^62-4 pour les serveurs, 2^62-1 pour les clients). Cela garantit que le pair cesse de créer de nouvelles requêtes ou push. Après avoir laissé le temps à toutes les requêtes ou push en transit d'arriver, le point de terminaison peut envoyer une autre trame GOAWAY indiquant quelles requêtes ou push il pourrait accepter avant la fin de la connexion. Cela garantit qu'une connexion peut être fermée proprement sans perdre de requêtes.
Un client a plus de flexibilité dans la valeur qu'il choisit pour le champ Push ID dans un GOAWAY qu'il envoie. Une valeur de 2^62-1 indique que le serveur peut continuer à exécuter les push qui ont déjà été promis. Une valeur plus petite indique que le client rejettera les push avec des ID de push supérieurs ou égaux à cette valeur. Comme le serveur, le client PEUT (MAY) envoyer des trames GOAWAY ultérieures tant que l'ID de push spécifié n'est pas supérieur à toute valeur précédemment envoyée.
Même lorsqu'un GOAWAY indique qu'une requête ou un push donné ne sera pas traité ou accepté à la réception, les ressources de transport sous-jacentes existent toujours. Le point de terminaison qui a initié ces requêtes peut les annuler pour nettoyer l'état de transport.
Une fois que toutes les requêtes et push acceptés ont été traités, le point de terminaison peut permettre à la connexion de devenir inactive, ou il PEUT (MAY) initier une fermeture immédiate de la connexion. Un point de terminaison qui termine un arrêt gracieux DEVRAIT (SHOULD) utiliser le code d'erreur H3_NO_ERROR lors de la fermeture de la connexion.
Si un client a consommé tous les ID de flux bidirectionnels disponibles avec des requêtes, le serveur n'a pas besoin d'envoyer une trame GOAWAY, car le client est incapable de faire d'autres requêtes.
5.3. Fermeture immédiate de l'application (Immediate Application Closure)
Une implémentation HTTP/3 peut fermer immédiatement la connexion QUIC à tout moment. Cela entraîne l'envoi d'une trame QUIC CONNECTION_CLOSE au pair indiquant que la couche application a terminé la connexion. Le code d'erreur d'application dans cette trame indique au pair pourquoi la connexion est fermée. Voir la section 8 pour les codes d'erreur qui peuvent être utilisés lors de la fermeture d'une connexion en HTTP/3.
Avant de fermer la connexion, une trame GOAWAY PEUT (MAY) être envoyée pour permettre au client de réessayer certaines requêtes. Inclure la trame GOAWAY dans le même paquet que la trame QUIC CONNECTION_CLOSE améliore les chances que la trame soit reçue par les clients.
S'il existe des flux ouverts qui n'ont pas été explicitement fermés, ils sont implicitement fermés lorsque la connexion est fermée ; voir la section 10.2 de [QUIC-TRANSPORT].
5.4. Fermeture du transport (Transport Closure)
Pour diverses raisons, le transport QUIC pourrait indiquer à la couche application que la connexion s'est terminée. Cela peut être dû à une fermeture explicite par le pair, à une erreur au niveau du transport ou à un changement de topologie réseau qui interrompt la connectivité.
Si une connexion se termine sans trame GOAWAY, les clients DOIVENT (MUST) supposer que toute requête qui a été envoyée, en tout ou en partie, a pu être traitée.
6. Mappage et utilisation des flux (Stream Mapping and Usage)
Un flux QUIC fournit une livraison d'octets fiable et ordonnée, mais ne garantit pas l'ordre de livraison par rapport aux octets sur d'autres flux. Dans la version 1 de QUIC, les données de flux contenant des trames HTTP sont transportées par des trames QUIC STREAM, mais ce cadrage est invisible pour la couche de cadrage HTTP. La couche transport met en mémoire tampon et ordonne les données de flux reçues, exposant un flux d'octets fiable à l'application. Bien que QUIC permette la livraison désordonnée au sein d'un flux, HTTP/3 n'utilise pas cette fonctionnalité.
Les flux QUIC peuvent être soit unidirectionnels, transportant des données uniquement de l'initiateur vers le récepteur, soit bidirectionnels, transportant des données dans les deux directions. Les flux peuvent être initiés par le client ou le serveur. Pour plus de détails sur les flux QUIC, voir la section 2 de [QUIC-TRANSPORT].
Lorsque les champs et données HTTP sont envoyés sur QUIC, la couche QUIC gère la majeure partie de la gestion des flux. HTTP n'a pas besoin de faire de multiplexage séparé lors de l'utilisation de QUIC : les données envoyées sur un flux QUIC sont toujours mappées à une transaction HTTP particulière ou au contexte de connexion HTTP/3 entier.
6.1. Flux bidirectionnels (Bidirectional Streams)
Tous les flux bidirectionnels initiés par le client sont utilisés pour les requêtes et réponses HTTP. Un flux bidirectionnel garantit que la réponse peut être facilement corrélée avec la requête. Ces flux sont appelés flux de requête (Request Streams).
Cela signifie que la première requête du client se produit sur le flux QUIC 0, avec les requêtes suivantes sur les flux 4, 8, et ainsi de suite. Afin de permettre l'ouverture de ces flux, un serveur HTTP/3 DEVRAIT (SHOULD) configurer des valeurs minimales non nulles pour le nombre de flux autorisés et la fenêtre de contrôle de flux du flux initial. Afin de ne pas limiter inutilement le parallélisme, au moins 100 flux de requête DEVRAIENT (SHOULD) être autorisés à la fois.
HTTP/3 n'utilise pas de flux bidirectionnels initiés par le serveur, bien qu'une extension puisse définir une utilisation pour ces flux. Les clients DOIVENT (MUST) traiter la réception d'un flux bidirectionnel initié par le serveur comme une erreur de connexion de type H3_STREAM_CREATION_ERROR, sauf si une telle extension a été négociée.
6.2. Flux unidirectionnels (Unidirectional Streams)
Les flux unidirectionnels, dans les deux directions, sont utilisés à diverses fins. Le but est indiqué par un type de flux (Stream Type), qui est envoyé sous forme d'entier de longueur variable au début du flux. Le format et la structure des données qui suivent cet entier sont déterminés par le type de flux.
Unidirectional Stream Header {
Stream Type (i),
}
Figure 1 : En-tête de flux unidirectionnel
Deux types de flux sont définis dans ce document : les flux de contrôle (Control Streams) (section 6.2.1) et les flux de push (Push Streams) (section 6.2.2). [QPACK] définit deux types de flux supplémentaires. D'autres types de flux peuvent être définis par des extensions à HTTP/3 ; voir la section 9 pour plus de détails. Certains types de flux sont réservés (section 6.2.3).
Les performances des connexions HTTP/3 dans la phase précoce de leur durée de vie sont sensibles à la création et à l'échange de données sur les flux unidirectionnels. Les points de terminaison qui restreignent excessivement le nombre de flux ou la fenêtre de contrôle de flux de ces flux augmenteront les chances que le pair distant atteigne la limite tôt et soit bloqué. En particulier, les implémentations devraient considérer que les pairs distants peuvent souhaiter exercer le comportement de flux réservé (section 6.2.3) avec certains des flux unidirectionnels qu'ils sont autorisés à utiliser.
Chaque point de terminaison doit créer au moins un flux unidirectionnel pour le flux de contrôle HTTP. QPACK nécessite deux flux unidirectionnels supplémentaires, et d'autres extensions pourraient nécessiter d'autres flux. Par conséquent, les paramètres de transport envoyés par les clients et les serveurs DOIVENT (MUST) permettre au pair de créer au moins trois flux unidirectionnels. Ces paramètres de transport DEVRAIENT (SHOULD) également fournir au moins 1 024 octets de crédit de contrôle de flux à chaque flux unidirectionnel.
Notez qu'un point de terminaison n'est pas tenu d'accorder des crédits supplémentaires pour créer plus de flux unidirectionnels si son pair consomme tous les crédits initiaux avant de créer les flux unidirectionnels critiques. Les points de terminaison DEVRAIENT (SHOULD) créer le flux de contrôle HTTP ainsi que les flux unidirectionnels requis par les extensions obligatoires (tels que les flux d'encodeur et de décodeur QPACK) en premier, puis créer des flux supplémentaires comme autorisé par leur pair.
Si l'en-tête de flux indique un type de flux qui n'est pas pris en charge par le destinataire, le reste du flux ne peut pas être consommé car la sémantique est inconnue. Les destinataires de types de flux inconnus DOIVENT (MUST) soit abandonner la lecture du flux, soit rejeter les données entrantes sans traitement supplémentaire. Si la lecture est abandonnée, le destinataire DEVRAIT (SHOULD) utiliser le code d'erreur H3_STREAM_CREATION_ERROR ou un code d'erreur réservé (section 8.1). Le destinataire NE DOIT PAS (MUST NOT) considérer les types de flux inconnus comme une erreur de connexion de quelque nature que ce soit.
Étant donné que certains types de flux peuvent affecter l'état de la connexion, un destinataire NE DEVRAIT PAS (SHOULD NOT) rejeter les données des flux unidirectionnels entrants avant de lire le type de flux.
Les implémentations PEUVENT (MAY) envoyer des types de flux avant de savoir si le pair les prend en charge. Cependant, les types de flux qui pourraient modifier l'état ou la sémantique des composants de protocole existants, y compris QPACK ou d'autres extensions, NE DOIVENT PAS (MUST NOT) être envoyés tant que le pair n'est pas connu pour les prendre en charge.
Un expéditeur peut fermer ou réinitialiser un flux unidirectionnel sauf indication contraire. Un récepteur DOIT (MUST) tolérer la fermeture ou la réinitialisation des flux unidirectionnels avant la réception de l'en-tête de flux unidirectionnel.
6.2.1. Flux de contrôle (Control Streams)
Un flux de contrôle est indiqué par un type de flux de 0x00. Les données sur ce flux consistent en des trames HTTP/3, comme défini dans la section 7.2.
Chaque côté DOIT (MUST) initier un seul flux de contrôle au début de la connexion et envoyer sa trame SETTINGS comme première trame sur ce flux. Si la première trame du flux de contrôle est tout autre type de trame, cela DOIT (MUST) être traité comme une erreur de connexion de type H3_MISSING_SETTINGS. Un seul flux de contrôle par pair est autorisé ; la réception d'un deuxième flux prétendant être un flux de contrôle DOIT (MUST) être traitée comme une erreur de connexion de type H3_STREAM_CREATION_ERROR. L'expéditeur NE DOIT PAS (MUST NOT) fermer le flux de contrôle, et le récepteur NE DOIT PAS (MUST NOT) demander que l'expéditeur ferme le flux de contrôle. Si l'un ou l'autre flux de contrôle est fermé à tout moment, cela DOIT (MUST) être traité comme une erreur de connexion de type H3_CLOSED_CRITICAL_STREAM. Les erreurs de connexion sont décrites dans la section 8.
Parce que le contenu du flux de contrôle est utilisé pour gérer le comportement d'autres flux, les points de terminaison DEVRAIENT (SHOULD) fournir suffisamment de crédit de contrôle de flux pour empêcher le flux de contrôle du pair de devenir bloqué.
Une paire de flux unidirectionnels est utilisée plutôt qu'un seul flux bidirectionnel. Cela permet à l'un ou l'autre pair d'envoyer des données dès qu'il le peut. Selon que 0-RTT est disponible sur la connexion QUIC, le client ou le serveur peut être capable d'envoyer des données de flux en premier.
6.2.2. Flux de push (Push Streams)
Le push serveur (Server Push) est une fonctionnalité facultative introduite dans HTTP/2 qui permet à un serveur d'initier une réponse avant qu'une requête ait été faite. Voir la section 4.6 pour plus de détails.
Un flux de push est indiqué par un type de flux de 0x01, suivi de l'ID de push (Push ID) de la promesse qu'il remplit, encodé sous forme d'entier de longueur variable. Les données restantes sur ce flux consistent en des trames HTTP/3, comme défini dans la section 7.2, et remplissent un push serveur promis par zéro ou plusieurs réponses HTTP intermédiaires suivies d'une seule réponse HTTP finale, comme défini dans la section 4.1. Le push serveur et les ID de push sont décrits dans la section 4.6.
Seuls les serveurs peuvent pousser ; si un serveur reçoit un flux de push initié par le client, cela DOIT (MUST) être traité comme une erreur de connexion de type H3_STREAM_CREATION_ERROR.
Push Stream Header {
Stream Type (i) = 0x01,
Push ID (i),
}
Figure 2 : En-tête de flux de push
Un client NE DEVRAIT PAS (SHOULD NOT) abandonner la lecture d'un flux de push avant de lire l'en-tête de flux de push, car cela pourrait entraîner un désaccord entre le client et le serveur sur les ID de push qui ont déjà été consommés.
Chaque ID de push NE DOIT (MUST) être utilisé qu'une seule fois dans un en-tête de flux de push. Si un client détecte qu'un en-tête de flux de push inclut un ID de push qui a été utilisé dans un autre en-tête de flux de push, le client DOIT (MUST) traiter cela comme une erreur de connexion de type H3_ID_ERROR.
6.2.3. Types de flux réservés (Reserved Stream Types)
Les types de flux du format 0x1f * N + 0x21 pour les valeurs entières non négatives de N sont réservés pour exercer l'exigence que les types inconnus soient ignorés. Ces flux n'ont pas de sémantique, et ils peuvent être envoyés lorsque le remplissage de la couche application est souhaité. Ils PEUVENT (MAY) également être envoyés sur des connexions où aucune donnée n'est actuellement transférée. Les points de terminaison NE DOIVENT PAS (MUST NOT) considérer que ces flux ont une signification quelconque à la réception.
La charge utile et la longueur du flux sont sélectionnées de la manière que l'implémentation d'envoi choisit. Lors de l'envoi d'un type de flux réservé, l'implémentation PEUT (MAY) soit terminer le flux proprement, soit le réinitialiser. Lors de la réinitialisation du flux, soit le code d'erreur H3_NO_ERROR, soit un code d'erreur réservé (section 8.1) DEVRAIT (SHOULD) être utilisé.
7. Couche de tramage HTTP (HTTP Framing Layer)
Les trames HTTP sont transportées sur les flux QUIC, comme décrit dans la section 6. HTTP/3 définit trois types de flux : flux de contrôle, flux de requête et flux de poussée. Cette section décrit les formats de trame HTTP/3 et leurs types de flux autorisés ; voir le tableau 1 pour un aperçu.
Tableau 1 : Aperçu des trames HTTP/3 et des types de flux
| Trame | Flux de contrôle | Flux de requête | Flux de poussée | Section |
|---|---|---|---|---|
| DATA | Non | Oui | Oui | 7.2.1 |
| HEADERS | Non | Oui | Oui | 7.2.2 |
| CANCEL_PUSH | Oui | Non | Non | 7.2.3 |
| SETTINGS | Oui (1) | Non | Non | 7.2.4 |
| PUSH_PROMISE | Non | Oui | Non | 7.2.5 |
| GOAWAY | Oui | Non | Non | 7.2.6 |
| MAX_PUSH_ID | Oui | Non | Non | 7.2.7 |
| Réservé | Oui | Oui | Oui | 7.2.8 |
La trame SETTINGS ne peut apparaître que comme première trame d'un flux de contrôle ; ceci est indiqué dans le tableau 1 par un (1).
Notez que, contrairement aux trames QUIC, les trames HTTP/3 peuvent s'étendre sur plusieurs paquets.
7.1. Disposition des trames (Frame Layout)
Toutes les trames ont le format suivant :
HTTP/3 Frame Format {
Type (i),
Length (i),
Frame Payload (..),
}
Une trame comprend les champs suivants :
- Type : Un entier de longueur variable qui identifie le type de trame
- Length (Longueur) : Un entier de longueur variable qui décrit la longueur en octets de la charge utile de la trame
- Frame Payload (Charge utile de la trame) : Une charge utile dont la sémantique est déterminée par le champ Type
La charge utile de chaque trame DOIT (MUST) contenir exactement les champs identifiés dans sa description. Une charge utile de trame contenant des octets supplémentaires ou se terminant prématurément DOIT (MUST) être traitée comme une erreur de connexion de type H3_FRAME_ERROR.
7.2. Définitions des trames (Frame Definitions)
7.2.1. DATA
Les trames DATA (type=0x00) transmettent des séquences d'octets arbitraires de longueur variable associées au contenu de requête ou de réponse HTTP.
Les trames DATA DOIVENT (MUST) être associées à une requête ou réponse HTTP. Si une trame DATA est reçue sur un flux de contrôle, le destinataire DOIT (MUST) répondre avec une erreur de connexion de type H3_FRAME_UNEXPECTED.
7.2.2. HEADERS
La trame HEADERS (type=0x01) est utilisée pour transporter une section de champ HTTP encodée avec QPACK.
Les trames HEADERS ne peuvent être envoyées que sur les flux de requête ou les flux de poussée. Si une trame HEADERS est reçue sur un flux de contrôle, le destinataire DOIT (MUST) répondre avec une erreur de connexion de type H3_FRAME_UNEXPECTED.
7.2.3. CANCEL_PUSH
La trame CANCEL_PUSH (type=0x03) est utilisée pour demander l'annulation d'une poussée serveur avant la réception du flux de poussée.
Lorsqu'un client envoie une trame CANCEL_PUSH, il indique qu'il ne souhaite pas recevoir la ressource promise. Le serveur DEVRAIT (SHOULD) abandonner l'envoi de la ressource.
Les trames CANCEL_PUSH sont envoyées sur le flux de contrôle. Recevoir une trame CANCEL_PUSH sur un flux de requête ou un flux de poussée DOIT (MUST) être traité comme une erreur de connexion de type H3_FRAME_UNEXPECTED.
7.2.4. SETTINGS
La trame SETTINGS (type=0x04) transmet les paramètres de configuration qui affectent la manière dont les points de terminaison communiquent.
Les trames SETTINGS DOIVENT (MUST) être envoyées comme première trame de chaque flux de contrôle. Les trames SETTINGS NE DOIVENT PAS (MUST NOT) être envoyées sur d'autres flux.
Les identifiants de paramètres définis incluent :
- SETTINGS_MAX_FIELD_SECTION_SIZE (0x06) : Taille maximale de section de champ
- SETTINGS_QPACK_MAX_TABLE_CAPACITY (0x01) : Paramètre lié à QPACK
- SETTINGS_QPACK_BLOCKED_STREAMS (0x07) : Paramètre lié à QPACK
7.2.5. PUSH_PROMISE
La trame PUSH_PROMISE (type=0x05) est utilisée pour transporter une section de champ d'en-tête de requête promise du serveur au client sur un flux de requête.
Les trames PUSH_PROMISE ne peuvent être envoyées que sur les flux de requête. Recevoir une trame PUSH_PROMISE sur un flux de contrôle ou un flux de poussée DOIT (MUST) être traité comme une erreur de connexion de type H3_FRAME_UNEXPECTED.
7.2.6. GOAWAY
La trame GOAWAY (type=0x07) est utilisée pour initier l'arrêt gracieux d'une connexion.
Les trames GOAWAY sont toujours envoyées sur le flux de contrôle. Recevoir une trame GOAWAY sur un flux de requête ou un flux de poussée DOIT (MUST) être traité comme une erreur de connexion de type H3_FRAME_UNEXPECTED.
7.2.7. MAX_PUSH_ID
La trame MAX_PUSH_ID (type=0x0d) est utilisée par les clients pour contrôler le nombre de poussées serveur que le serveur peut initier.
Les trames MAX_PUSH_ID sont toujours envoyées sur le flux de contrôle. Un serveur NE DOIT PAS (MUST NOT) envoyer de trame MAX_PUSH_ID.
7.2.8. Types de trames réservés (Reserved Frame Types)
Les types de trames au format 0x1f * N + 0x21 pour des valeurs entières non négatives de N sont réservés pour exercer l'exigence que les types inconnus soient ignorés. Ces trames n'ont pas de sémantique et peuvent être envoyées sur n'importe quel flux.
8. Gestion des erreurs (Error Handling)
Lorsqu'un flux ne peut pas être complété avec succès, QUIC permet à l'application de terminer (réinitialiser) brusquement ce flux et de communiquer une raison ; voir la section 2.4 de [QUIC-TRANSPORT]. Ceci est appelé une "erreur de flux (Stream Error)". Une implémentation HTTP/3 peut décider de fermer un flux QUIC et de communiquer le type d'erreur. Les encodages filaires des codes d'erreur sont définis dans la section 8.1. Les erreurs de flux sont distinctes des codes d'état HTTP qui indiquent des conditions d'erreur. Les erreurs de flux indiquent que l'expéditeur n'a pas transféré ou consommé la requête ou la réponse complète, tandis que les codes d'état HTTP indiquent le résultat d'une requête qui a été reçue avec succès.
Si une connexion entière doit être terminée, QUIC fournit de manière similaire des mécanismes pour communiquer une raison ; voir la section 5.3 de [QUIC-TRANSPORT]. Ceci est appelé une "erreur de connexion (Connection Error)". Semblable aux erreurs de flux, une implémentation HTTP/3 peut terminer une connexion QUIC et communiquer la raison en utilisant un code d'erreur de la section 8.1.
Bien que les raisons de fermeture des flux et des connexions soient appelées "erreurs", ces actions n'indiquent pas nécessairement un problème avec la connexion ou l'une ou l'autre implémentation. Par exemple, un flux peut être réinitialisé si la ressource demandée n'est plus nécessaire.
Un point de terminaison PEUT (MAY) choisir de traiter une erreur de flux comme une erreur de connexion dans certaines circonstances, en fermant la connexion entière en réponse à une condition sur un seul flux. Les implémentations doivent considérer l'impact sur les requêtes en cours avant de faire ce choix.
Parce que de nouveaux codes d'erreur peuvent être définis sans négociation (voir la section 9), l'utilisation d'un code d'erreur dans un contexte inattendu ou la réception d'un code d'erreur inconnu DOIT (MUST) être traitée comme équivalente à H3_NO_ERROR. Cependant, la fermeture d'un flux peut avoir d'autres effets indépendamment du code d'erreur ; par exemple, voir la section 4.1.
8.1. Codes d'erreur HTTP/3 (HTTP/3 Error Codes)
Les codes d'erreur suivants sont définis pour une utilisation lors de la terminaison brusque de flux, de l'abandon de la lecture de flux ou de la fermeture immédiate de connexions HTTP/3.
H3_NO_ERROR (0x0100)
Aucune erreur. Utilisé lorsque la connexion ou le flux doit être fermé, mais qu'il n'y a pas d'erreur à signaler.
H3_GENERAL_PROTOCOL_ERROR (0x0101)
Le pair a violé les exigences du protocole d'une manière qui ne correspond pas à un code d'erreur plus spécifique ou le point de terminaison refuse d'utiliser le code d'erreur plus spécifique.
H3_INTERNAL_ERROR (0x0102)
Une erreur interne s'est produite dans la pile HTTP.
H3_STREAM_CREATION_ERROR (0x0103)
Le point de terminaison a détecté que son pair a créé un flux qu'il n'acceptera pas.
H3_CLOSED_CRITICAL_STREAM (0x0104)
Un flux requis par la connexion HTTP/3 a été fermé ou réinitialisé.
H3_FRAME_UNEXPECTED (0x0105)
Une trame a été reçue qui n'était pas autorisée dans l'état actuel ou sur le flux actuel.
H3_FRAME_ERROR (0x0106)
Une trame qui ne satisfait pas les exigences de disposition ou avec une taille invalide a été reçue.
H3_EXCESSIVE_LOAD (0x0107)
Le point de terminaison a détecté que son pair présente un comportement qui pourrait générer une charge excessive.
H3_ID_ERROR (0x0108)
Un ID de flux ou un ID de poussée a été utilisé incorrectement, par exemple en dépassant une limite, en réduisant une limite ou en étant réutilisé.
H3_SETTINGS_ERROR (0x0109)
Un point de terminaison a détecté une erreur dans la charge utile d'une trame SETTINGS.
H3_MISSING_SETTINGS (0x010a)
Aucune trame SETTINGS n'a été reçue au début du flux de contrôle.
H3_REQUEST_REJECTED (0x010b)
Un serveur a rejeté une requête sans effectuer de traitement d'application.
H3_REQUEST_CANCELLED (0x010c)
La requête ou sa réponse (y compris la réponse poussée) est annulée.
H3_REQUEST_INCOMPLETE (0x010d)
Le flux du client s'est terminé sans contenir une requête complètement formée.
H3_MESSAGE_ERROR (0x010e)
Un message HTTP était mal formé et ne peut pas être traité.
H3_CONNECT_ERROR (0x010f)
La connexion TCP établie en réponse à une requête CONNECT a été réinitialisée ou fermée anormalement.
H3_VERSION_FALLBACK (0x0110)
L'opération demandée ne peut pas être servie sur HTTP/3. Le pair devrait réessayer sur HTTP/1.1.
Les codes d'erreur au format 0x1f * N + 0x21 pour des valeurs entières non négatives de N sont réservés pour exercer l'exigence que les codes d'erreur inconnus soient traités comme équivalents à H3_NO_ERROR (section 9). Les implémentations DEVRAIENT (SHOULD) sélectionner un code d'erreur de cet espace avec une certaine probabilité lorsqu'elles auraient envoyé H3_NO_ERROR.
9. Extensions à HTTP/3 (Extensions to HTTP/3)
HTTP/3 permet l'extension du protocole. Dans les limites décrites dans cette section, les extensions de protocole peuvent être utilisées pour fournir des services supplémentaires ou modifier n'importe quel aspect du protocole. Les extensions ne sont effectives que dans le cadre d'une seule connexion HTTP/3.
Cela s'applique aux éléments de protocole définis dans ce document. Cela n'affecte pas les options existantes pour étendre HTTP, telles que la définition de nouvelles méthodes, codes d'état ou champs.
Les extensions sont autorisées à utiliser de nouveaux types de trames (Section 7.2), de nouveaux paramètres (Section 7.2.4.1), de nouveaux codes d'erreur (Section 8) ou de nouveaux types de flux unidirectionnels (Section 6.2). Des registres sont établis pour gérer ces points d'extension : types de trames (Section 11.2.1), paramètres (Section 11.2.2), codes d'erreur (Section 11.2.3) et types de flux (Section 11.2.4).
Les implémentations DOIVENT (MUST) ignorer les valeurs inconnues ou non supportées dans tous les éléments de protocole extensibles. Les implémentations DOIVENT (MUST) rejeter les données ou abandonner la lecture sur les flux unidirectionnels ayant des types inconnus ou non supportés. Cela signifie que n'importe lequel de ces points d'extension peut être utilisé en toute sécurité par les extensions sans arrangement ou négociation préalable. Cependant, lorsqu'un type de trame connu doit être dans un emplacement spécifique, tel que la trame SETTINGS comme première trame du flux de contrôle (voir Section 6.2.1), un type de trame inconnu ne satisfait pas cette exigence et DEVRAIT (SHOULD) être traité comme une erreur.
Les extensions qui pourraient modifier la sémantique des composants de protocole existants DOIVENT (MUST) être négociées avant d'être utilisées. Par exemple, une extension qui modifie la disposition de la trame HEADERS ne peut pas être utilisée jusqu'à ce que le pair ait donné un signal positif que cela est acceptable. Coordonner quand une telle disposition révisée entre en vigueur pourrait s'avérer complexe. En tant que tel, l'attribution de nouveaux identifiants pour de nouvelles définitions d'éléments de protocole existants est susceptible d'être plus efficace.
Ce document n'impose pas de méthode spécifique pour négocier l'utilisation d'une extension, mais il note qu'un paramètre (Section 7.2.4.1) pourrait être utilisé à cette fin. Si les deux pairs définissent une valeur qui indique la volonté d'utiliser l'extension, alors l'extension peut être utilisée. Si un paramètre est utilisé pour la négociation d'extension, la valeur par défaut DOIT (MUST) être définie de manière à ce que l'extension soit désactivée si le paramètre est omis.
10. Considérations de sécurité (Security Considerations)
Les considérations de sécurité de HTTP/3 devraient être comparables à celles de HTTP/2 avec TLS. Toutefois, de nombreuses considérations de la section 10 de [HTTP/2] s'appliquent à [QUIC-TRANSPORT] et sont discutées dans ce document.
10.1. Autorité du serveur (Server Authority)
HTTP/3 s'appuie sur la définition d'autorité de HTTP. Les considérations de sécurité relatives à l'établissement de l'autorité sont discutées à la section 17.1 de [HTTP].
10.2. Attaques inter-protocoles (Cross-Protocol Attacks)
L'utilisation d'ALPN dans les poignées de main TLS et QUIC établit le protocole applicatif cible avant le traitement des octets de couche application. Cela donne aux points d'extrémité une forte garantie que le pair utilise le même protocole.
Cela ne garantit pas une protection contre toutes les attaques inter-protocoles. La section 21.5 de [QUIC-TRANSPORT] décrit certaines manières dont le texte clair des paquets QUIC peut être utilisé pour effectuer de la falsification de requêtes contre des points d'extrémité qui n'utilisent pas un transport authentifié.
10.3. Attaques d'encapsulation par intermédiaire (Intermediary-Encapsulation Attacks)
L'encodage des champs HTTP/3 permet d'exprimer des noms de champ qui ne sont pas valides dans la syntaxe utilisée par HTTP; voir la section 5.1 de [HTTP]. Une requête ou une réponse contenant un nom de champ invalide doit être traitée comme mal formée.
De même, HTTP/3 peut transporter des valeurs de champ invalides. Bien que la plupart des valeurs encodables ne changent pas l'analyse des champs, les retours chariot (ASCII 0x0d), les sauts de ligne (ASCII 0x0a) et les caractères nuls (ASCII 0x00) peuvent être exploités par un attaquant s'ils sont convertis littéralement.
10.4. Mise en cache des réponses poussées (Cacheability of Pushed Responses)
Les réponses poussées ne disposent pas d'une requête explicite du client; la requête est fournie par le serveur dans la trame PUSH_PROMISE.
Lorsque plusieurs locataires partagent le même serveur, celui-ci doit garantir qu'un locataire ne peut pas pousser la représentation d'une ressource pour laquelle il n'a pas d'autorisation.
10.5. Considérations de déni de service (Denial-of-Service Considerations)
Les connexions HTTP/3 peuvent nécessiter davantage de ressources que les connexions HTTP/1.1 ou HTTP/2.
La capacité d'envoyer des éléments de protocole non définis que le pair doit ignorer peut être détournée afin de lui imposer un temps de traitement supplémentaire.
Les points d'extrémité qui ne surveillent pas ce type de comportement s'exposent à un risque de déni de service. Les implémentations devraient suivre l'utilisation de ces fonctionnalités et imposer des limites à leur usage.
10.5.1. Limites de taille de section de champs (Limits on Field Section Size)
De grandes sections de champs (section 4.1) peuvent amener une implémentation à engager une quantité importante d'état. Un point d'extrémité peut utiliser le paramètre SETTINGS_MAX_FIELD_SECTION_SIZE (section 4.2.2) pour informer le pair de la limite susceptible d'être appliquée à la taille des sections de champs.
10.5.2. Problèmes liés à CONNECT (CONNECT Issues)
La méthode CONNECT peut être utilisée pour créer une charge disproportionnée sur un proxy, car la création de flux est relativement peu coûteuse par rapport à la création et à la maintenance de connexions TCP.
10.6. Utilisation de la compression (Use of Compression)
Lorsque des données secrètes sont compressées dans le même contexte que des données contrôlées par un attaquant, la compression peut permettre à l'attaquant de récupérer ces données secrètes. HTTP/3 active la compression des champs (section 4.2).
Les implémentations qui communiquent sur un canal sécurisé interdisent la compression de contenu contenant à la fois des données secrètes et des données contrôlées par un attaquant, sauf si des contextes de compression séparés sont utilisés pour chaque source de données.
10.7. Bourrage et analyse du trafic (Padding and Traffic Analysis)
Le bourrage peut être utilisé pour masquer la taille exacte du contenu des trames et pour atténuer certaines attaques dans HTTP.
10.8. Analyse des trames (Frame Parsing)
Plusieurs éléments de protocole contiennent des éléments de longueur imbriqués. Les implémentations doivent garantir que la longueur d'une trame correspond exactement à la longueur des champs qu'elle contient.
10.9. Données précoces (Early Data)
L'utilisation de 0-RTT avec HTTP/3 entraîne un risque d'attaque par rejeu. Les mesures d'atténuation contre le rejeu de [HTTP-REPLAY] doivent être appliquées lorsque HTTP/3 est utilisé avec 0-RTT.
10.10. Migration (Migration)
Certaines implémentations HTTP utilisent l'adresse du client pour la journalisation ou le contrôle d'accès. Comme l'adresse d'un client QUIC peut changer pendant une connexion, ces implémentations doivent récupérer activement l'adresse courante du client ou accepter explicitement que l'adresse d'origine puisse changer.
10.11. Considérations de confidentialité (Privacy Considerations)
Plusieurs caractéristiques de HTTP/3 donnent aux observateurs des occasions de corréler dans le temps les opérations d'un client ou d'un serveur donné. Ces caractéristiques incluent les valeurs des paramètres, le temps de réponse aux stimuli et le traitement de toute fonctionnalité contrôlée par des paramètres.
La préférence de HTTP/3 pour l'utilisation d'une seule connexion QUIC permet de corréler l'activité d'un utilisateur sur un site.
11. Considérations relatives à l'IANA (IANA Considerations)
Ce document enregistre un nouvel identifiant de protocole ALPN (section 11.1) et crée de nouveaux registres qui gèrent l'allocation des points de code dans HTTP/3.
11.1. Enregistrement de la chaîne d'identification HTTP/3 (Registration of HTTP/3 Identification String)
Ce document crée, pour l'identification de HTTP/3, un nouvel enregistrement dans le registre "TLS Application-Layer Protocol Negotiation (ALPN) Protocol ID" établi par [RFC7301].
La chaîne "h3" identifie HTTP/3:
- Protocole (Protocol): HTTP/3
- Séquence d'identification (Identification Sequence): 0x68 0x33 (
"h3") - Spécification (Specification): ce document
11.2. Nouveaux registres (New Registries)
Les nouveaux registres créés dans ce document fonctionnent selon la politique d'enregistrement QUIC documentée à la section 22.1 de [QUIC-TRANSPORT]. Ces registres incluent tous l'ensemble de champs communs listé à la section 22.1.1 de [QUIC-TRANSPORT]. Ils sont regroupés sous l'intitulé "Hypertext Transfer Protocol version 3 (HTTP/3)".
Les allocations initiales de ces registres sont toutes désignées comme permanentes, avec l'IETF comme contrôleur de changement et le groupe de travail HTTP ([email protected]) comme contact.
11.2.1. Types de trames (Frame Types)
Ce document établit un registre pour les codes de type de trame HTTP/3. Le registre "HTTP/3 Frame Types" gère un espace de 62 bits.
Tableau 2: types de trames HTTP/3 initiaux
| Type de trame (Frame Type) | Valeur (Value) | Spécification (Specification) |
|---|---|---|
| DATA | 0x00 | Section 7.2.1 |
| HEADERS | 0x01 | Section 7.2.2 |
| Reserved | 0x02 | Ce document |
| CANCEL_PUSH | 0x03 | Section 7.2.3 |
| SETTINGS | 0x04 | Section 7.2.4 |
| PUSH_PROMISE | 0x05 | Section 7.2.5 |
| Reserved | 0x06 | Ce document |
| GOAWAY | 0x07 | Section 7.2.6 |
| MAX_PUSH_ID | 0x0d | Section 7.2.7 |
11.2.2. Paramètres de réglage (Settings Parameters)
Ce document établit un registre pour les paramètres HTTP/3. Le registre "HTTP/3 Settings" gère un espace de 62 bits.
Tableau 3: paramètres HTTP/3 initiaux
| Nom du paramètre (Setting Name) | Valeur (Value) | Spécification (Specification) | Défaut (Default) |
|---|---|---|---|
| MAX_FIELD_SECTION_SIZE | 0x06 | Section 4.2.2 | Illimité (Unlimited) |
11.2.3. Codes d'erreur (Error Codes)
Ce document établit un registre pour les codes d'erreur HTTP/3. Le registre "HTTP/3 Error Codes" gère un espace de 62 bits.
Les entrées enregistrées par ce document sont présentées à la section 8.1.
11.2.4. Types de flux (Stream Types)
Ce document établit un registre pour les types de flux unidirectionnels HTTP/3. Le registre "HTTP/3 Stream Types" gère un espace de 62 bits.
Tableau 5: types de flux HTTP/3 initiaux
| Type de flux (Stream Type) | Valeur (Value) | Spécification (Specification) | Expéditeur (Sender) |
|---|---|---|---|
| Flux de contrôle (Control Stream) | 0x00 | Section 6.2.1 | Les deux (Both) |
| Flux poussé (Push Stream) | 0x01 | Section 4.6 | Serveur (Server) |
Annexe A. Considérations pour la transition depuis HTTP/2 (Considerations for Transitioning from HTTP/2)
HTTP/3 est basé sur la conception d'HTTP/2 et partage la sémantique de base. Cette annexe résume les principales différences entre HTTP/2 et HTTP/3 pour aider les implémenteurs à comprendre la relation entre les deux protocoles.
A.1. Flux (Streams)
HTTP/3 utilise les flux QUIC, tandis qu'HTTP/2 utilise une abstraction de flux sur TCP. Différences clés :
- Identificateurs de flux : Les ID de flux dans HTTP/3 sont attribués par QUIC, pas par HTTP/3
- Priorité des flux : HTTP/3 n'inclut pas le schéma de priorité des flux d'HTTP/2
- Contrôle de flux : HTTP/3 utilise les mécanismes de contrôle de flux de QUIC
A.2. Types de trames HTTP (HTTP Frame Types)
De nombreux types de trames HTTP/2 sont préservés ou modifiés dans HTTP/3 :
Types de trames préservés :
- DATA (0x00) - Fonctionnalité similaire
- HEADERS (0x01) - Fonctionnalité similaire
- SETTINGS (0x04) - Similaire mais uniquement sur le flux de contrôle
- PUSH_PROMISE (0x05) - Fonctionnalité similaire
- GOAWAY (0x07) - Fonctionnalité similaire
Types de trames HTTP/2 supprimés ou remplacés :
- PRIORITY (0x02) - Supprimé dans HTTP/3
- RST_STREAM (0x03) - Remplacé par RESET_STREAM de QUIC
- PING (0x06) - Remplacé par la trame PING de QUIC
- WINDOW_UPDATE (0x08) - Remplacé par le contrôle de flux de QUIC
- CONTINUATION (0x09) - Non nécessaire dans HTTP/3
Nouveaux types de trames dans HTTP/3 :
- CANCEL_PUSH (0x03) - Annuler le push serveur
- MAX_PUSH_ID (0x0d) - Contrôler l'espace d'ID de push
A.3. Paramètres SETTINGS HTTP/2 (HTTP/2 SETTINGS Parameters)
Les paramètres dans HTTP/3 diffèrent d'HTTP/2 :
Paramètres supprimés :
- SETTINGS_HEADER_TABLE_SIZE - Remplacé par les paramètres QPACK
- SETTINGS_ENABLE_PUSH - Contrôlé via MAX_PUSH_ID
- SETTINGS_MAX_CONCURRENT_STREAMS - Contrôlé par les paramètres de transport QUIC
- SETTINGS_INITIAL_WINDOW_SIZE - Remplacé par le contrôle de flux QUIC
- SETTINGS_MAX_FRAME_SIZE - Non nécessaire dans HTTP/3
- SETTINGS_MAX_HEADER_LIST_SIZE - Remplacé par SETTINGS_MAX_FIELD_SECTION_SIZE
Paramètres préservés :
- SETTINGS_MAX_FIELD_SECTION_SIZE (0x06) - Similaire à SETTINGS_MAX_HEADER_LIST_SIZE d'HTTP/2
A.4. Codes d'erreur HTTP/2 (HTTP/2 Error Codes)
HTTP/3 définit son propre ensemble de codes d'erreur qui diffèrent des codes d'erreur d'HTTP/2. Les implémenteurs doivent noter les relations de correspondance mais ne doivent pas supposer une correspondance directe un-à-un.
A.5. Autres différences (Other Differences)
Gestion des connexions :
- HTTP/3 utilise la gestion des connexions de QUIC, y compris la migration de connexion et le support multichemin
- Le préambule de connexion d'HTTP/2 n'est pas nécessaire
Push serveur :
- Le mécanisme de push serveur dans HTTP/3 est similaire à HTTP/2 mais utilise différentes trames et types de flux
- Les ID de push sont explicites dans HTTP/3
Compression des champs :
- HTTP/3 utilise QPACK au lieu de HPACK
- QPACK est conçu pour gérer la livraison dans le désordre
Extensibilité :
- HTTP/3 fournit des mécanismes d'extension plus flexibles
- Les nouveaux types de trames, paramètres et types de flux peuvent être utilisés sans négociation