Ce module ajoute le support de HTTP/2 (RFC 7540) au serveur HTTP Apache.
Il s'appuie sur la bibliothèque libnghttp2 pour implémenter le moteur de base http/2.
Pour mettre en oeuvre les fonctionnalités décrites dans ce
document, vous devez activer HTTP/2 en utilisant la directive
h2
(HTTP/2 avec TLS) at h2c
(HTTP/2 avec TCP).
Voici deux types de configuration courant :
Permet une négociation HTTP/2 (h2) via TLS ALPN au sein d'un
h2
.
Permet une négociation HTTP/2 (h2) via TLS ALPN au sein d'un
Si vous avez besoin d'informations supplémentaires à propos du protocole, veuillez vous reporter à la HTTP/2 FAQ.
Activer HTTP/2 sur votre serveur Apache a un impact sur la consommation de ressources, et si votre site est très actif, il est conseillé d'en prendre sérieusement en compte les implications.
HTTP/2 attribue à chaque requête qu'il reçoit son propre thread de travail pour son traitement, la collecte des résultats et l'envoie de ces derniers au client. Pour y parvenir, il lui faut lancer des threads supplémentaires, et ceci constituera le premier effet notable de l'activation de HTTP/2.
Dans l'implémentation actuelle, ces threads de travail font partie
d'un jeu de threads distinct de celui des threads de travail du MPM
avec lequel vous êtes familié. Il s'agit simplement du mode de
fonctionnement actuel, et il n'en sera pas obligatoirement toujours
ainsi (il est cependant probable que la situation restera inchangée
avec la version 2.4.x). De par ce mode de fonctionnement, les
threads de travail HTTP/2, ou plus simplement H2 ne seront pas
affichés par
Autre changement à surveiller : la consommation de mémoire. En
effet, comme HTTP/2 conserve plus d'informations sur le serveur pour
gérer toutes les requêtes en cours, leurs priorités et
interdépendances, il aura toujours besoin de plus de mémoire que
pour un traitement en HTTP/1.1. Trois directives permettent de
limiter l'empreinte mémoire d'une connexion HTTP/2 :
La directive
La directive
En outre, la directive
De nombreux site utilisent le même certificat TLS pour plusieurs serveurs virtuels. Ce certificat référence un nom de serveur générique comme '*.example.org' ou plusieurs noms de serveur différents. Les navigateurs qui utilisent HTTP/2 détectent ce comportement et réutilisent une connexion déjà ouverte pour ces serveurs.
Ceci améliore considérablement les performances, mais il y a un prix à payer : il faut accorder un soin tout particulier à la configuration de tels serveurs virtuels. Le problème réside dans le fait que plusieurs requêtes pour plusieurs serveurs virtuels vont se partager la même connexion TLS, et ceci empêche toute renégociation car le standard HTTP/2 l'interdit.
Ainsi, lorsque plusieurs de vos serveurs virtuels utilisent le même certificat et si vous souhaitez utiliser HTTP/2 pour y accéder, vous devez vous assurer que tous vos serveurs virtuels possèdent exactement la même configuration SSL. En particulier, ils doivent utiliser les mêmes protocole, algorithme de chiffrement et configuration pour la vérification du client.
Dans le cas contraire, Apache httpd le détectera et renverra au client un code de réponse spécial, 421 Misdirected Request.
Ce module peut être configuré pour fournir des informations en
rapport avec HTTP/2 sous la forme de variables d'environnement
supplémentaires dans l'espace de nommage SSI et CGI, ainsi que dans les
configurations personnalisées de le journalisation (voir
%{VAR_NAME}e
).
Nom variable : | Type : | Description : |
---|---|---|
HTTPe | drapeau | HTTP/2 est utilisé. |
H2PUSH | drapeau | La fonctionnalité HTTP/2 Server Push est activée pour cette requête et supportée par le client. |
H2_PUSH | drapeau | autre nom pour H2PUSH |
H2_PUSHED | chaîne | vide ou
PUSHED pour une requête pushée par le serveur. |
H2_PUSHED_ON | nombre | numéro du flux HTTP/2 qui a déclenché le push de cette requête. |
H2_STREAM_ID | nombre | numéro du flux HTTP/2 de cette requête. |
H2_STREAM_TAG | chaîne | identifiant
de flux unique du processus HTTP/2 composé de l'identifiant de la
connexion et de l'identifiant du flux séparés par - . |
Cette directive permet d'activer/désactiver
l'utilisation du mode HTTP/2 Direct. Elle doit être
située dans une section
La notion de communication directe signifie que si les premiers octets reçus par le serveur correspondent à un en-tête HTTP/2, le protocole HTTP/2 est utilisé sans négociation supplémentaire. Ce mode est défini pour les transmissions en clair (h2c) dans la RFC 7540. Son utilisation avec les connexions TLS n'est pas officiellement supportée.
Lorsque le protocole h2 ou h2c n'est pas activé via la
directive
Pour un client qui sait qu'un serveur supporte h2c, la communication directe HTTP/2 dispense le client d'une mise à jour HTTP/1.1, ce qui entraîne une amélioration des performances et évite les restrictions sur les corps de requête suite à une mise à jour.
Cette directive rend aussi h2c plus attractif pour les communications de serveur à serveur lorsque la connexion est sure ou peut être sécurisée d'une manière ou d'une autre.
Cette directive permet d'activer/désactiver l'utilisation de la fonctionnalité server push du protocole HTTP/2.
Lorsqu'un client demande une ressource particulière, le protocole HTTP/2 permet au serveur de lui fournir des ressources supplémentaires. Ceci s'avère utile lorsque ces ressources sont reliées entre elles, ce qui peut laisser supposer que le client va probablement les demander dans un délai plus ou moins long. Le mécanisme de pushing permet alors au client d'économiser le temps qu'il lui aurait fallu pour demander ces ressources supplémentaires lui-même. Par contre, fournir au client des ressources dont il n'a pas besoin ou qu'il possède déjà constitue une perte de bande passante.
Les server pushes sont détectés en inspectant les
en-têtes Link
des réponses (voir
https://tools.ietf.org/html/rfc5988 pour la
spécification). Lorsqu'un lien spécifié de cette manière
possède l'attribut rel=preload
, il est
considéré comme devant faire l'objet d'un push.
Les en-têtes link des réponses sont soit définis par
l'application, soit configurés via la directive
Comme le montre l'exemple, il est possible d'ajouter autant d'en-têtes link que l'on souhaite à une réponse, ce qui déclenchera autant de pushes. Cette fonctionnalité doit donc être utilisée avec prudence car le module ne vérifie pas si une ressource n'a pas déjà été "pushée" vers un client.
Les PUSH HTTP/2 sont activés par défaut. Vous pouvez activer/désactiver cette fonctionnalité pour toute connexion au serveur au niveau global ou serveur virtuel. Vous pouvez en outre désactiver PUSH pour un jeu de ressources dans une section Directory/Location. Notez que ceci permet de contrôler quelles ressources peuvent déclencher un PUSH, mais pas les ressources qui peuvent être envoyées via PUSH.
Enfin, il est important de savoir que les pushes ne se produisent que si le client en manifeste le désir ; la plupart des navigateurs le font, mais certains, comme Safari 9, ne le font pas. En outre, les pushes ne se produisent que pour les ressources de la même autorité que celle de la réponse originale.
Cette directive permet de définir le nombre maximum de pushes
qui seront enregistrés pour une connexion HTTP/2. Elle peut être
placée dans une section
Le journal des pushes enregistre un condensé (sous la forme d'un nombre de 64 bits) des ressources préchargées (leurs URLs) afin d'éviter les duplications de pushes pour une même connexion. Cependant, ces données ne sont pas conservées, et les clients qui ouvrent une nouvelle connexion se verront à nouveau affecter les mêmes pushes. A ce titre, une étude est en cours pour permettre au client de supprimer le condensé des ressources qu'il possède déjà, et par là-même de réinitialiser le journal des pushes à chaque nouvelle connexion.
Si la taille maximale est atteinte, les nouvelles entrées remplacent les plus anciennes. Une entrée du journal nécessitant 8 octets, un journal de 256 entrées consomme 2 Ko de mémoire.
Si cette directive est définie à 0, le journal des pushes est désactivé.
Cette directive permet de définir une gestion de priorité des pushes en fonction du type de contenu de la réponse. Elle est en général définie au niveau du serveur principal, mais peut aussi l'être au niveau d'un serveur virtuel.
Les pushes HTTP/2 sont toujours liés à une requête client. Chaque paire requête/réponse de cette sorte, ou flux, possède une dépendance et un poids qui définissent la priorité du flux.
Lorsqu'un flux dépend d'un autre, disons X dépend de Y, alors Y reçoit toute la bande passante avant que X n'en reçoive ne serait-ce qu'une partie. Notez que cela ne signifie en rien que Y bloque X ; en effet, si Y n'a aucune donnée à envoyer, toute la bande passante qui lui est allouée peut être utilisée par X.
Lorsque plusieurs flux dépendent d'un même autre flux, disons X1 et X2 dépendent tous deux de Y, le poids détermine la bande passante allouée. Ainsi, si X1 et X2 possèdent le même poids, ils recevront tous deux la moitié de la bande passante disponible. Si le poids de X1 est égal au double de celui de X2, X1 recevra une bande passante double de celle de X2.
En fin de compte, tout flux dépend du flux racine qui reçoit toute la bande passante disponible mais n'envoie jamais de données. Cette bande passante est ainsi répartie entre les flux enfants selon leur poids. Ces derniers l'utilisent alors pour envoyer leurs données ou pour la répartir entre leurs propres flux enfants, et ainsi de suite. Si aucun des flux enfants n'a de données à envoyer, la bande passante est attribuée à d'autres flux selon les mêmes règles.
Ce système de priorités a été conçu de façon a toujours pouvoir utiliser la bande passante disponible tout en définissant des priorités et en attribuant des poids aux différents flux. Ainsi, tous les flux sont en général initialisés par le client qui lui-même définit les priorités.
Seul le fait de savoir qu'un flux implique un PUSH permet au serveur de décider quelle est la priorité initiale d'un tel flux. Dans les exemples ci-dessous, X est le flux client. Il dépend de Y et le serveur décide de "PUSHer" les flux P1 et P2 sur X.
La règle de priorité par défaut est :
Elle peut se traduire par "Envoyer un flux PUSH avec tout type de contenu et dépendant du flux client avec le poids 16". P1 et P2 seront alors envoyés après X, et comme leurs poids sont identiques, il se verront allouer la même quantité de bande passante.
Ce qui peut se traduire par "Envoyer toute ressource CSS dans la
même dépendance et avec le même poids que le flux client". Si le
type de contenu de P1 est "text/css", il dépendra de Y (comme X)
et son poids effectif sera calculé selon la formule : P1ew
= Xw * (P1w / 256)
. Si P1w est de 256, Le poids effectif
de P1 sera le même que celui de X. Si X et P1 ont des données à
envoyer, il se verront allouer la même quantité de bande
passante.
Avec un Pw de 512, un flux entrelacé et PUSHé aura un poids double de celui de X. Avec un poids de 128, son poids ne sera que la moitié de celui de X. Notez que les poids effectifs sont toujours plafonnés à 256.
Dans cet exemple, tout flux PUSHé dont le contenu est de type 'application/json' sera envoyé avant X, ce qui rend P1 dépendant de Y et X dépendant de P1. Ainsi, X sera mis en attente aussi longtemps que P1 aura des données à envoyer. Le poids effectif est hérité du flux client, et l'attribution d'un poids spécifique n'est pas autorisée.
Vous devez garder à l'esprit que les spécifications en matière de priorités sont limitées par les ressources disponibles du serveur. Si un serveur ne dispose d'aucun processus/thread de travail pour les flux PUSHés, les données du flux considéré ne seront envoyées que lorsque les autres flux auront terminé l'envoi des leurs.
Enfin et surtout, il convient de tenir compte de certaines particularités de la syntaxe de cette directive :
Cette directive permet d'activer/désactiver l'utilisation de la
méthode de mise à jour pour passer de HTTP/1.1 à HTTP/2. Elle
doit être placée dans une section
Cette méthode de changement de protocole est définie dans HTTP/1.1 et utilise l'en-tête "Upgrade" (d'où son nom) pour indiquer l'intention d'utiliser un autre protocole. Cet en-tête peut être présent dans toute requête sur une connexion HTTP/1.1.
Elle activée par défaut pour les transmissions en clair (h2c), et désactivée avec TLS (h2), comme préconisé par la RFC 7540.
Sachez cependant que les mises à jour ne sont acceptées que pour
les requêtes qui ne possèdent pas de corps. Le requêtes de type
POST et PUT avec un contenu ne feront jamais l'objet d'une mise
à jour vers HTTP/2. Se référer à la documentation de la
directive
Cette directive n'a d'effet que si h2 ou h2c est activé via la
directive
Cette directive permet de définir le nombre maximal de flux
actifs par session (connexion) HTTP/2 accepté par le serveur.
Selon la RFC 7540, un flux est considéré comme actif s'il n'est
ni en attente
ni fermé
.
Cette directive permet de définir la quantité maximale de données en sortie mises en tampon mémoire pour un flux actif. Ce tampon mémoire n'est pas alloué pour chaque flux en tant que tel. Les quantités de mémoire sont définies en fonction de cette limite lorsqu'elles sont sur le point d'être allouées. Le flux s'arrête lorsque la limite a été atteinte, et ne reprendra que lorsque les données du tampon auront été transmises au client.
Cette directive permet de définir la taille maximale des paquets de données envoyés par le client au serveur, et limite la quantité de données que le serveur doit mettre en tampon. Le client arrêtera d'envoyer des données sur un flux lorsque cette limite sera atteinte jusqu'à ce que le serveur indique qu'il dispose d'un espace suffisant (car il aura traité une partie des données).
Cette limite n'affecte que les corps de requêtes, non les métadonnées comme les en-têtes. Par contre, elle n'affecte pas les corps de réponses car la taille maximale de ces derniers est gérée au niveau des clients.
Cette directive permet de définir le nombre minimal de threads à
lancer pour le traitement HTTP/2 de chaque processus enfant. Si
cette directive n'est pas définie, mpm
utilisé.
Cette directive permet de définir le nombre maximal de threads à
lancer pour le traitement HTTP/2 de chaque processus enfant. Si
cette directive n'est pas définie, mpm
utilisé.
This directive sets the maximum number of worker threads to spawn
per child process for HTTP/2 processing. If this directive is not used,
mod_http2
will chose a value suitable for the mpm
module loaded.
Cette directive permet de définir le nombre maximal de secondes
pendant lequel une unité de traitement h2 pourra rester inactive
avant de s'arrêter elle-même. Cet arrêt ne peut cependant se
produire que si le nombre d'unités de traitement h2 dépasse
Cette directive permet de définir si les requêtes HTTP/2 doivent
être sérialisées au format HTTP/1.1 pour être traitées par le
noyau de httpd
, ou si les données binaires reçues
doivent être passées directement aux request_rec
s.
La sérialisation dégrade les performances, mais garantit une meilleure compatibilité ascendante lorsque des filtres ou programmes accroche personnalisés en ont besoin.
Cette directive permet de définir si les vérifications de
sécurité sur les connexions HTTP/2 doivent être exclusivement en
mode TLS (https:). Elle peut être placée au niveau du serveur
principal ou dans une section
Les vérifications de sécurité nécessitent TLSv1.2 au minimum et l'absence de tout algorithme de chiffrement listé dans la RFC 7540, Appendix A. Ces vérifications seront étendues lorsque de nouveaux prérequis en matière de sécurité seront mis en place.
Le nom provient des définitions Mozilla Security/Server Side TLS où il est question de "modern compatibility". Mozilla Firefox et d'autres navigateurs imposent la "modern compatibility" pour les connexions HTTP/2. Comme toute chose en matière de sécurité opérationnelle, c'est une cible mouvante susceptible d'évoluer dans le futur.
Un des buts de ces vérifications dans
En fin de compte, la sécurité de la connexion TLS est déterminée
par les directives de configuration du serveur pour
Cette directive permet de définir le nombre d'octets à envoyer
dans les petits enregistrements TLS (~1300 octets) avant
d'atteindre leur taille maximale de 16 ko pour les connexions
https: HTTP/2. Elle peut être définie au niveau du serveur
principal ou pour des
Les mesures effectuées par les laboratoires de performances de Google montrent que les meilleurs performances sont atteintes pour les connexions TLS si la taille initiale des enregistrements reste en deça du niveau du MTU afin de permettre à la totalité d'un enregistrement d'entrer dans un paquet IP.
Comme TCP ajuste son contrôle de flux et sa taille de fenêtre, des enregistrements TLS trop longs peuvent rester en file d'attente ou même être perdus et devoir alors être réémis. Ceci est bien entendu vrai pour tous les paquets ; cependant, TLS a besoin de la totalité de l'enregistrement pour pouvoir le déchiffrer. Tout octet manquant rendra impossible l'utilisation de ceux qui ont été reçus.
Lorqu'un nombre suffisant d'octets a été transmis avec succès, la connexion TCP est stable, et la taille maximale (16 ko) des enregistrements TLS peut être utilisée pour des performances optimales.
Dans les architectures où les serveurs sont atteints par des machines locales ou pour les connexions de confiance seulement, la valeur de cette directive peut être définie à 0, ce qui a pour effet de désactiver la "phase de chauffage".
Dans l'exemple suivant, la phase de chauffage est effectivement désactivée en définissant la directive à 0.
Cette directive permet de spécifier le nombre de secondes avant
lequel une connexion TLS inactive va diminuer
la taille des paquets de données à une valeur inférieure (~1300
octets). Elle peut être définie au niveau du serveur principal
ou pour un
Voir la directive
Dans les situations où les connexions peuvent être considérées comme fiables, ce délai peut être désactivé en définissant cette directive à 0.
Dans l'exemple suivant, la directive est définie à 0, ce qui désactive tout retour à une phase de préchauffage des connexions TLS. Les connexions TLS déjà préchauffées conservent donc toujours leur taille de paquet de données maximale.
Cette directive permet de définir un délai pour les opérations
de lecture/écriture lorsqu'une connexion HTTP/2 a été
négociée. Elle peut être définie pour l'ensemble du serveur ou
pour un
Elle est similaire à la directive
Une valeur de 0 signifie qu'aucun délai n'est imposé.
Cette directive permet de définir la durée de vie des connexions
HTTP/2 inactives. Sa portée peut s'étendre à l'ensemble du
serveur, ou seulement à un
Cette directive est équivalente à la directive
Pour les MPMs non-asynch (prefork, worker), la durée de vie sera par défaut égale à H2Timeout. Pour les MPMs async, il semble qu'aucune action ne soit à entreprendre pour la durée de vie des connexions HTTP/1.
Cette directive permet de définir la durée de vie des flux
HTTP/2 pour les requêtes individuelles. Sa portée peut s'étendre
à l'ensemble du serveur, ou seulement à un
De par la nature de HTTP/2 qui transmet plusieurs requêtes sur une seule connexion et gère une planification des priorités, les flux individuels ne sont pas susceptibles de recevoir des données en entrée beaucoup plus longtemps qu'une connexion HTTP/1.1.
Si cette directive est définie à 0, la durée de vie des flux HTTP/2 n'a aucune limite, et il peuvent attendre indéfiniment l'arrivée de données à lire ou écrire. Cela expose cependant le serveur à atteindre sa limite en nombre de threads.
Un site peut nécessiter une augmentation de cette valeur en fonction de votre gestion des flux PUSHés, des priorités et de la réactivité générale. Par exemple, si vous PUSHez une ressource de taille importante avant celle qui a fait l'objet d'une requête, le flux initiale n'effectuera aucune écriture jusqu'à ce que la ressource PUSHée ne soit envoyée dans son intégralité.
Cette directive permet de définir la manière de gérer les
contenus de fichiers dans les réponses. Lorsqu'elle est à off
(sa valeur par défaut), les descripteurs de fichiers sont
transmis par le processus de traitement de la requête vers la
connexion principale en utilisant le système habituel de mise en
réserve d'Apache pour gérer le durée de vie du fichier.
Lorsqu'elle est à on
, le contenu du fichier est
recopier pendant le traitement de la requête et ces données
mises en tampon sont transmises vers la connexion principale, ce
qui s'avère avantageux lorsqu'un module tiers injecte dans la
réponse des fichiers possédant des durées de vie différentes.
Un exemple de ces modules tiers : mod_wsgi
qui peut
injecter des descripteurs de fichiers dans la réponse. Ces
fichiers sont fermés lorsque Python estime que le traitement est
terminé, alors que
Lorsqu'il sont activés pour un répertoire, les PUSHes HTTP/2 seront tentés pour tous les chemins ajoutés via cette directive. Cette dernière peut être utilisée plusieurs fois pour le même répertoire.
Cette directive propose des ressources beaucoup plus tôt que les
en-têtes Link
de 103 Early Hints
. Ceci
implique que les clients qui ne supportent pas PUSH recevront
quand-même rapidement des propositions de préchargement.
A la différence de la définition d'en-têtes de réponse
Link
via
En ajoutant l'option critical
à une telle
ressource, le serveur la traitera prioritairement, et une fois
les données disponibles, ces dernières seront envoyées avant les
données de la requête principale.
Cette directive permet de définir si les réponses intermédiaires contenant un code d'état HTTP 103 doivent être envoyées au client ou non. Par défaut ce n'est actuellement pas le cas car certains clients ont encore des problèmes avec les réponses intermédiaires inattendues.
Lorsque cette directive est définie à on
, les
ressources PUSHées définie par la directive
H2PushResource
déclenchent une réponse
intermédiaire 103 avant la réponse finale. Cette réponse 103
comporte des en-têtes Link
qui provoquent le
préchargement
des ressources considérées.
La valeur par défaut 0 indique qu'aucun octet de bourrage ne sera ajouté aux trames utiles comme HEADERS, DATA et PUSH_PROMISE. Ceci correspond au comportement des versions précédentes. Dans ce cas et sous certaines conditions, un observateur du trafic réseau pourra alors déterminer la longueur de ces trames dans le flux TLS.
Si on attribue à numbits la valeur 1-8, un nombre aléatoire d'octets entre 0 et 2^numbits sont ajoutés à chaque trame. Une valeur aléatoire d'octets de bourrage est attribué indépendamment à chaque trame que le module renvoie au client.
Pour améliorer la dissimulation de la longueur des trames, on peut augmenter le nombre moyen d'octets de bourrage, mais cela augmente d'autant le trafic réseau. Le nombre optimal d'octets de bourrage dépend donc du type de trafic web que le serveur engendre.
La valeur par défaut de 0 (aucun octet de bourrage) a été choisie dans un but de compatibilité ascendante. Il peut en effet exister des installations où les octets de bourrage ne sont pas souhaités ou sont néfastes. La cause principale peut provenir d'un client dont l'implémentation comporte des erreurs.