Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion httpie/downloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,17 @@ def start(

# FIXME: some servers still might sent Content-Encoding: gzip
# <https://github.com/httpie/cli/issues/423>
# 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

Expand Down
15 changes: 15 additions & 0 deletions tests/test_downloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
parse_content_range, filename_from_content_disposition, filename_from_url,
get_unique_filename, ContentRangeError, Downloader, PARTIAL_CONTENT
)
from httpie.status import ExitStatus
from .utils import http, MockEnvironment


Expand Down Expand Up @@ -259,3 +260,17 @@ 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(self, httpbin):
# Regression test for https://github.com/httpie/cli/issues/1642
# 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.
r = http(
'--download',
httpbin + '/gzip', # returns gzip-compressed JSON
env=MockEnvironment(),
)
assert 'Incomplete download' not in r.stderr
assert r.exit_status == ExitStatus.SUCCESS
Loading