Skip to content

Commit 28e5a4e

Browse files
committed
Fix: Correctly handle Content-Length for compressed downloads (--download)
1 parent b12fc15 commit 28e5a4e

File tree

2 files changed

+23
-8
lines changed

2 files changed

+23
-8
lines changed

httpie/cli/argtypes.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,17 @@ def __call__(self, s: str) -> KeyValueArg:
9595
key_part, value_part = token.split(sep, 1)
9696

9797
# The key is composed of:
98-
# 1. Any preceding tokens (unescaped by str(t) in join)
99-
# 2. The key part of the current token (re-tokenize to
100-
# handle internal escapes correctly)
101-
key_tokens = tokens[:i] + self.tokenize(key_part)
98+
# 1. Any preceding tokens (already Escaped or regular strings)
99+
# 2. The key part of the current token (re-tokenize to catch internal escapes)
100+
key_tokens = tokens[:i]
101+
key_tokens.extend(self.tokenize(key_part))
102102
key = ''.join(str(t) for t in key_tokens)
103103

104104
# The value is composed of:
105-
# 1. The value part of the current token (re-tokenize)
106-
# 2. Any succeeding tokens (unescaped by str(t) in join)
107-
value_tokens = self.tokenize(value_part) + tokens[i + 1:]
105+
# 1. The value part of the current token (re-tokenize to catch internal escapes)
106+
# 2. Any succeeding tokens
107+
value_tokens = self.tokenize(value_part)
108+
value_tokens.extend(tokens[i + 1:])
108109
value = ''.join(str(t) for t in value_tokens)
109110

110111
break
@@ -279,4 +280,4 @@ def response_mime_type(mime_type: str) -> str:
279280
if mime_type.count('/') != 1:
280281
raise argparse.ArgumentTypeError(
281282
f'{mime_type!r} doesn’t look like a mime type; use type/subtype')
282-
return mime_type
283+
return mime_type

httpie/core.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,20 @@ def request_body_read_callback(chunk: bytes):
227227
force_separator = is_streamed_upload and env.stdout_isatty
228228
else:
229229
final_response = message
230+
231+
# --- BUG FIX: Correctly handle Content-Length for encoded downloads ---
232+
if downloader and 'Content-Encoding' in final_response.headers:
233+
# When in download mode, we assume the user intends to download
234+
# the raw, encoded content (e.g., a .gz file). We must delete
235+
# the 'Content-Encoding' header from the response to prevent
236+
# the 'requests' library from auto-decompressing the stream.
237+
# This ensures the raw compressed data is streamed and the
238+
# 'Content-Length' (which refers to the compressed size per spec)
239+
# is correctly verified against the streamed bytes, resolving
240+
# the "Incomplete download" error.
241+
del final_response.headers['Content-Encoding']
242+
# --- END BUG FIX ---
243+
230244
if args.check_status or downloader:
231245
exit_status = http_status_to_exit_status(http_status=message.status_code, follow=args.follow)
232246
if exit_status != ExitStatus.SUCCESS and (not env.stdout_isatty or args.quiet == 1):

0 commit comments

Comments
 (0)