mirror of
https://github.com/httpie/cli.git
synced 2025-02-09 06:09:29 +01:00
Send filenames with multipart/form-data file uploads.
This commit is contained in:
parent
1efea59a8d
commit
f5bc081fda
@ -384,8 +384,8 @@ Changelog
|
|||||||
Authors
|
Authors
|
||||||
=======
|
=======
|
||||||
|
|
||||||
`Jakub Roztocil`_ (`@jkbrzt`_) created HTTPie and `these fine people`_ have
|
`Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_
|
||||||
contributed.
|
have contributed.
|
||||||
|
|
||||||
|
|
||||||
.. _suite of tests: https://github.com/jkbr/httpie/blob/master/tests/tests.py
|
.. _suite of tests: https://github.com/jkbr/httpie/blob/master/tests/tests.py
|
||||||
@ -400,7 +400,7 @@ contributed.
|
|||||||
.. _the repository: https://github.com/jkbr/httpie
|
.. _the repository: https://github.com/jkbr/httpie
|
||||||
.. _these fine people: https://github.com/jkbr/httpie/contributors
|
.. _these fine people: https://github.com/jkbr/httpie/contributors
|
||||||
.. _Jakub Roztocil: http://roztocil.name
|
.. _Jakub Roztocil: http://roztocil.name
|
||||||
.. _@jkbrzt: https://twitter.com/jkbrzt
|
.. _@jakubroztocil: https://twitter.com/jakubroztocil
|
||||||
.. _existing issues: https://github.com/jkbr/httpie/issues?state=open
|
.. _existing issues: https://github.com/jkbr/httpie/issues?state=open
|
||||||
.. _0.1.6: https://github.com/jkbr/httpie/compare/0.1.4...0.1.6
|
.. _0.1.6: https://github.com/jkbr/httpie/compare/0.1.4...0.1.6
|
||||||
.. _0.2.0: https://github.com/jkbr/httpie/compare/0.1.6...0.2.0
|
.. _0.2.0: https://github.com/jkbr/httpie/compare/0.1.6...0.2.0
|
||||||
|
@ -97,28 +97,19 @@ class Parser(argparse.ArgumentParser):
|
|||||||
self._parse_items(args)
|
self._parse_items(args)
|
||||||
|
|
||||||
if not env.stdin_isatty:
|
if not env.stdin_isatty:
|
||||||
self._body_from_file(args, env.stdin)
|
self._body_from_file(args, env.stdin.read())
|
||||||
|
|
||||||
if args.auth and not args.auth.has_password():
|
if args.auth and not args.auth.has_password():
|
||||||
# Stdin already read (if not a tty) so it's save to prompt.
|
# Stdin already read (if not a tty) so it's save to prompt.
|
||||||
args.auth.prompt_password()
|
args.auth.prompt_password()
|
||||||
|
|
||||||
if args.files:
|
|
||||||
# Will be read multiple times.
|
|
||||||
for name in args.files:
|
|
||||||
args.files[name] = args.files[name].read()
|
|
||||||
|
|
||||||
if args.prettify == PRETTIFY_STDOUT_TTY_ONLY:
|
if args.prettify == PRETTIFY_STDOUT_TTY_ONLY:
|
||||||
args.prettify = env.stdout_isatty
|
args.prettify = env.stdout_isatty
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def _body_from_file(self, args, data):
|
def _body_from_file(self, args, data):
|
||||||
"""Use the content of `f` as the `request.data`.
|
"""There can only be one source of request data."""
|
||||||
|
|
||||||
There can only be one source of request data.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if args.data:
|
if args.data:
|
||||||
self.error('Request body (from stdin or a file) and request '
|
self.error('Request body (from stdin or a file) and request '
|
||||||
'data (key=value) cannot be mixed.')
|
'data (key=value) cannot be mixed.')
|
||||||
@ -192,14 +183,14 @@ class Parser(argparse.ArgumentParser):
|
|||||||
' --form is used. File fields: %s'
|
' --form is used. File fields: %s'
|
||||||
% ','.join(args.files.keys()))
|
% ','.join(args.files.keys()))
|
||||||
|
|
||||||
f = list(args.files.values())[0]
|
fn, data = list(args.files.values())[0]
|
||||||
self._body_from_file(args, f)
|
self._body_from_file(args, data)
|
||||||
|
|
||||||
# Reset files
|
# Reset files
|
||||||
args.files = {}
|
args.files = {}
|
||||||
|
|
||||||
if 'Content-Type' not in args.headers:
|
if 'Content-Type' not in args.headers:
|
||||||
mime, encoding = mimetypes.guess_type(f.name, strict=False)
|
mime, encoding = mimetypes.guess_type(fn, strict=False)
|
||||||
if mime:
|
if mime:
|
||||||
content_type = mime
|
content_type = mime
|
||||||
if encoding:
|
if encoding:
|
||||||
@ -414,7 +405,8 @@ def parse_items(items, data=None, headers=None, files=None, params=None):
|
|||||||
target = params
|
target = params
|
||||||
elif item.sep == SEP_FILES:
|
elif item.sep == SEP_FILES:
|
||||||
try:
|
try:
|
||||||
value = open(os.path.expanduser(value), 'r')
|
with open(os.path.expanduser(value), 'r') as f:
|
||||||
|
value = (os.path.basename(f.name), f.read())
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
raise ParseError(
|
raise ParseError(
|
||||||
'Invalid argument "%s": %s' % (item.orig, e))
|
'Invalid argument "%s": %s' % (item.orig, e))
|
||||||
|
@ -11,7 +11,7 @@ from pygments.lexers import get_lexer_for_mimetype
|
|||||||
from pygments.formatters.terminal import TerminalFormatter
|
from pygments.formatters.terminal import TerminalFormatter
|
||||||
from pygments.formatters.terminal256 import Terminal256Formatter
|
from pygments.formatters.terminal256 import Terminal256Formatter
|
||||||
from pygments.util import ClassNotFound
|
from pygments.util import ClassNotFound
|
||||||
from requests.compat import is_windows, bytes
|
from requests.compat import is_windows
|
||||||
|
|
||||||
from . import solarized
|
from . import solarized
|
||||||
from .models import Environment
|
from .models import Environment
|
||||||
|
@ -60,21 +60,18 @@ def httpbin(path):
|
|||||||
return HTTPBIN_URL + path
|
return HTTPBIN_URL + path
|
||||||
|
|
||||||
|
|
||||||
class BytesResponse(bytes):
|
class ResponseMixin(object):
|
||||||
|
|
||||||
exit_status = None
|
exit_status = None
|
||||||
stderr = None
|
stderr = None
|
||||||
json = None
|
json = None
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return super(BytesResponse, self).__eq__(other)
|
|
||||||
|
|
||||||
class StrResponse(str):
|
class BytesResponse(bytes, ResponseMixin):
|
||||||
exit_status = None
|
pass
|
||||||
stderr = None
|
|
||||||
json = None
|
|
||||||
def __eq__(self, other):
|
class StrResponse(str, ResponseMixin):
|
||||||
return super(StrResponse, self).__eq__(other)
|
pass
|
||||||
|
|
||||||
|
|
||||||
def http(*args, **kwargs):
|
def http(*args, **kwargs):
|
||||||
@ -543,7 +540,7 @@ class MultipartFormDataFileUploadTest(BaseTestCase):
|
|||||||
self.assertIn('HTTP/1.1 200', r)
|
self.assertIn('HTTP/1.1 200', r)
|
||||||
self.assertIn('Content-Disposition: form-data; name="foo"', r)
|
self.assertIn('Content-Disposition: form-data; name="foo"', r)
|
||||||
self.assertIn('Content-Disposition: form-data; name="test-file";'
|
self.assertIn('Content-Disposition: form-data; name="test-file";'
|
||||||
' filename="test-file"', r)
|
' filename="%s"' % os.path.basename(TEST_FILE_PATH), r)
|
||||||
self.assertEqual(r.count(TEST_FILE_CONTENT), 2)
|
self.assertEqual(r.count(TEST_FILE_CONTENT), 2)
|
||||||
self.assertIn('"foo": "bar"', r)
|
self.assertIn('"foo": "bar"', r)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user