Dans ce tutoriel je vous propose de découvrir le protocole HTTP et ses évolutions. L'objectif est de comprendre comment ces changements affectent notre manière de concevoir des applications webs.
HTTP/1.1
La première version du protocole (créée en 1996 et évolué en 1.1 en 1999) propose un fonctionnement simple basé sur une représentation des requêtes et réponses sous forme de texte au travers du protocole TCP.
Chaque ressource (fichier) est échangé au travers d'une connexion TCP. Les données reçues sont formatées de la manière suivante :
- La première ligne représente la méthode, le chemin et la version du protocole utilisée.
- Les lignes suivantes représentent les en-têtes séparées par un saut de ligne.
- Une ligne vide qui marque la fin des en-têtes.
- Optionnellement, les lignes suivantes peuvent contenir le corps de la requête.
La réponse sera formatté de la même manière à la différence de la première ligne.
- La première ligne représente la version du protocole, le statuts (nombre à 3 chiffres) suivi du verbe.
- Les lignes suivantes représentent les en-têtes séparées par un saut de ligne.
- Une ligne vide qui marque la fin des en-têtes.
- Optionnellement, les lignes suivantes peuvent contenir le corps de la réponse.
Limitation
Cette première itération du protocole HTTP réside dans le fait de devoir créer une connexion TCP pour chaque ressource que l'on souhaite charger (on notera d'ailleurs que les navigateurs imposent une limite sur le nombre de connexion simultanées par origine). Pour contrebalancer, cette limitation un système de "Pipeline" a été introduit dans la version 1.1 du protocole mais n'a jamais été supporté convenablement par les navigateurs à cause de trop nombreux bugs.
L'autre problème réside dans l'échange des en-têtes qui peut rapidement prendre beaucoup de place alors qu'elles sont souvent répétées.
HTTP/2
La seconde version du protocole repense complètement l'échange d'information avec un échange binaire et un multiplexage des requêtes / réponse.
Les données sont maintenant échangée sous forme de trames de taille variable qui vont être associées à une flux au travers d'un identifiant.
Il existe différents type de trames mais celles qui vont nous intéresser sont les en-têtes de type HEADERS et DATA.
Multiplexage
Ce nouveau système de communication permet au client et au serveur d'échanger des fichiers avec une seul connexion TCP (ce qui permet de faire l'économie de la poignée de main à chaque nouvelle ressource). Aussi, avec ce système de trame le serveur n'est pas obligé de répondre immédiatement après chaque requête. Il peut recevoir plusieurs trame de requête (plusieurs flux) avant de commencer à répondre. Il existe même un système de priorisation qui permet au client de définir les ressources à traiter en priorité.
En-têtes compressées via HPACK
Contrairement à la version 1, les en-têtes sont compressées à l'aide du système HPACK qui permet de limiter la taille des trames HEADERS. Ce système repose sur un index statique (remplit par les en-têtes les plus communes) et un index dynamique qui se remplit au fil des requêtes / réponses. Ainsi, une ligne d'en tête peut faire référence à cet index et prendre une place significativement moins importante.
Push server
Un autre atout du HTTP/2 est la possibilité d'envoyer des ressources sans forcément que le client en ai fait la demande. Pour cela le serveur peut envoyer une trame PUSH_PROMISE ce qui permet d'initialiser un flux de manière autonome (cette capacité peut être utilisé avec le Server Sent Event).
Inconvénients
Même si les avantages de cette nouvelle version sont clairs il est important de noter qu'ils viennent aussi avec quelques inconvénients.
Protocole plus complexe
Comme on l'a vu, le protocole est beaucoup plus complexe à interpréter et cela se traduit par une consommation plus importantes de ressources côté serveur.
Surcharge serveur
Le support de multiples requêtes par connexion peut potentiellement surcharger les serveurs qui ne sont pas configurés pour gérer la charge accrue par cette version du protocole. Il est possible de définir, au travers d'une trame SETTINGS, le nombre de flux qui peuvent être ouvert (via le drapeau SETTINGS_MAX_CONCURRENT_STREAMS
) en parallèle.
Ce paramètre est d'ailleurs au cœur d'une attaque Fast Reset qui consiste à envoyer des requête de réinitialisation immédiatement après une requête, ce qui permet d'envoyer un nombre illimité de requête sans jamais dépasser la limite imposée par SETTINGS_MAX_CONCURRENT_STREAMS
.
Dépendant du TLS
En soit, ce problème ne vient pas du protocole en lui même, mais plutôt de son adoption. HTTP/2 ne spécifie rien en ce qui concerne le chiffrement des données Dans les fait, les navigateurs imposent l'utilisation du TLS lorsqu'il s'agit de l'utilisation de l'HTTP/2. C'est d'ailleurs lors de la phase de poignée de main du TLS que la liste des protocoles supportées est diffusée par le serveur. Sans cette poignée de main les navigateur sélectionne l'HTTP/1.1 comme protocole d'échange.
HTTP/3
La version 3 est l'itération la plus récente du protocole et a été publié en Juin 2022. L'objectif de cette nouvelle version est d'améliorer la fiabilité et la sécurité du protocole à travers plusieurs objectifs :
- Permettre la migration de réseau, pour maintenir une connexion même si le client change de réseau (pour s'adapter aux smartphones qui passent du Wifi au réseau mobile par exemple).
- Améliorer le "Time to First byte" (TTB) en permettant une communication sans aller-retour avec un envoie de données dès les premiers paquets.
Ces améliorations passent par un changement important : l'abandon du protocole TCP au profit du protocole QUIC basé sur le protocole UDP.
Pourquoi abandonner TCP ?
Le protocole TCP pose 2 problèmes vis à vis des objectifs que cherche à atteindre cette nouvelle itération de l'HTTP/3.
- Une connexion TCP ne peut être maintenue lorsqu'il y a un changement de réseau de la part du client.
- L'échange de données ne se fait qu'après l'étape de poignée de main qui nécessite 3 envois de données.
Pour contourner ces limitations il a été décidé de se baser sur un tout nouveau protocole : QUIC. Ce protocole repose sur le protocole UDP afin de limiter les changements matériels nécessaires à faire pour son support vu que les périphériques réseaux sont déjà à même de comprendre ce type d'échange.
Les fonctionnalités de QUIC
Une grande partie de la complexité des échanges est maintenant déplacée dans ce protocole. Le protocole est plutôt complexe mais dans les grandes lignes il intègre les fonctionnalités suivantes :
- Une latence réduite avec un nombre d'aller retour réduit (un seul aller-retour qui combine connexion et chiffrement).
- Le chiffrement est intégré, via TLS, dans le protocole.
- Le multiplexage permet la gestion de plusieurs flux de données sur une seul connexion.
- Les données, sont envoyées sous forme de trames associées à des flux (directionnels ou bidirectionnels) qui sont indépendants (une erreur sur un des flux ne bloque pas les autres flux).
- Un système anti congestion pour limiter de saturer le client ou le serveur.
- Un système d'acquittement permet de marquer la réception de plusieurs trames en une fois.
Le protocole HTTP/3
A part ce changement de protocole, la version 3 du HTTP se comporte de manière assez similaire à la version 2 avec quelques simplifications vu que le protocole QUIC gère une partie des choses qui était auparavant gérée par le protocole HTTP.
- Des trames SETTINGS permettent de définir les paramètres des échanges et sont envoyés dans des flux unidirectionnels.
- Une requête / réponse passe par un flux bidirectionnel dans lequel sera échangé des trames HEADERS et DATA.
Compression QPACK
Comme pour l'HTTP/2, les en-têtes sont compressées mais cela se fait au travers d'un nouveau système : QPACK. Ce nouveau système est nécessaire pour gérer le côté non ordonnées des trames QUIC mais le principe est sensiblement le même que pour HPACK.
Inconvénients
Ce protocole est encore assez récent donc il est difficile de faire un bilan sur ses inconvénients mais on peut déjà souligner plusieurs problèmes.
UDP limité
Le premier problème est l'utilisation d'un tout nouveau protocole qui peut souvent être bloqué ou limité par les réseaux pour des raisons de sécurité. En dehors du streaming audio / vidéo le protocole UDP n'est utilisé que pour les échanges DNS il n'est donc pas rare qu'il soit bloqué. Le support de l'HTTP/3 nécessite donc de faire des changement dans la configuration des parefeux.
Découvrabilité
Le second problème est la découvrabilité du protocole. Les navigateur ne pouvant pas déterminer si un serveur support l'HTTP/3 ils commencent leur contacte avec la version 2 ou 1 et le support sera déclaré au travers d'une en-tête particulière alt-svc
.
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Le navigateur mémorise ensuite cette information et utilisera HTTP/3 pour les prochaines ressources.
Support
Le protocole est encore récent et son support est pour le moment relativement limité (à l'heure où j'écris ces lignes).
- nginx supporte l'HTTP/3 mais son support est considéré comme expérimental.
- Caddy Serveur supporte l'HTTP/3
- Apache ne supporte pas HTTP/3
Bénéfices à la marge
Enfin, le principal frein a son adoption est le rapport changement / bénéfice. Par exemple Google annonce une réduction de latence de 2% par recherche ce qui est relativement faible par rapport à la quantité de changement que le support implique. Contrairement au passage de l'HTTP/1 vers l'HTTP/2 où les bénéfices était clairement visibles, les bénéfice de l'HTTP/3 reste limités en fonctions des usages. Il sera donc plus difficile de convaincre.