Transfer-Encoding: gzip vs Content-Encoding: gzip

98

Quel est l'état actuel des choses lorsqu'il s'agit de faire ou non

Transfer-Encoding: gzip

ou un

Content-Encoding: gzip

lorsque je veux permettre à des clients avec par exemple une bande passante limitée de signaler leur volonté d'accepter une réponse compressée et que le serveur a le dernier mot sur la compression ou non .

C'est ce que font par exemple le mod_deflate d'Apache et IIS, si vous le laissez prendre en charge la compression. En fonction de la taille du contenu à compresser, il fera le plus Transfer-Encoding: chunked.

Il comprendra également un Vary: Accept-Encoding, qui fait déjà allusion au problème. Content-Encodingsemble faire partie de l'entité, donc changer les Content-Encodingmontants en un changement d'entité, c'est-à-dire un en- Accept-Encodingtête différent signifie par exemple qu'un cache ne peut pas utiliser sa version mise en cache de l'entité par ailleurs identique.

Y a-t-il une réponse définitive à ce sujet que j'ai manquée (et qui n'est pas enterrée dans un message dans un long fil de discussion dans un groupe de discussion Apache)?

Mon impression actuelle est:

  • Transfer-Encoding serait en fait la bonne façon de faire ce qui est principalement fait avec Content-Encoding par les implémentations existantes de serveur et de client
  • Content-Encoding, en raison de ses implications sémantiques, pose quelques problèmes (que doit faire le serveur ETaglorsqu'il compresse une réponse de manière transparente?)
  • La raison en est chicken'n'egg: les navigateurs ne le prennent pas en charge parce que les serveurs ne le font pas parce que les navigateurs ne le font pas

Donc, je suppose que la bonne manière serait un Transfer-Encoding: gzip(ou, si je découpais en plus le corps, il le deviendrait Transfer-Encoding: gzip, chunked ). Et aucune raison de toucher Varyou ETagou tout autre en-tête dans ce cas, car c'est une chose au niveau du transport.

Pour l'instant, je ne me soucie pas trop du «saut par saut» de Transfer-Encoding, quelque chose dont les autres semblent se préoccuper avant tout, parce que les proxys peuvent décompresser et transmettre non compressés au client. Cependant, les proxys peuvent tout aussi bien le transmettre tel quel (compressé), si la demande d'origine a l'en- Accept-Encodingtête approprié , ce qui dans le cas de tous les navigateurs que je connais est une donnée.

Btw, ce problème date d'au moins une décennie, voir par exemple https://bugzilla.mozilla.org/show_bug.cgi?id=68517 .

Toute clarification à ce sujet sera appréciée. À la fois en termes de ce qui est considéré comme conforme aux normes et de ce qui est considéré comme pratique. Par exemple, les bibliothèques clientes HTTP ne prenant en charge que le "Content-Encoding" transparent serait un argument contre l'aspect pratique.

Eugene Beresovksy
la source
2
En relation: stackapps.com/questions/916/…
Jo Liss
Je viens de rencontrer ça. Curl sur PHP 5.3 ne comprend pas Transfer-Encoding:gzip, bien que curl en ligne de commande le fasse. Pour être prudent, envoyez les deux, sauf si vous combinez chunked et gzip.
Seva Alekseyev
1
@SevaAlekseyev envoyer les deux serait très faux - les clients pourraient essayer de décompresser deux fois
Joshua Wise
C'est quelque chose qui m'a aussi dérangé pour toujours ( question que j'ai posée ) ... selon l'une des réponses à la question citée par @JoLiss, il existe un moyen parfaitement logique, sémantiquement cohérent et conforme aux normes de compresser les corps de requête / réponse ... et fondamentalement aucun client / serveur ne l'utilise ou ne le prend en charge. 🤦🏻‍
Dan Lenski le

Réponses:

35

Citant Roy T.Fielding , l'un des auteurs de la RFC 2616:

modifier le codage du contenu à la volée de manière incohérente (ni "jamais" ni "toujours") rend impossible le traitement correct des demandes ultérieures concernant ce contenu (par exemple, PUT ou GET conditionnel). C'est, bien sûr, pourquoi effectuer l'encodage de contenu à la volée est une idée stupide, et pourquoi j'ai ajouté Transfer-Encoding à HTTP comme moyen approprié de faire l'encodage à la volée sans changer la ressource.

Source: https://issues.apache.org/bugzilla/show_bug.cgi?id=39727#c31

En d'autres termes: ne faites pas l' encodage de contenu à la volée , utilisez plutôt l'encodage de transfert!

Edit: Autrement dit, à moins que vous ne souhaitiez servir du contenu gzippé à des clients qui ne comprennent que le codage de contenu . Ce qui, malheureusement, semble être la plupart d'entre eux. Mais sachez que vous quittez les domaines de la spécification et que vous pourriez rencontrer des problèmes tels que celui mentionné par Fielding ainsi que d'autres, par exemple lorsque des proxys de mise en cache sont impliqués.

Evgeniy Berezovsky
la source
3
Donc, si je comprends bien: 1. Le codage du contenu fait référence au codage du contenu sur le serveur dans l'abstrait, c'est-à-dire que le contenu sera systématiquement servi dans un codage spécifié par le serveur. 2. Le codage de transfert fait référence au codage que le serveur a décidé d'utiliser pour le fournir à l'agent utilisateur dans ce cas, c'est-à-dire dans cette réponse. Assurez-vous simplement de ne pas mal interpréter votre réponse.
dot slash hack
30
@KemHeyndels À propos de droite. En d'autres termes: selon les spécifications, Transfer-Encoding est un pur détail de la couche de transport , c'est-à-dire qu'un proxy intermédiaire est libre d'annuler, par exemple, la compression gzip à ce niveau, alors que Content-Encoding est une propriété de couche métier , ce qu'un proxy ne serait pas autorisé à changer, en plus d'autres ramifications (ETags, etc.). Cependant, selon la réalité , TE n'est normalement pas utilisé pour la compression, et de nombreux serveurs / clients ne le prennent même pas en charge immédiatement, alors que CE est utilisé plus ou moins de la manière dont TE était censé être utilisé : comme détail de la couche de transport .
Evgeniy Berezovsky
1
Nous sommes donc obligés par la réalité d'ignorer les conseils de Roy T. Fielding?
dot slash hack
11
@KemHeyndels Vous êtes obligé par l'idéalisme de sortir et d'ajouter d'abord le support TE à toutes les implémentations client / serveur HTTP open-source. Ensuite, embauchez-vous dans chaque entreprise qui a des implémentations HTTP à source fermée (je pense que ce n'est que Microsoft de toute façon) et ajoutez-y également la fonctionnalité. Après cela, la réalité et les spécifications coïncideront. ;) (Et HTTP 2.0 aura été publié, faisant disparaître le problème de toute façon)
Evgeniy Berezovsky
10
Indiquer que vous prenez en charge le codage de transfert ne signifie toujours pas que vous prenez en charge gzip sur le codage de transfert, donc cela ne vous achète rien. L'indication se fait dans l'autre sens : tout client qui peut faire gzip via Transfer-Encoding le fera savoir au serveur en définissant TE: gzip. Et puis votre serveur devrait suivre la route de transfert-encodage. Si le client le dit seulement Accept-Encoding: gzip, vous devez le faire comme vous le souhaitez Content-Encoding. Si le client ne spécifie ni l'un ni l'autre dans sa requête, le serveur ne doit pas du tout gzip.
Evgeniy Berezovsky
27

L' utilisation correcte , telle que définie dans la RFC 2616 et réellement implémentée dans la nature, consiste pour le client à envoyer un en- Accept-Encodingtête de demande (le client peut spécifier plusieurs codages). Le serveur peut alors, et alors seulement, coder la réponse selon les codages pris en charge par le client (si les données du fichier ne sont pas déjà stockées dans ce codage), indiquer dans l'en- Content-Encodingtête de réponse quel codage est utilisé. Le client peut alors lire les données de la socket en fonction du Transfer-Encoding(c'est-à-dire chunked), puis les décoder en fonction du Content-Encoding(c'est-à-dire:) gzip.

Ainsi, dans votre cas, le client enverrait un en- Accept-Encoding: gziptête de demande, puis le serveur pourrait décider de compresser (si ce n'est déjà fait) et d'envoyer un en Content-Encoding: gzip- Transfer-Encoding: chunkedtête et éventuellement de réponse.

Et oui, l'en- Transfer-Encodingtête peut être utilisé dans les requêtes, mais uniquement pour HTTP 1.1, ce qui nécessite que les implémentations client et serveur prennent en charge l' chunkedencodage dans les deux sens.

ETagidentifie de manière unique les données de ressources sur le serveur, pas les données réellement transmises. Si une ressource URL donnée change sa ETagvaleur, cela signifie que les données côté serveur de cette ressource ont changé.

Remy Lebeau
la source
14
le codage de contenu est une caractéristique de l'entité identifiée par l'URI de demande En d'autres termes: Différent Content-Encodingrequiert différentETag C'est d'ailleurs ce à quoi sert le bogue mod_deflate auquel je fais référence dans ma réponse. Je me demande pourquoi ce détail au niveau de l'application est dans la norme HTTP en premier lieu. Transfer-EncodingCependant, lorsque vous utilisez un paramètre de niveau de transport, il n'est pas nécessaire de modifier le fichier ETag. Sauf que personne n'a implémenté Transfer-Enc.
Evgeniy Berezovsky
2
Content-Encoding n'est pas pour l'encodage "à la volée". La RFC 2616 dit que "Le codage de transfert ... diffère du codage de contenu en ce que le codage de transfert est une propriété du message, pas de l'entité." ( Tools.ietf.org/html/rfc2616#section-14.41 ), et "Le codage de contenu est une caractéristique de l'entité identifiée par l'URI de demande. En règle générale, le corps de l'entité est stocké avec ce codage" ( tools.ietf.org/html/rfc2616#section-14.11 ). Alors je vote contre.
Robert
Ce que je décrit est ce qui est « effectivement mis en œuvre dans la nature », quel que soit Content-Encodingvs Transfer-Encoding. Oui, gzip doit être une propriété du transfert d'une ressource, s'il est effectué à la volée. En revanche, si la ressource est stockée compressée sur le serveur, elle doit plutôt être une propriété du contenu de la ressource, si elle est envoyée telle quelle . Mais ce qui devrait être et ce qui est réellement ne sont pas toujours la même chose.
Remy Lebeau