Skip to content

Commit

Permalink
Merge cc626fb into eb929cb
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksandr-vin committed Aug 30, 2018
2 parents eb929cb + cc626fb commit 727c834
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 5 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ matrix:
language: generic
env:
# Latest Python 3.x from Homebrew
- TOXENV=py37 # <= needs to be kept up-to-date to reflect latest minor version
- TOXENV=py36 # <= needs to be kept up-to-date to reflect latest minor version
- BREW_PYTHON_PACKAGE=python@3
# Travis Python 3.7 must run sudo on
# Travis Python 3.7 must run sudo on
- os: linux
python: 3.7
env: TOXENV=py37
Expand Down
2 changes: 1 addition & 1 deletion AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ Patches and ideas
* `Dennis Brakhane <https://github.com/brakhane>`_
* `Matt Layman <https://github.com/mblayman>`_
* `Edward Yang <https://github.com/honorabrutroll>`_

* `Aleksandr Vinokurov <https://github.com/aleksandr-vin>`_

23 changes: 23 additions & 0 deletions httpie/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,29 @@ def _split_lines(self, text, width):
)


#######################################################################
# Content processing.
#######################################################################

content_processing = parser.add_argument_group(
title='Content Processing Options',
description=None
)

content_processing.add_argument(
'--compress', '-x',
action='count',
help="""
Content compressed (encoded) with Deflate algorithm.
The Content-Encoding header is set to deflate.
Compression is skipped if it appears that compression ratio is
negative. Compression can be forced by repeating the argument.
"""
)


#######################################################################
# Output processing
#######################################################################
Expand Down
32 changes: 30 additions & 2 deletions httpie/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from httpie.plugins import plugin_manager
from httpie.utils import repr_dict_nice

import zlib

try:
# https://urllib3.readthedocs.io/en/latest/security.html
# noinspection PyPackageRequirements
Expand Down Expand Up @@ -42,12 +44,38 @@ def init_poolmanager(self, *args, **kwargs):
super(HTTPieHTTPAdapter, self).init_poolmanager(*args, **kwargs)


def get_requests_session(ssl_version):
class ContentCompressionHttpAdapter(HTTPAdapter):

def __init__(self, compress, **kwargs):
self.compress = compress
super(ContentCompressionHttpAdapter, self).__init__(**kwargs)

def send(self, request, **kwargs):
if request.body and self.compress > 0:
deflater = zlib.compressobj()
print(">>>> " + str(type(request.body)))
if isinstance(request.body, bytes):
deflated_data = deflater.compress(request.body)
else:
deflated_data = deflater.compress(request.body.encode())
deflated_data += deflater.flush()
if len(deflated_data) < len(request.body) or self.compress > 1:
request.body = deflated_data
request.headers['Content-Encoding'] = 'deflate'
request.headers['Content-Length'] = str(len(deflated_data))
return super(ContentCompressionHttpAdapter, self).send(request, **kwargs)


def get_requests_session(ssl_version, compress):
requests_session = requests.Session()
requests_session.mount(
'https://',
HTTPieHTTPAdapter(ssl_version=ssl_version)
)
if compress:
adapter = ContentCompressionHttpAdapter(compress)
for prefix in ['http://', 'https://']:
requests_session.mount(prefix, adapter)
for cls in plugin_manager.get_transport_plugins():
transport_plugin = cls()
requests_session.mount(prefix=transport_plugin.prefix,
Expand All @@ -62,7 +90,7 @@ def get_response(args, config_dir):
if args.ssl_version:
ssl_version = SSL_VERSION_ARG_MAPPING[args.ssl_version]

requests_session = get_requests_session(ssl_version)
requests_session = get_requests_session(ssl_version, args.compress)
requests_session.max_redirects = args.max_redirects

if not args.session and not args.session_read_only:
Expand Down
41 changes: 41 additions & 0 deletions tests/test_httpie.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,28 @@ def test_POST_JSON_data(httpbin_both):
assert r.json['json']['foo'] == 'bar'


def test_POST_JSON_data_compressed(httpbin_both):
r = http('--compress', '--compress', 'POST', httpbin_both + '/post', 'foo=bar')
assert HTTP_OK in r
assert r.json['headers']['Content-Encoding'] == 'deflate'
assert r.json['data'].startswith('data:application/octet-stream;')
assert r.json['json'] is None


def test_POST_form(httpbin_both):
r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar')
assert HTTP_OK in r
assert '"foo": "bar"' in r


def test_POST_form_compressed(httpbin_both):
r = http('--form', '--compress', '--compress', 'POST', httpbin_both + '/post', 'foo=bar')
assert HTTP_OK in r
assert r.json['headers']['Content-Encoding'] == 'deflate'
assert r.json['data'] == ""
assert '"foo": "bar"' not in r


def test_POST_form_multiple_values(httpbin_both):
r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar', 'foo=baz')
assert HTTP_OK in r
Expand All @@ -69,6 +85,31 @@ def test_POST_stdin(httpbin_both):
assert FILE_CONTENT in r


def test_POST_stdin_compressed(httpbin_both):
with open(FILE_PATH) as f:
env = MockEnvironment(stdin=f, stdin_isatty=False)
r = http('--form', '--compress', '--compress', 'POST', httpbin_both + '/post', env=env)
assert HTTP_OK in r
assert r.json['headers']['Content-Encoding'] == 'deflate'
assert r.json['data'] == ""
assert FILE_CONTENT not in r


def test_POST_file(httpbin_both):
r = http('--form', 'POST', httpbin_both + '/post', 'file@' + FILE_PATH)
assert HTTP_OK in r
assert FILE_CONTENT in r


def test_POST_file_compressed(httpbin_both):
r = http('--form', '--compress', '--compress', 'POST', httpbin_both + '/post', 'file@' + FILE_PATH)
assert HTTP_OK in r
assert r.json['headers']['Content-Encoding'] == 'deflate'
assert r.json['headers']['Content-Type'].startswith('multipart/form-data; boundary=')
assert r.json['files'] == {}
assert FILE_CONTENT not in r


def test_headers(httpbin_both):
r = http('GET', httpbin_both + '/headers', 'Foo:bar')
assert HTTP_OK in r
Expand Down

0 comments on commit 727c834

Please sign in to comment.