Comment gérer correctement une page gzippée lors de l'utilisation de curl?

139

J'ai écrit un script bash qui obtient la sortie d'un site Web en utilisant curl et fait un tas de manipulations de chaînes sur la sortie html. Le problème est lorsque je l'exécute sur un site qui renvoie sa sortie gzippée. Accéder au site dans un navigateur fonctionne très bien.

Lorsque je lance curl à la main, j'obtiens une sortie gzippée:

$ curl "http://example.com"

Voici l'en-tête de ce site particulier:

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=utf-8
X-Powered-By: PHP/5.2.17
Last-Modified: Sat, 03 Dec 2011 00:07:57 GMT
ETag: "6c38e1154f32dbd9ba211db8ad189b27"
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Cache-Control: must-revalidate
Content-Encoding: gzip
Content-Length: 7796
Date: Sat, 03 Dec 2011 00:46:22 GMT
X-Varnish: 1509870407 1509810501
Age: 504
Via: 1.1 varnish
Connection: keep-alive
X-Cache-Svr: p2137050.pubip.peer1.net
X-Cache: HIT
X-Cache-Hits: 425

Je sais que les données renvoyées sont gzippées, car cela renvoie du html, comme prévu:

$ curl "http://example.com" | gunzip

Je ne veux pas diriger la sortie via gunzip, car le script fonctionne tel quel sur d'autres sites, et le fait de passer par gzip casserait cette fonctionnalité.

Ce que j'ai essayé

  1. changer le user-agent (j'ai essayé la même chaîne que mon navigateur envoie, "Mozilla / 4.0", etc.)
  2. homme curl
  3. recherche Google
  4. recherche stackoverflow

Tout est venu vide

Des idées?

BryanH
la source
Pour moi, le problème était que cURL ne pouvait pas décompresser Brotli ( curl 7.54.0 (x86_64-apple-darwin17.0) libcurl/7.54.0 LibreSSL/2.0.20 zlib/1.2.11 nghttp2/1.24.0) - le résolvait en supprimant brde Accept-Encoding. voir stackoverflow.com/questions/18983719/…
Nino Škopac

Réponses:

260

curldécompressera automatiquement la réponse si vous définissez l' --compressedindicateur:

curl --compressed "http://example.com"

--compressed (HTTP) Demande une réponse compressée à l'aide de l'un des algorithmes pris en charge par libcurl et enregistre le document non compressé. Si cette option est utilisée et que le serveur envoie un encodage non pris en charge, curl signalera une erreur.

gzip est probablement pris en charge, mais vous pouvez le vérifier en exécutant curl -Vet en recherchant libz quelque part dans la ligne "Features":

$ curl -V
...
Protocols: ...
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz 

Notez que c'est vraiment le site Web en question qui est ici en faute. S'il curln'a pas passé un en- Accept-Encoding: gziptête de demande, le serveur n'aurait pas dû envoyer de réponse compressée.

Martin
la source
24
Cela semble être un bogue curl, car il devrait déclencher son décodage en fonction de la réponse, et non de ce qu'il a demandé (étant donné qu'il prend en charge gzip). Pour citer HTTP 1.1: "Si aucun champ Accept-Encoding n'est présent dans une demande, le serveur PEUT supposer que le client acceptera tout codage de contenu." Mais il continue en disant que les serveurs DEVRAIENT dans ce cas ne pas encoder le contenu, hmm, allez comprendre.
George Lund
effectivement sur ma version fonctionne --comp --compress --compressed
Radu Toader
3
cela définit également l'en-tête de la requête: "Accept-Encoding: deflate, gzip" c'est génial car si le serveur sert gzip et pas de gzip, il vous suffit de --compressed et de ne pas ajouter vous-même l'en-tête d'encodage d'accept
mbert
Aidez mon QA avec cette solution en 1 minute! Je vous remercie ! Cela dit, mon application envoie en fait une réponse gzip avec Content-Encoding: gzip. Les navigateurs et les outils modernes (par exemple httpie) le gèrent automatiquement. Je suppose que curl a juste besoin d'un "indice"
Faraway
Étonnamment, le réglage Accept-Encoding: deflate, gzipne suffit pas - même si le serveur renvoie une réponse gzip avec Content-Encoding: gzip, curl ne le décompressera pas automatiquement. Le --compresseddrapeau est obligatoire.
rjh