-
Notifications
You must be signed in to change notification settings - Fork 345
Feat: gzip/decompressed response content handling #584
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 51 commits
ef6d872
0a63b3c
1fb2bce
06606ff
cd57fad
a38e333
57d6d10
1db84f2
cc14082
80d005f
aa6ece2
d88839b
dfc6251
c62dd1a
7080d14
8122dbb
b8b585a
77ca4c7
b4c306f
9ddb911
8f2d0ef
9ec8277
8f254de
aa04dc9
0c4c3b6
92175f2
2b29a54
337c772
77d7b6e
fd30685
0ba2dda
50f7fb7
1d7c8dc
f7b49ed
dd92972
c8a61c0
53567f2
1ed6e11
81d77d2
e3ac25b
440fdcd
2795786
7dcdd23
4a16f7c
8c2a10d
0bc1ff0
5e86c23
f234566
06769c4
4facfed
5caccea
c0d003b
74d1c65
111c27b
2fc6c00
4b2cfb3
4980fcc
3b56a68
1a9b873
4cebd8f
b47cbb6
cce1738
6955a69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
|
|
||
| import asyncio | ||
| import functools | ||
| import zlib | ||
|
|
||
| import aiohttp | ||
| import six | ||
|
|
@@ -31,6 +32,52 @@ | |
| _DEFAULT_TIMEOUT = 180 # in seconds | ||
|
|
||
|
|
||
| class _CombinedResponse(transport.Response): | ||
| """ | ||
| In order to more closely resemble the `requests` interface, where a raw | ||
| and deflated content could be accessed at once, this class lazily reads the | ||
| stream in `transport.Response` so both return forms can be used | ||
| """ | ||
|
|
||
| def __init__(self, response): | ||
| self._response = response | ||
| self._raw_content = None | ||
|
|
||
| def _is_compressed(self): | ||
| # The gzip and deflate transfer-encodings are automatically decoded for you. | ||
|
||
| headers = self._client_response.headers | ||
| return "Content-Encoding" in headers and ( | ||
| headers["Content-Encoding"] == "gzip" | ||
| or headers["Content-Encoding"] == "deflate" | ||
| ) | ||
|
|
||
| @property | ||
| def status(self): | ||
| return self._response.status | ||
|
|
||
| @property | ||
| def headers(self): | ||
| return self._response.headers | ||
|
|
||
| @property | ||
| def data(self): | ||
| return self.content | ||
|
|
||
| async def raw_content(self): | ||
| if self._raw_content is None: | ||
| self._raw_content = await self._response.content.read() | ||
| return self._raw_content | ||
|
|
||
| async def content(self): | ||
| if self._raw_content is None: | ||
| self._raw_content = await self._response.content.read() | ||
| if self._is_compressed: | ||
| d = zlib.decompressobj(zlib.MAX_WBITS | 32) | ||
| decompressed = d.decompress(self._raw_content) | ||
| return decompressed | ||
| return self._raw_content | ||
|
|
||
|
|
||
| class _Response(transport.Response): | ||
| """ | ||
| Requests transport response adapter. | ||
|
|
@@ -79,7 +126,6 @@ class Request(transport.Request): | |
| """ | ||
|
|
||
| def __init__(self, session=None): | ||
|
|
||
| self.session = None | ||
|
|
||
| async def __call__( | ||
|
|
@@ -89,7 +135,7 @@ async def __call__( | |
| body=None, | ||
| headers=None, | ||
| timeout=_DEFAULT_TIMEOUT, | ||
| **kwargs | ||
| **kwargs, | ||
| ): | ||
| """ | ||
| Make an HTTP request using aiohttp. | ||
|
|
@@ -115,7 +161,9 @@ async def __call__( | |
|
|
||
| try: | ||
| if self.session is None: # pragma: NO COVER | ||
| self.session = aiohttp.ClientSession() # pragma: NO COVER | ||
| self.session = aiohttp.ClientSession( | ||
| auto_decompress=False | ||
| ) # pragma: NO COVER | ||
| requests._LOGGER.debug("Making request: %s %s", method, url) | ||
| response = await self.session.request( | ||
| method, url, data=body, headers=headers, timeout=timeout, **kwargs | ||
|
|
@@ -175,6 +223,7 @@ def __init__( | |
| max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS, | ||
| refresh_timeout=None, | ||
| auth_request=None, | ||
| auto_decompress=False, | ||
| ): | ||
| super(AuthorizedSession, self).__init__() | ||
| self.credentials = credentials | ||
|
|
@@ -186,6 +235,7 @@ def __init__( | |
| self._auth_request_session = None | ||
| self._loop = asyncio.get_event_loop() | ||
| self._refresh_lock = asyncio.Lock() | ||
| self._auto_decompress = auto_decompress | ||
|
|
||
| async def request( | ||
| self, | ||
|
|
@@ -195,7 +245,8 @@ async def request( | |
| headers=None, | ||
| max_allowed_time=None, | ||
| timeout=_DEFAULT_TIMEOUT, | ||
| **kwargs | ||
| auto_decompress=False, | ||
| **kwargs, | ||
| ): | ||
|
|
||
| """Implementation of Authorized Session aiohttp request. | ||
|
|
@@ -230,8 +281,14 @@ async def request( | |
| transmitted. The timout error will be raised after such | ||
| request completes. | ||
| """ | ||
|
|
||
| async with aiohttp.ClientSession() as self._auth_request_session: | ||
| if headers: | ||
| for key in headers.keys(): | ||
crwilcox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if type(headers[key]) is bytes: | ||
| headers[key] = headers[key].decode("utf-8") | ||
|
|
||
| async with aiohttp.ClientSession( | ||
| auto_decompress=self._auto_decompress | ||
| ) as self._auth_request_session: | ||
| auth_request = Request(self._auth_request_session) | ||
| self._auth_request = auth_request | ||
|
|
||
|
|
@@ -264,7 +321,7 @@ async def request( | |
| data=data, | ||
| headers=request_headers, | ||
| timeout=timeout, | ||
| **kwargs | ||
| **kwargs, | ||
crwilcox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
|
|
||
| remaining_time = guard.remaining_timeout | ||
|
|
@@ -307,7 +364,7 @@ async def request( | |
| max_allowed_time=remaining_time, | ||
| timeout=timeout, | ||
| _credential_refresh_attempt=_credential_refresh_attempt + 1, | ||
| **kwargs | ||
| **kwargs, | ||
| ) | ||
|
|
||
| return response | ||
Uh oh!
There was an error while loading. Please reload this page.