Résumé

  • La RFC 6455 lançait WebSocket avec un GET HTTP/1.1, Upgrade et une réponse 101. La RFC 7540 a écarté ce basculement de toute la connexion dans HTTP/2, où plusieurs flux cohabitent.
  • La RFC 8441 permet un CONNECT étendu portant :protocol = websocket, :scheme et :path après réception de SETTINGS_ENABLE_CONNECT_PROTOCOL = 1 du serveur. L’IANA enregistre le paramètre 0x8, initialement à 0.
  • Le flux accepté transporte les données WebSocket à côté des autres flux HTTP/2. Les anciens traitements Connection, Upgrade et Sec-WebSocket-Key/Accept ne servent plus à cette ouverture ; les trames WebSocket fonctionnent ensuite dans le tunnel.

Un interrupteur trop grand pour le couloir

Le protocole WebSocket de 2011 s’ouvrait par une requête HTTP/1.1. Le client envoyait un GET avec Upgrade: websocket et Connection: Upgrade; le serveur pouvait répondre 101 Switching Protocols. La connexion TCP devenait alors le canal bidirectionnel. Lorsqu’une connexion ne portait qu’une requête, on pouvait remettre tout le tuyau à cette conversation.

HTTP/2 a fait partager ce tuyau entre plusieurs flux. Une page peut recevoir une image pendant qu’un autre composant entretient un dialogue. La RFC 7540 a retiré le 101 de HTTP/2 : Upgrade et Connection concernent tout le transport, et un flux ne peut pas changer le destin de ses voisins. L’ouverture WebSocket héritée de HTTP/1.1 frappait donc à une porte qui n’existait plus.

Ce conflit avait un coût concret. Une application disposait déjà d’une connexion HTTP/2 pour sa page, mais devait trouver une autre voie pour la conversation en temps réel. Si le chat s’appropriait la connexion entière, les autres transferts perdaient leur place. Si l’on gardait l’ancienne cérémonie, on perdait le bénéfice du partage. La RFC 8441 redéfinit la taille de la ressource qu’un WebSocket peut demander.

Le serveur ouvre d’abord la petite porte

Le serveur annonce son accord avec SETTINGS_ENABLE_CONNECT_PROTOCOL = 1. Le registre des paramètres HTTP/2 de l’IANA lui attribue le code 0x8 et la valeur initiale 0. Après avoir reçu 1, le client peut utiliser le CONNECT étendu sur de nouveaux flux. S’il envoie le nouveau pseudo-en-tête avant cet accord, un pair qui ignore l’extension voit une requête mal formée. Le paramètre est une autorisation de changer le sens d’une requête, pas un badge de présentation.

Le client autorisé crée un flux avec :method = CONNECT et :protocol = websocket. Il ajoute :scheme, :path et :authority pour l’URI visée. Ce dernier champ est le piège. Dans un CONNECT ordinaire, il nomme l’hôte vers lequel ouvrir un tunnel ; dans le CONNECT étendu, il représente l’autorité de l’URI cible. La RFC 8441 interdit expressément au serveur d’ouvrir à cet hôte un tunnel classique simplement parce que CONNECT apparaît. :protocol précise ce que transportera le flux.

Une URI WebSocket sécurisée correspond au schéma cible https, et une URI non sécurisée à http. Le reste de la destination suit l’URI WebSocket. Pour un proxy HTTP/2 direct, la RFC préconise d’abord le CONNECT ordinaire vers le serveur WebSocket ; la version HTTP obtenue à l’intérieur du tunnel détermine ensuite la cérémonie d’ouverture. Le tunnel vers un proxy et le nouveau flux vers le service d’origine sont deux opérations distinctes.

Un flux commence là où l’ancien basculement s’arrêtait

Le CONNECT étendu remplace le GET d’ouverture. Il n’envoie ni Connection ni Upgrade, et ne traite pas l’échange HTTP/1.1 Sec-WebSocket-Key/Sec-WebSocket-Accept ; :protocol reprend cette fonction sur ce chemin. Les champs Origin, version WebSocket, sous-protocole et extensions restent utilisés selon les règles WebSocket. La procédure d’admission change, tandis que le protocole des trames demeure.

L’exemple de la RFC montre l’autorisation du serveur, la demande CONNECT puis une réponse :status = 200. Des trames DATA HTTP/2 transportent ensuite les données WebSocket dans les deux sens. Le flux joue le rôle que la connexion TCP jouait dans la RFC 6455, à côté de requêtes classiques ou d’autres tunnels. Priorité, annulation et contrôle du débit restent ceux de HTTP/2. END_STREAM et RST_STREAM figurent la fin normale ou exceptionnelle de ce canal particulier.

Le changement répartit mieux le pouvoir. Un chat peut rester ouvert sans retenir les images de la page. Le serveur peut refuser la nouveauté en omettant son paramètre ; le client le sait avant d’essayer. L’accord est lisible dans les paramètres et la requête. Aucun intermédiaire n’a besoin de deviner ce qu’un ancien 101 ferait à une connexion partagée.

Les autres locataires ont gardé leur connexion

La RFC 8441 choisit une modification limitée. Elle admet qu’une intégration plus profonde serait possible, mais le CONNECT étendu règle le problème immédiat de WebSocket et HTTP/2 en parallèle. La norme de 2018 a changé l’entrée ; après l’ouverture, les trames WebSocket et la plupart des exigences de sécurité de la RFC 6455 continuent. Le masquage des trames est une autre histoire. Ici, la question est de savoir quel flux reçoit le droit de les porter.

Les quatre sources officielles prouvent le mécanisme et son inscription au registre. Pour établir son usage par un service nommé, il faudrait des versions datées de clients, serveurs et proxys ainsi que des échanges SETTINGS et HEADERS capturés. Le résultat historique est net : HTTP/2 n’a pas cédé une connexion commune pour une conversation ; WebSocket a obtenu un flux dont l’ouverture doit être acceptée.