Le cache HTTP partagé est mort en 2020

performancergpdweb

Il existe un argument que je vois encore passer en revue de code, en réunion et dans les fils de discussion : « charge tes polices depuis fonts.google.com, comme ça si le visiteur les a déjà téléchargées sur un autre site, il les a déjà en cache ». L'argument est élégant. Il a été vrai. Il ne l'est plus depuis octobre 2020, et il vaut la peine de comprendre pourquoi, parce que le raisonnement qui l'a tué s'applique à bien plus que la typographie.

Ce que promettait le cache partagé

Le raisonnement d'origine était solide. Le cache HTTP des navigateurs était indexé par l'URL de la ressource, et par rien d'autre. Un fichier téléchargé depuis fonts.gstatic.com en visitant un site A restait disponible pour un site B, un site C, n'importe quel site. Plus le CDN était populaire, plus la probabilité d'un cache déjà chaud était élevée. À l'échelle du web, la mutualisation avait un sens réel.

Le problème, c'est que cette même mutualisation constituait un canal de fuite. Si un site peut mesurer qu'une ressource est déjà en cache, il peut déduire que vous avez visité un autre site. En chaînant assez de mesures, on reconstitue un historique de navigation, et on fabrique un identifiant persistant qui survit à la suppression des cookies. C'est la famille d'attaques dite XS-Leaks, et les supercookies.

Les navigateurs ont tranché

Chrome a partitionné son cache HTTP à partir de la version 86, déployée courant fin 2020. Une ressource n'est plus indexée par sa seule URL, mais par une clé qui inclut le site de premier niveau qui la demande. La même police téléchargée sur deux sites différents occupe désormais deux entrées de cache distinctes. La mutualisation a disparu par construction.

Firefox a suivi avec la version 85, le 26 janvier 2021, et est allé plus loin encore. Mozilla ne partitionne pas seulement le cache HTTP : la liste couvre le cache d'images, de favicons, HSTS, OCSP, de feuilles de style, DNS, d'authentification HTTP, Alt-Svc, de certificats TLS, et, explicitement, le cache de polices. Les connexions groupées, les préconnexions et les identifiants de session TLS sont partitionnés eux aussi. Autrement dit, même la connexion réutilisée vers fonts.gstatic.com ne traverse plus la frontière entre deux sites.

Safari partitionne également, par eTLD+1 du site de premier niveau, et l'a fait avant les autres.

Les trois moteurs qui comptent ont donc supprimé la propriété exacte sur laquelle l'argument reposait. Ce n'est pas une dépréciation annoncée, ni un mode expérimental : c'est le comportement par défaut de tous les navigateurs de vos visiteurs depuis cinq ans.

Le chiffre qui devrait clore le débat

Le plus intéressant n'est pas que le cache partagé ait disparu. C'est ce que sa disparition a coûté, mesuré par Google sur son propre parc :

Le taux global d'échec de cache augmente d'environ 3,6 %, les variations du FCP (First Contentful Paint) sont modestes (~0,3 %), et la fraction globale d'octets chargés depuis le réseau augmente d'environ 4 %.

Trois dixièmes de pour cent de FCP. Google a démantelé le cache inter-sites du web entier et l'a payé 0,3 % de temps d'affichage. Cela dit quelque chose de rétrospectif et d'assez brutal : même avant le partitionnement, le gain réel de la mutualisation était marginal. On a longtemps optimisé pour un effet que personne n'avait mesuré.

Ce qui reste, une fois l'argument retiré

Sans cache partagé, il faut regarder ce que coûte réellement un appel à Google Fonts, et le bilan s'inverse.

Une intégration classique commence par une feuille de style sur fonts.googleapis.com. Cette feuille référence ensuite les fichiers de polices, hébergés sur fonts.gstatic.com. Deux domaines, donc deux résolutions DNS, deux poignées de main TLS, et surtout une chaîne de requêtes : le navigateur ne peut pas découvrir l'URL du fichier de police avant d'avoir reçu et analysé le CSS. Vous avez ajouté un aller-retour réseau sur le chemin critique du rendu, au bénéfice d'un cache qui n'existe plus.

En auto-hébergeant, les polices partent du même domaine que le document, sur une connexion déjà ouverte, découvrables dès le HTML, et préchargeables. Le chemin critique raccourcit.

Et puis il y a le droit

L'argument technique suffit déjà, mais il ne vit pas seul. Une requête vers un serveur de Google transmet l'adresse IP du visiteur, qui est une donnée personnelle, à un tiers, aux États-Unis, sans consentement préalable.

Le 20 janvier 2022, le Landgericht München I (affaire 3 O 17493/20) a jugé cette transmission illicite. Un particulier a obtenu 100 euros de dommages et intérêts, ainsi qu'une injonction de cesser. Le montant est anecdotique. Le précédent ne l'est pas, et il a ouvert en Allemagne une vague de mises en demeure.

En France, il n'existe pas à ma connaissance de décision de la CNIL portant spécifiquement sur Google Fonts. Le raisonnement applicable est celui, plus général, issu de l'arrêt Schrems II sur les transferts vers les États-Unis. Et il existe un critère simple que tout DPO vous opposera : si le même résultat visuel est atteignable sans appeler un tiers, il devient très difficile d'expliquer en quoi l'externalisation était nécessaire.

Ce que coûte l'auto-hébergement

Je ne vais pas prétendre que c'est gratuit. En rapatriant vos polices, vous héritez de trois responsabilités que le CDN portait pour vous.

Vous devenez responsable du sous-ensemble de caractères. Google servait automatiquement une version allégée adaptée au navigateur. Chez vous, une police complète peut peser plusieurs centaines de kilo-octets là où un sous-ensemble latin en pèse quelques dizaines. C'est un outil à faire tourner, une fois.

Vous devenez responsable des en-têtes de cache. Un fichier de police est immuable : il mérite un nom versionné et un Cache-Control: public, max-age=31536000, immutable. Si vous laissez la configuration par défaut de votre serveur, vous perdrez plus que ce que vous avez gagné.

Vous devenez responsable des mises à jour. Une police auto-hébergée ne reçoit pas les corrections de glyphes en amont. Dans la pratique, pour du texte courant, c'est un non-sujet.

En échange, vous obtenez une propriété que le CDN ne peut pas offrir : la reproductibilité. Sur ce site, les PDF de mon CV sont générés au moment du build par un navigateur sans tête. Avec des polices distantes, le rendu de ces documents dépendrait de la disponibilité d'un service tiers au moment précis de la compilation, et deux builds identiques pourraient produire deux fichiers différents. Avec des polices versionnées dans le dépôt, le build est hermétique.

La vraie leçon

Le cache HTTP partagé est un cas d'école d'optimisation devenue folklore. L'argument était juste, le contexte a changé, et l'argument a continué à circuler sans son contexte. Cinq ans plus tard, on le répète encore.

Cela vaut le coup de se demander, sur les autres évidences de nos métiers, laquelle a déjà été démentie par une note de version que personne n'a lue.

Sources


← Retour au blog