Jak prawidłowo obsłużyć stronę spakowaną na gzip podczas używania curl?

139

Napisałem skrypt bash, który pobiera dane wyjściowe ze strony internetowej za pomocą curl i wykonuje kilka operacji na ciągach na wyjściu html. Problem polega na tym, że uruchamiam go na witrynie, która zwraca dane wyjściowe spakowane gzipem. Przechodzenie do witryny w przeglądarce działa dobrze.

Kiedy uruchamiam curl ręcznie, otrzymuję dane wyjściowe spakowane gzipem:

$ curl "http://example.com"

Oto nagłówek z tej konkretnej witryny:

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

Wiem, że zwrócone dane są spakowane gzipem, ponieważ zgodnie z oczekiwaniami zwraca to html:

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

Nie chcę potokować wyjścia przez gunzip, ponieważ skrypt działa tak, jak jest w innych witrynach, a przesyłanie potokiem przez gzip zepsułoby tę funkcjonalność.

Co próbowałem

  1. zmiana agenta użytkownika (próbowałem użyć tego samego ciągu, który wysyła moja przeglądarka, „Mozilla / 4.0” itp.)
  2. loki mężczyzna
  3. wyszukiwarka Google
  4. wyszukiwanie stackoverflow

Wszystko wyszło puste

Jakieś pomysły?

BryanH
źródło
Dla mnie problem polegał na tym, że cURL nie był w stanie zdekompresować 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) - rozwiązałem go, usuwając brz Accept-Encoding. patrz stackoverflow.com/questions/18983719/…
Nino Škopac

Odpowiedzi:

260

curlautomatycznie rozpakuje odpowiedź, jeśli ustawisz --compressedflagę:

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

--compressed (HTTP) Zażądaj skompresowanej odpowiedzi przy użyciu jednego z algorytmów obsługiwanych przez bibliotekę libcurl i zapisz nieskompresowany dokument. Jeśli ta opcja jest używana, a serwer wysyła nieobsługiwane kodowanie, curl zgłosi błąd.

Program gzip jest najprawdopodobniej obsługiwany, ale możesz to sprawdzić, uruchamiając curl -Vi wyszukując bibliotekę libz w wierszu „Funkcje”:

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

Zauważ, że to naprawdę ta witryna jest tutaj winna. Jeśli curlnie przekazał Accept-Encoding: gzipnagłówka żądania, serwer nie powinien był wysłać skompresowanej odpowiedzi.

Jaskółka oknówka
źródło
24
Wydawałoby się, że jest to błąd związany z curl, ponieważ powinno wyzwalać dekodowanie na podstawie odpowiedzi, a nie tego, czego zażądał (biorąc pod uwagę, że obsługuje gzip). Cytując HTTP 1.1: „Jeśli w żądaniu nie ma pola Accept-Encoding, serwer MOŻE założyć, że klient zaakceptuje kodowanie treści”. Ale mówi się dalej, że serwery POWINNY w takim przypadku kodować zawartość, hmm, idź do robienia.
George Lund,
faktycznie w mojej wersji działa --comp --compress --compressed
Radu Toader
3
to również ustawia nagłówek żądania: "Accept-Encoding: deflate, gzip" to świetnie, ponieważ jeśli serwer obsługuje gzip, a nie gzip, potrzebujesz tylko --compressed i nie dodawać samodzielnie nagłówka accept encoding
mbert
pomóż mojej kontroli jakości z tym rozwiązaniem w 1 minutę! Dziękuję Ci ! To powiedziawszy, moja aplikacja w rzeczywistości wysyła odpowiedź gzip za pomocą Content-Encoding: gzip. Przeglądarki i nowoczesne narzędzia (np. Httpie) obsługują to automatycznie. Myślę, że curl potrzebuje tylko "podpowiedzi"
Faraway
O dziwo, ustawienie Accept-Encoding: deflate, gzipnie wystarczy - nawet jeśli serwer zwróci odpowiedź gzip z Content-Encoding: gzip, curl nie rozpakuje jej automatycznie. --compressedWymagana jest flaga.
rjh