Skip to content

Commit 55aea9c

Browse files
author
Ahmed TAHRI
committed
fixed+enabled recently disabled tests for download + compressed bodies
1 parent d02b882 commit 55aea9c

File tree

3 files changed

+68
-69
lines changed

3 files changed

+68
-69
lines changed

httpie/downloads.py

+11-15
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,6 @@ def pre_request(self, request_headers: dict):
211211
Might alter `request_headers`.
212212
213213
"""
214-
# Ask the server not to encode the content so that we can resume, etc.
215-
# TODO: Reconsider this once the underlying library can report raw download size (i.e., not decoded).
216-
# Then it might still be needed when resuming. But in the default case, it won’t probably be necessary.
217-
# <https://github.com/jawah/niquests/issues/127>
218-
request_headers['Accept-Encoding'] = 'identity'
219-
220214
if self._resume:
221215
bytes_have = os.path.getsize(self._output_file.name)
222216
if bytes_have:
@@ -301,11 +295,11 @@ def failed(self):
301295
def is_interrupted(self) -> bool:
302296
return self.status.is_interrupted
303297

304-
def chunk_downloaded(self, chunk_or_new_total: Union[bytes, int]):
298+
def chunk_downloaded(self, chunk_or_new_total: Union[bytes, int]) -> None:
305299
"""
306300
A download progress callback.
307301
308-
:param chunk: A chunk of response body data that has just
302+
:param chunk_or_new_total: A chunk of response body data that has just
309303
been downloaded and written to the output.
310304
311305
"""
@@ -333,8 +327,7 @@ def _get_output_file_from_response(
333327
return open(unique_filename, buffering=0, mode='a+b')
334328

335329

336-
DECODED_FROM_SUFFIX = ' - decoded from {encodings}'
337-
DECODED_SIZE_NOTE_SUFFIX = ' - decoded size'
330+
DECODED_FROM_SUFFIX = ' - decoded using {encodings}'
338331

339332

340333
class DownloadStatus:
@@ -365,8 +358,14 @@ def start_display(self, output_file):
365358
ProgressDisplayFull
366359
)
367360
message = f'Downloading to {output_file.name}'
368-
message_suffix = ''
369361
summary_suffix = ''
362+
363+
if self.decoded_from:
364+
encodings = ', '.join(f'`{enc}`' for enc in self.decoded_from)
365+
message_suffix = DECODED_FROM_SUFFIX.format(encodings=encodings)
366+
else:
367+
message_suffix = ''
368+
370369
if not self.env.show_displays:
371370
progress_display_class = DummyProgressDisplay
372371
else:
@@ -375,11 +374,8 @@ def start_display(self, output_file):
375374
if has_reliable_total:
376375
progress_display_class = ProgressDisplayFull
377376
else:
378-
if self.decoded_from:
379-
encodings = ', '.join(f'`{enc}`' for enc in self.decoded_from)
380-
message_suffix = DECODED_FROM_SUFFIX.format(encodings=encodings)
381-
summary_suffix = DECODED_SIZE_NOTE_SUFFIX
382377
progress_display_class = ProgressDisplayNoTotal
378+
383379
self.display = progress_display_class(
384380
env=self.env,
385381
total_size=self.total_size,

httpie/output/streams.py

+7
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,15 @@ def __iter__(self) -> Iterable[bytes]:
7979
# Useful when the remote compress the body. We use the "untouched" amt of data to determine
8080
# the download speed.
8181
if hasattr(self.msg, "_orig") and hasattr(self.msg._orig, "download_progress") and self.msg._orig.download_progress:
82+
# this is plan A: using public interfaces!
8283
self.on_body_chunk_downloaded(self.msg._orig.download_progress.total)
84+
elif hasattr(self.msg, "_orig") and hasattr(self.msg._orig, "raw") and hasattr(self.msg._orig.raw, "_fp_bytes_read"):
85+
# plan B, falling back on a private property that may disapear from urllib3-future...
86+
# this case is mandatory due to how the mocking library works. it does not use any "socket" but
87+
# rather a simple io.BytesIO.
88+
self.on_body_chunk_downloaded(self.msg._orig.raw._fp_bytes_read)
8389
else:
90+
# well. this case will certainly cause issues if the body is compressed.
8491
self.on_body_chunk_downloaded(chunk)
8592
except DataSuppressedError as e:
8693
if self.output_options.headers:

tests/test_downloads.py

+50-54
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import tempfile
33
import time
4+
import zlib
45
from unittest import mock
56
from urllib.request import urlopen
67

@@ -15,7 +16,7 @@
1516
ContentRangeError,
1617
Downloader,
1718
PARTIAL_CONTENT,
18-
DECODED_SIZE_NOTE_SUFFIX,
19+
DECODED_FROM_SUFFIX,
1920
)
2021
from niquests.structures import CaseInsensitiveDict
2122
from .utils import http, MockEnvironment, cd_clean_tmp_dir, DUMMY_URL
@@ -232,7 +233,6 @@ def test_download_resumed(self, mock_env, httpbin_both):
232233
# Ensure `pre_request()` is working as expected too
233234
headers = {}
234235
downloader.pre_request(headers)
235-
assert headers['Accept-Encoding'] == 'identity'
236236
assert headers['Range'] == 'bytes=3-'
237237

238238
downloader.start(
@@ -264,7 +264,7 @@ def test_download_gzip_content_encoding(self, httpbin):
264264
@responses.activate
265265
def test_incomplete_response(self):
266266
# We have incompleteness checks in the downloader, but it might not be needed as it’s built into (ni|req)uests.
267-
error_msg = 'peer closed connection without sending complete message body (received 2 bytes, expected 1 more)'
267+
error_msg = 'IncompleteRead(2 bytes read, 1 more expected)'
268268
responses.add(
269269
method=responses.GET,
270270
url=DUMMY_URL,
@@ -281,55 +281,53 @@ def test_incomplete_response(self):
281281
class TestDecodedDownloads:
282282
"""Test downloading responses with `Content-Encoding`"""
283283

284-
# todo: find an appropriate way to mock compressed bodies within those tests.
285-
# @responses.activate
286-
# def test_decoded_response_no_content_length(self):
287-
# responses.add(
288-
# method=responses.GET,
289-
# url=DUMMY_URL,
290-
# headers={
291-
# 'Content-Encoding': 'gzip, br',
292-
# },
293-
# body='123',
294-
# )
295-
# with cd_clean_tmp_dir():
296-
# r = http('--download', '--headers', DUMMY_URL)
297-
# print(r.stderr)
298-
# assert DECODED_FROM_SUFFIX.format(encodings='`gzip`, `br`') in r.stderr
299-
# assert DECODED_SIZE_NOTE_SUFFIX in r.stderr
300-
#
301-
# @responses.activate
302-
# def test_decoded_response_with_content_length(self):
303-
# responses.add(
304-
# method=responses.GET,
305-
# url=DUMMY_URL,
306-
# headers={
307-
# 'Content-Encoding': 'gzip, br',
308-
# 'Content-Length': '3',
309-
# },
310-
# body='123',
311-
# )
312-
# with cd_clean_tmp_dir():
313-
# r = http('--download', DUMMY_URL)
314-
# print(r.stderr)
315-
# assert DECODED_FROM_SUFFIX.format(encodings='`gzip`, `br`') in r.stderr
316-
# assert DECODED_SIZE_NOTE_SUFFIX in r.stderr
317-
#
318-
# @responses.activate
319-
# def test_decoded_response_without_content_length(self):
320-
# responses.add(
321-
# method=responses.GET,
322-
# url=DUMMY_URL,
323-
# headers={
324-
# 'Content-Encoding': 'gzip, br',
325-
# },
326-
# body='123',
327-
# )
328-
# with cd_clean_tmp_dir():
329-
# r = http('--download', DUMMY_URL)
330-
# print(r.stderr)
331-
# assert DECODED_FROM_SUFFIX.format(encodings='`gzip`, `br`') in r.stderr
332-
# assert DECODED_SIZE_NOTE_SUFFIX in r.stderr
284+
@responses.activate
285+
def test_decoded_response_no_content_length(self):
286+
responses.add(
287+
method=responses.GET,
288+
url=DUMMY_URL,
289+
headers={
290+
'Content-Encoding': 'deflate',
291+
},
292+
body=zlib.compress(b"foobar"),
293+
)
294+
with cd_clean_tmp_dir():
295+
r = http('--download', '--headers', DUMMY_URL)
296+
print(r.stderr)
297+
assert DECODED_FROM_SUFFIX.format(encodings='`deflate`') in r.stderr
298+
299+
@responses.activate
300+
def test_decoded_response_with_content_length(self):
301+
payload = zlib.compress(b"foobar")
302+
303+
responses.add(
304+
method=responses.GET,
305+
url=DUMMY_URL,
306+
headers={
307+
'Content-Encoding': 'deflate',
308+
'Content-Length': str(len(payload)),
309+
},
310+
body=payload,
311+
)
312+
with cd_clean_tmp_dir():
313+
r = http('--download', DUMMY_URL)
314+
print(r.stderr)
315+
assert DECODED_FROM_SUFFIX.format(encodings='`deflate`') in r.stderr
316+
317+
@responses.activate
318+
def test_decoded_response_without_content_length(self):
319+
responses.add(
320+
method=responses.GET,
321+
url=DUMMY_URL,
322+
headers={
323+
'Content-Encoding': 'deflate',
324+
},
325+
body=zlib.compress(b'foobar'),
326+
)
327+
with cd_clean_tmp_dir():
328+
r = http('--download', DUMMY_URL)
329+
print(r.stderr)
330+
assert DECODED_FROM_SUFFIX.format(encodings='`deflate`') in r.stderr
333331

334332
@responses.activate
335333
def test_non_decoded_response_without_content_length(self):
@@ -344,7 +342,6 @@ def test_non_decoded_response_without_content_length(self):
344342
with cd_clean_tmp_dir():
345343
r = http('--download', DUMMY_URL)
346344
print(r.stderr)
347-
assert DECODED_SIZE_NOTE_SUFFIX not in r.stderr
348345

349346
@responses.activate
350347
def test_non_decoded_response_with_content_length(self):
@@ -358,4 +355,3 @@ def test_non_decoded_response_with_content_length(self):
358355
with cd_clean_tmp_dir():
359356
r = http('--download', DUMMY_URL)
360357
print(r.stderr)
361-
assert DECODED_SIZE_NOTE_SUFFIX not in r.stderr

0 commit comments

Comments
 (0)