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.