Fix --offline --multipart, add more tests

This commit is contained in:
Jakub Roztocil 2020-09-28 16:22:34 +02:00
parent 75f1e02215
commit 32d8b481e9
6 changed files with 78 additions and 9 deletions

View File

@ -283,7 +283,8 @@ def make_request_kwargs(
body=data, body=data,
body_read_callback=request_body_read_callback, body_read_callback=request_body_read_callback,
chunked=args.chunked, chunked=args.chunked,
content_length_header_value=headers.get('Content-Length') offline=args.offline,
content_length_header_value=headers.get('Content-Length'),
), ),
'auth': args.auth, 'auth': args.auth,
'params': args.params.items(), 'params': args.params.items(),

View File

@ -201,7 +201,7 @@ def program(
if is_request: if is_request:
if not initial_request: if not initial_request:
initial_request = message initial_request = message
is_streamed_upload = not args.offline and not isinstance( is_streamed_upload = not isinstance(
message.body, (str, bytes)) message.body, (str, bytes))
if with_body: if with_body:
with_body = not is_streamed_upload with_body = not is_streamed_upload

View File

@ -39,11 +39,20 @@ def prepare_request_body(
body_read_callback: Callable[[bytes], bytes], body_read_callback: Callable[[bytes], bytes],
content_length_header_value: int = None, content_length_header_value: int = None,
chunked=False, chunked=False,
offline=False,
) -> Union[str, bytes, IO, MultipartEncoder, ChunkedUploadStream]: ) -> Union[str, bytes, IO, MultipartEncoder, ChunkedUploadStream]:
is_file_like = hasattr(body, 'read')
if isinstance(body, RequestDataDict): if isinstance(body, RequestDataDict):
body = urlencode(body, doseq=True) body = urlencode(body, doseq=True)
if not hasattr(body, 'read'): if offline:
if is_file_like:
return body.read()
return body
if not is_file_like:
if chunked: if chunked:
body = ChunkedUploadStream( body = ChunkedUploadStream(
# Pass the entire body as one chunk. # Pass the entire body as one chunk.

View File

@ -10,7 +10,7 @@ from httpie.context import Environment
from httpie.status import ExitStatus from httpie.status import ExitStatus
from httpie.cli.exceptions import ParseError from httpie.cli.exceptions import ParseError
from utils import MockEnvironment, StdinBytesIO, http, HTTP_OK from utils import MockEnvironment, StdinBytesIO, http, HTTP_OK
from fixtures import FILE_PATH, FILE_CONTENT from fixtures import FILE_PATH, FILE_CONTENT, FILE_PATH_ARG
import httpie import httpie
@ -193,6 +193,48 @@ def test_offline():
assert 'GET /foo' in r assert 'GET /foo' in r
def test_offline_form():
r = http(
'--offline',
'--form',
'https://this-should.never-resolve/foo',
'foo=bar'
)
assert 'POST /foo' in r
assert 'foo=bar' in r
def test_offline_json():
r = http(
'--offline',
'https://this-should.never-resolve/foo',
'foo=bar'
)
assert 'POST /foo' in r
assert r.json == {'foo': 'bar'}
def test_offline_multipart():
r = http(
'--offline',
'--multipart',
'https://this-should.never-resolve/foo',
'foo=bar'
)
assert 'POST /foo' in r
assert 'name="foo"' in r
def test_offline_from_file():
r = http(
'--offline',
'https://this-should.never-resolve/foo',
f'@{FILE_PATH_ARG}'
)
assert 'POST /foo' in r
assert FILE_CONTENT in r
def test_offline_download(): def test_offline_download():
"""Absence of response should be handled gracefully with --download""" """Absence of response should be handled gracefully with --download"""
r = http( r = http(

View File

@ -170,7 +170,6 @@ class TestMultipartFormDataFileUpload:
'--verbose', '--verbose',
'--multipart', '--multipart',
'--chunked', '--chunked',
# '--offline',
HTTPBIN_WITH_CHUNKED_SUPPORT + '/post', HTTPBIN_WITH_CHUNKED_SUPPORT + '/post',
'AAA=AAA', 'AAA=AAA',
) )
@ -179,6 +178,25 @@ class TestMultipartFormDataFileUpload:
assert 'name="AAA"' in r # in request assert 'name="AAA"' in r # in request
assert '"AAA": "AAA"', r # in response assert '"AAA": "AAA"', r # in response
def test_multipart_preserve_order(self, httpbin):
r = http(
'--form',
'--offline',
httpbin + '/post',
'text_field=foo',
f'file_field@{FILE_PATH_ARG}',
)
assert r.index('text_field') < r.index('file_field')
r = http(
'--form',
'--offline',
httpbin + '/post',
f'file_field@{FILE_PATH_ARG}',
'text_field=foo',
)
assert r.index('text_field') > r.index('file_field')
class TestRequestBodyFromFilePath: class TestRequestBodyFromFilePath:
""" """

View File

@ -144,10 +144,9 @@ class StrCLIResponse(str, BaseCLIResponse):
elif self.strip().startswith('{'): elif self.strip().startswith('{'):
# Looks like JSON body. # Looks like JSON body.
self._json = json.loads(self) self._json = json.loads(self)
elif (self.count('Content-Type:') == 1 elif self.count('Content-Type:') == 1:
and 'application/json' in self): # Looks like a HTTP message,
# Looks like a whole JSON HTTP message, # try to extract JSON from its body.
# try to extract its body.
try: try:
j = self.strip()[self.strip().rindex('\r\n\r\n'):] j = self.strip()[self.strip().rindex('\r\n\r\n'):]
except ValueError: except ValueError: