diff --git a/httpie/downloads.py b/httpie/downloads.py index 9c4b895e6f..57e2b722fa 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -218,8 +218,17 @@ def start( # FIXME: some servers still might sent Content-Encoding: gzip # + # Skip Content-Length validation when Content-Encoding is present. + # Per RFC 9110, Content-Length reflects the encoded (compressed) size, + # but the requests library transparently decompresses, making written + # bytes exceed Content-Length. Skip the check to match curl/browser behaviour. + # See: https://github.com/httpie/cli/issues/1642 try: - total_size = int(final_response.headers['Content-Length']) + content_encoding = final_response.headers.get('Content-Encoding') + if content_encoding: + total_size = None # cannot reliably compare compressed vs decompressed bytes + else: + total_size = int(final_response.headers['Content-Length']) except (KeyError, ValueError, TypeError): total_size = None diff --git a/tests/test_downloads.py b/tests/test_downloads.py index b646a0e6a5..558c840fa5 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -259,3 +259,14 @@ def test_download_with_redirect_original_url_used_for_filename(self, httpbin): assert os.listdir('.') == [expected_filename] finally: os.chdir(orig_cwd) + + def test_download_gzip_no_false_incomplete(httpbin): + #Regression test for https://github.com/httpie/cli/issues/1642 + #Content-Encoding: gzip must not trigger a false "Incomplete download" error. + r = http( + '--download', + httpbin + '/gzip', # returns gzip-compressed JSON + env=MockEnvironment(), + ) + assert 'Incomplete download' not in r.stderr + assert r.exit_status == ExitStatus.SUCCESS