From 965a1cdffa2c4e85aaf1df3e14015aa5b5fdf24b Mon Sep 17 00:00:00 2001 From: Nick Timkovich Date: Thu, 13 Sep 2018 13:46:57 -0500 Subject: [PATCH 01/14] Quiet warnings about netrc If there isn't a .netrc file specified by an environment variable, it can be confusing to see warnings about it. If NETRC isn't set, don't warn. Only warn if: a) can't resolve HOME, b) can load, but can't parse file, c) can't find file, d) file appears to exist at the default location but is unreadable for some reason. --- aiohttp/helpers.py | 54 +++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/aiohttp/helpers.py b/aiohttp/helpers.py index b062917b846..4cdf3e40c10 100644 --- a/aiohttp/helpers.py +++ b/aiohttp/helpers.py @@ -9,6 +9,7 @@ import inspect import netrc import os +import platform import re import sys import time @@ -146,30 +147,39 @@ def strip_auth_from_url(url: URL) -> Tuple[URL, Optional[BasicAuth]]: def netrc_from_env(): - netrc_obj = None - netrc_path = os.environ.get('NETRC') - try: - if netrc_path is not None: - netrc_path = Path(netrc_path) - else: + """Attempt to load the netrc file from the path specified by the env-var + NETRC or in the default location in the user's home directory. + + Returns ``None`` if it couldn't be found or fails to parse. + """ + netrc_env = os.environ.get('NETRC') + + if netrc_env is not None: + netrc_path = Path(netrc_env) + else: + try: home_dir = Path.home() - if os.name == 'nt': # pragma: no cover - netrc_path = home_dir.joinpath('_netrc') - else: - netrc_path = home_dir.joinpath('.netrc') + except RuntimeError as e: # pragma: no cover + # if pathlib can't resolve home, it may raise a RuntimeError + client_logger.warning('Could not resolve home directory when ' + 'trying to look for .netrc file: %s', e) + return None - if netrc_path and netrc_path.is_file(): - try: - netrc_obj = netrc.netrc(str(netrc_path)) - except (netrc.NetrcParseError, OSError) as e: - client_logger.warning(".netrc file parses fail: %s", e) - - if netrc_obj is None: - client_logger.warning("could't find .netrc file") - except RuntimeError as e: # pragma: no cover - """ handle error raised by pathlib """ - client_logger.warning("could't find .netrc file: %s", e) - return netrc_obj + netrc_path = home_dir / ( + '_netrc' if platform.system() == 'Windows' else '.netrc') + + try: + return netrc.netrc(str(netrc_path)) + except netrc.NetrcParseError as e: + client_logger.warning('Could not parse .netrc file: %s', e) + except OSError as e: + # we couldn't read the file (doesn't exist, permissions, etc.) + if netrc_env or netrc_path.is_file(): + # only warn if the enviroment wanted us to load it, + # or it appears like the default file does actually exist + client_logger.warning('Could not read .netrc file: %s', e) + + return None @attr.s(frozen=True, slots=True) From db3293b87c88b8f4ec5e980c721a75f337b7041e Mon Sep 17 00:00:00 2001 From: Adam Cooper Date: Sun, 14 Oct 2018 21:36:53 +0100 Subject: [PATCH 02/14] Moved the adding of Host header before default headers --- aiohttp/client_reqrep.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 67ba098788c..84cef26ca87 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -311,10 +311,6 @@ def update_auto_headers(self, skip_auto_headers): used_headers = self.headers.copy() used_headers.extend(self.skip_auto_headers) - for hdr, val in self.DEFAULT_HEADERS.items(): - if hdr not in used_headers: - self.headers.add(hdr, val) - # add host if hdrs.HOST not in used_headers: netloc = self.url.raw_host @@ -324,6 +320,10 @@ def update_auto_headers(self, skip_auto_headers): netloc += ':' + str(self.url.port) self.headers[hdrs.HOST] = netloc + for hdr, val in self.DEFAULT_HEADERS.items(): + if hdr not in used_headers: + self.headers.add(hdr, val) + if hdrs.USER_AGENT not in used_headers: self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE From 72e906f5fc166b3e64feac32fb882f919bbef395 Mon Sep 17 00:00:00 2001 From: Adam Cooper Date: Sun, 14 Oct 2018 21:37:19 +0100 Subject: [PATCH 03/14] Added test to ensure Host header is positionally first --- tests/test_client_request.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_client_request.py b/tests/test_client_request.py index 147ea2c49d1..d5ab73abc52 100644 --- a/tests/test_client_request.py +++ b/tests/test_client_request.py @@ -210,6 +210,11 @@ def test_hostname_err(make_request) -> None: make_request('get', 'http://:8080/') +def test_host_header_host_first(make_request) -> None: + req = make_request('get', 'http://python.org/') + assert list(req.headers)[0] == 'Host' + + def test_host_header_host_without_port(make_request) -> None: req = make_request('get', 'http://python.org/') assert req.headers['HOST'] == 'python.org' From e5a332c65826f4c5305d06065cb9f1de1b593c8d Mon Sep 17 00:00:00 2001 From: Adam Cooper Date: Mon, 15 Oct 2018 13:53:47 +0100 Subject: [PATCH 04/14] Added myself to CONTRIBUTORS --- CONTRIBUTORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 76ca43d3209..aacc0ac187d 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -1,6 +1,7 @@ - Contributors - ---------------- A. Jesse Jiryu Davis +Adam Cooper Adam Mills Adrián Chaves Alec Hanefeld From 2b2e99cad11d6a9ad83acbe7ca8ccbfa38ce9af2 Mon Sep 17 00:00:00 2001 From: Adam Cooper Date: Mon, 15 Oct 2018 13:56:37 +0100 Subject: [PATCH 05/14] Added news fragment to outline PR changes --- CHANGES/3265.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 CHANGES/3265.bugfix diff --git a/CHANGES/3265.bugfix b/CHANGES/3265.bugfix new file mode 100644 index 00000000000..a783711c129 --- /dev/null +++ b/CHANGES/3265.bugfix @@ -0,0 +1 @@ +Ensure Host header is added first to ClientRequest to better replicate browser From b26d4a83e795661acfe1701c397c338b48b92f55 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Mon, 15 Oct 2018 12:20:21 -0700 Subject: [PATCH 06/14] Scheduled weekly dependency update for week 41 (#3344) * Update async-timeout from 3.0.0 to 3.0.1 * Update cython from 0.28.5 to 0.29 * Update cython from 0.28.5 to 0.29 * Update cython from 0.28.5 to 0.29 * Update gunicorn from 19.8.1 to 19.9.0 * Update tox from 3.5.0 to 3.5.2 --- requirements/ci-wheel.txt | 8 ++++---- requirements/cython.txt | 2 +- requirements/wheel.txt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/requirements/ci-wheel.txt b/requirements/ci-wheel.txt index cbb703e4269..133f1adc31c 100644 --- a/requirements/ci-wheel.txt +++ b/requirements/ci-wheel.txt @@ -1,20 +1,20 @@ -r flake.txt attrs==18.2.0 async-generator==1.10 -async-timeout==3.0.0 +async-timeout==3.0.1 brotlipy==0.7.0 cchardet==2.1.4 chardet==3.0.4 coverage==4.5.1 -cython==0.28.5 -gunicorn==19.8.1 +cython==0.29 +gunicorn==19.9.0 pyflakes==2.0.0 multidict==4.4.2 pytest==3.8.2 pytest-cov==2.6.0 pytest-mock==1.10.0 pytest-xdist==1.23.2 -tox==3.5.0 +tox==3.5.2 twine==1.12.1 yarl==1.2.6 diff --git a/requirements/cython.txt b/requirements/cython.txt index 64c06c65b80..4d49466ac1e 100644 --- a/requirements/cython.txt +++ b/requirements/cython.txt @@ -1 +1 @@ -cython==0.28.5 +cython==0.29 diff --git a/requirements/wheel.txt b/requirements/wheel.txt index 3b041a89869..79d8a057f92 100644 --- a/requirements/wheel.txt +++ b/requirements/wheel.txt @@ -1,3 +1,3 @@ -cython==0.28.5 +cython==0.29 pytest==3.8.2 twine==1.12.1 From 3e50a9b3a234e6857f8c3deab008747456a3f1c9 Mon Sep 17 00:00:00 2001 From: Adam Cooper Date: Mon, 15 Oct 2018 20:40:47 +0100 Subject: [PATCH 07/14] Implemented server side functional test to ensure Host header order is first --- tests/test_client_functional.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py index f9c870d35cc..56bf80418db 100644 --- a/tests/test_client_functional.py +++ b/tests/test_client_functional.py @@ -497,6 +497,18 @@ async def handler(request): resp.close() +async def test_host_header_first(aiohttp_client) -> None: + async def handler(request): + assert list(request.headers)[0] == hdrs.HOST + return web.Response() + + app = web.Application() + app.router.add_route('GET', '/', handler) + client = await aiohttp_client(app) + resp = await client.get('/') + assert resp.status == 200 + + async def test_empty_header_values(aiohttp_client) -> None: async def handler(request): resp = web.Response() From ebc0a99e7c452ff21c37c5e15babc812cbeb0801 Mon Sep 17 00:00:00 2001 From: Adam Cooper Date: Mon, 15 Oct 2018 20:41:11 +0100 Subject: [PATCH 08/14] Moved the processing logic of Host header into update_headers from update_auto_headers --- aiohttp/client_reqrep.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 84cef26ca87..8e49f37358e 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -305,14 +305,8 @@ def update_headers(self, headers): for key, value in headers: self.headers.add(key, value) - def update_auto_headers(self, skip_auto_headers): - self.skip_auto_headers = CIMultiDict( - (hdr, None) for hdr in sorted(skip_auto_headers)) - used_headers = self.headers.copy() - used_headers.extend(self.skip_auto_headers) - # add host - if hdrs.HOST not in used_headers: + if hdrs.HOST not in self.headers: netloc = self.url.raw_host if helpers.is_ipv6_address(netloc): netloc = '[{}]'.format(netloc) @@ -320,6 +314,12 @@ def update_auto_headers(self, skip_auto_headers): netloc += ':' + str(self.url.port) self.headers[hdrs.HOST] = netloc + def update_auto_headers(self, skip_auto_headers): + self.skip_auto_headers = CIMultiDict( + (hdr, None) for hdr in sorted(skip_auto_headers)) + used_headers = self.headers.copy() + used_headers.extend(self.skip_auto_headers) + for hdr, val in self.DEFAULT_HEADERS.items(): if hdr not in used_headers: self.headers.add(hdr, val) From 427204bb914fe8a9a563d447934d1eaa19449dd9 Mon Sep 17 00:00:00 2001 From: Dmytro Bohomiakov Date: Tue, 16 Oct 2018 11:03:55 +0300 Subject: [PATCH 09/14] Add typings for Tracing (#3343) --- CHANGES/1749.feature | 1 + CONTRIBUTORS.txt | 1 + aiohttp/tracing.py | 147 ++++++++++++++++++++++++++----------------- 3 files changed, 92 insertions(+), 57 deletions(-) diff --git a/CHANGES/1749.feature b/CHANGES/1749.feature index dcf34f34d05..934941b1fa5 100644 --- a/CHANGES/1749.feature +++ b/CHANGES/1749.feature @@ -2,3 +2,4 @@ Add type hints to Application and Response Add type hints to Exceptions Upgrade mypy to 0.630 Add type hints to payload.py +Add type hints to tracing.py diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 76ca43d3209..cedb4234dd4 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -69,6 +69,7 @@ Dmitry Doroshev Dmitry Lukashin Dmitry Shamov Dmitry Trofimov +Dmytro Bohomiakov Dmytro Kuznetsov Dustin J. Mitchell Eduard Iskandarov diff --git a/aiohttp/tracing.py b/aiohttp/tracing.py index 165e68cbf9d..960e47037d4 100644 --- a/aiohttp/tracing.py +++ b/aiohttp/tracing.py @@ -1,13 +1,22 @@ from types import SimpleNamespace +from typing import TYPE_CHECKING, Awaitable, Callable, Type import attr -from multidict import CIMultiDict +from multidict import CIMultiDict # noqa from yarl import URL from .client_reqrep import ClientResponse from .signals import Signal +if TYPE_CHECKING: # pragma: no cover + from .client import ClientSession # noqa + + _Signal = Signal[Callable[['TraceConfig'], Awaitable[None]]] +else: + _Signal = Signal + + __all__ = ( 'TraceConfig', 'TraceRequestStartParams', 'TraceRequestEndParams', 'TraceRequestExceptionParams', 'TraceConnectionQueuedStartParams', @@ -24,31 +33,37 @@ class TraceConfig: """First-class used to trace requests launched via ClientSession objects.""" - def __init__(self, trace_config_ctx_factory=SimpleNamespace): - self._on_request_start = Signal(self) - self._on_request_chunk_sent = Signal(self) - self._on_response_chunk_received = Signal(self) - self._on_request_end = Signal(self) - self._on_request_exception = Signal(self) - self._on_request_redirect = Signal(self) - self._on_connection_queued_start = Signal(self) - self._on_connection_queued_end = Signal(self) - self._on_connection_create_start = Signal(self) - self._on_connection_create_end = Signal(self) - self._on_connection_reuseconn = Signal(self) - self._on_dns_resolvehost_start = Signal(self) - self._on_dns_resolvehost_end = Signal(self) - self._on_dns_cache_hit = Signal(self) - self._on_dns_cache_miss = Signal(self) - - self._trace_config_ctx_factory = trace_config_ctx_factory - - def trace_config_ctx(self, trace_request_ctx=None): + def __init__( + self, + trace_config_ctx_factory: Type[SimpleNamespace]=SimpleNamespace + ) -> None: + self._on_request_start = Signal(self) # type: _Signal + self._on_request_chunk_sent = Signal(self) # type: _Signal + self._on_response_chunk_received = Signal(self) # type: _Signal + self._on_request_end = Signal(self) # type: _Signal + self._on_request_exception = Signal(self) # type: _Signal + self._on_request_redirect = Signal(self) # type: _Signal + self._on_connection_queued_start = Signal(self) # type: _Signal + self._on_connection_queued_end = Signal(self) # type: _Signal + self._on_connection_create_start = Signal(self) # type: _Signal + self._on_connection_create_end = Signal(self) # type: _Signal + self._on_connection_reuseconn = Signal(self) # type: _Signal + self._on_dns_resolvehost_start = Signal(self) # type: _Signal + self._on_dns_resolvehost_end = Signal(self) # type: _Signal + self._on_dns_cache_hit = Signal(self) # type: _Signal + self._on_dns_cache_miss = Signal(self) # type: _Signal + + self._trace_config_ctx_factory = trace_config_ctx_factory # type: Type[SimpleNamespace] # noqa + + def trace_config_ctx( + self, + trace_request_ctx: SimpleNamespace=None + ) -> SimpleNamespace: # noqa """ Return a new trace_config_ctx instance """ return self._trace_config_ctx_factory( trace_request_ctx=trace_request_ctx) - def freeze(self): + def freeze(self) -> None: self._on_request_start.freeze() self._on_request_chunk_sent.freeze() self._on_response_chunk_received.freeze() @@ -66,63 +81,63 @@ def freeze(self): self._on_dns_cache_miss.freeze() @property - def on_request_start(self): + def on_request_start(self) -> _Signal: return self._on_request_start @property - def on_request_chunk_sent(self): + def on_request_chunk_sent(self) -> _Signal: return self._on_request_chunk_sent @property - def on_response_chunk_received(self): + def on_response_chunk_received(self) -> _Signal: return self._on_response_chunk_received @property - def on_request_end(self): + def on_request_end(self) -> _Signal: return self._on_request_end @property - def on_request_exception(self): + def on_request_exception(self) -> _Signal: return self._on_request_exception @property - def on_request_redirect(self): + def on_request_redirect(self) -> _Signal: return self._on_request_redirect @property - def on_connection_queued_start(self): + def on_connection_queued_start(self) -> _Signal: return self._on_connection_queued_start @property - def on_connection_queued_end(self): + def on_connection_queued_end(self) -> _Signal: return self._on_connection_queued_end @property - def on_connection_create_start(self): + def on_connection_create_start(self) -> _Signal: return self._on_connection_create_start @property - def on_connection_create_end(self): + def on_connection_create_end(self) -> _Signal: return self._on_connection_create_end @property - def on_connection_reuseconn(self): + def on_connection_reuseconn(self) -> _Signal: return self._on_connection_reuseconn @property - def on_dns_resolvehost_start(self): + def on_dns_resolvehost_start(self) -> _Signal: return self._on_dns_resolvehost_start @property - def on_dns_resolvehost_end(self): + def on_dns_resolvehost_end(self) -> _Signal: return self._on_dns_resolvehost_end @property - def on_dns_cache_hit(self): + def on_dns_cache_hit(self) -> _Signal: return self._on_dns_cache_hit @property - def on_dns_cache_miss(self): + def on_dns_cache_miss(self) -> _Signal: return self._on_dns_cache_miss @@ -131,7 +146,7 @@ class TraceRequestStartParams: """ Parameters sent by the `on_request_start` signal""" method = attr.ib(type=str) url = attr.ib(type=URL) - headers = attr.ib(type=CIMultiDict) + headers = attr.ib(type='CIMultiDict[str]') @attr.s(frozen=True, slots=True) @@ -151,7 +166,7 @@ class TraceRequestEndParams: """ Parameters sent by the `on_request_end` signal""" method = attr.ib(type=str) url = attr.ib(type=URL) - headers = attr.ib(type=CIMultiDict) + headers = attr.ib(type='CIMultiDict[str]') response = attr.ib(type=ClientResponse) @@ -160,7 +175,7 @@ class TraceRequestExceptionParams: """ Parameters sent by the `on_request_exception` signal""" method = attr.ib(type=str) url = attr.ib(type=URL) - headers = attr.ib(type=CIMultiDict) + headers = attr.ib(type='CIMultiDict[str]') exception = attr.ib(type=Exception) @@ -169,7 +184,7 @@ class TraceRequestRedirectParams: """ Parameters sent by the `on_request_redirect` signal""" method = attr.ib(type=str) url = attr.ib(type=URL) - headers = attr.ib(type=CIMultiDict) + headers = attr.ib(type='CIMultiDict[str]') response = attr.ib(type=ClientResponse) @@ -226,110 +241,128 @@ class Trace: """ Internal class used to keep together the main dependencies used at the moment of send a signal.""" - def __init__(self, session, trace_config, trace_config_ctx): + def __init__(self, + session: 'ClientSession', + trace_config: TraceConfig, + trace_config_ctx: SimpleNamespace) -> None: self._trace_config = trace_config self._trace_config_ctx = trace_config_ctx self._session = session - async def send_request_start(self, method, url, headers): + async def send_request_start(self, + method: str, + url: URL, + headers: 'CIMultiDict[str]') -> None: return await self._trace_config.on_request_start.send( self._session, self._trace_config_ctx, TraceRequestStartParams(method, url, headers) ) - async def send_request_chunk_sent(self, chunk): + async def send_request_chunk_sent(self, chunk: bytes) -> None: return await self._trace_config.on_request_chunk_sent.send( self._session, self._trace_config_ctx, TraceRequestChunkSentParams(chunk) ) - async def send_response_chunk_received(self, chunk): + async def send_response_chunk_received(self, chunk: bytes) -> None: return await self._trace_config.on_response_chunk_received.send( self._session, self._trace_config_ctx, TraceResponseChunkReceivedParams(chunk) ) - async def send_request_end(self, method, url, headers, response): + async def send_request_end(self, + method: str, + url: URL, + headers: 'CIMultiDict[str]', + response: ClientResponse) -> None: return await self._trace_config.on_request_end.send( self._session, self._trace_config_ctx, TraceRequestEndParams(method, url, headers, response) ) - async def send_request_exception(self, method, url, headers, exception): + async def send_request_exception(self, + method: str, + url: URL, + headers: 'CIMultiDict[str]', + exception: Exception) -> None: return await self._trace_config.on_request_exception.send( self._session, self._trace_config_ctx, TraceRequestExceptionParams(method, url, headers, exception) ) - async def send_request_redirect(self, method, url, headers, response): + async def send_request_redirect(self, + method: str, + url: URL, + headers: 'CIMultiDict[str]', + response: ClientResponse) -> None: return await self._trace_config._on_request_redirect.send( self._session, self._trace_config_ctx, TraceRequestRedirectParams(method, url, headers, response) ) - async def send_connection_queued_start(self): + async def send_connection_queued_start(self) -> None: return await self._trace_config.on_connection_queued_start.send( self._session, self._trace_config_ctx, TraceConnectionQueuedStartParams() ) - async def send_connection_queued_end(self): + async def send_connection_queued_end(self) -> None: return await self._trace_config.on_connection_queued_end.send( self._session, self._trace_config_ctx, TraceConnectionQueuedEndParams() ) - async def send_connection_create_start(self): + async def send_connection_create_start(self) -> None: return await self._trace_config.on_connection_create_start.send( self._session, self._trace_config_ctx, TraceConnectionCreateStartParams() ) - async def send_connection_create_end(self): + async def send_connection_create_end(self) -> None: return await self._trace_config.on_connection_create_end.send( self._session, self._trace_config_ctx, TraceConnectionCreateEndParams() ) - async def send_connection_reuseconn(self): + async def send_connection_reuseconn(self) -> None: return await self._trace_config.on_connection_reuseconn.send( self._session, self._trace_config_ctx, TraceConnectionReuseconnParams() ) - async def send_dns_resolvehost_start(self, host): + async def send_dns_resolvehost_start(self, host: str) -> None: return await self._trace_config.on_dns_resolvehost_start.send( self._session, self._trace_config_ctx, TraceDnsResolveHostStartParams(host) ) - async def send_dns_resolvehost_end(self, host): + async def send_dns_resolvehost_end(self, host: str) -> None: return await self._trace_config.on_dns_resolvehost_end.send( self._session, self._trace_config_ctx, TraceDnsResolveHostEndParams(host) ) - async def send_dns_cache_hit(self, host): + async def send_dns_cache_hit(self, host: str) -> None: return await self._trace_config.on_dns_cache_hit.send( self._session, self._trace_config_ctx, TraceDnsCacheHitParams(host) ) - async def send_dns_cache_miss(self, host): + async def send_dns_cache_miss(self, host: str) -> None: return await self._trace_config.on_dns_cache_miss.send( self._session, self._trace_config_ctx, From e0bd30aa8d339be47316e53360b63d92252aac12 Mon Sep 17 00:00:00 2001 From: Oisin Aylward Date: Tue, 16 Oct 2018 09:04:58 +0100 Subject: [PATCH 10/14] Deprecated use of boolean in resp.enable_compression() (#3322) --- CHANGES/3318.removal | 1 + CONTRIBUTORS.txt | 1 + aiohttp/web_response.py | 2 ++ tests/test_web_response.py | 6 ++++-- 4 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 CHANGES/3318.removal diff --git a/CHANGES/3318.removal b/CHANGES/3318.removal new file mode 100644 index 00000000000..8c8236e7403 --- /dev/null +++ b/CHANGES/3318.removal @@ -0,0 +1 @@ +Deprecated use of boolean in ``resp.enable_compression()`` diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index cedb4234dd4..fb4639c8461 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -155,6 +155,7 @@ Mun Gwan-gyeong Nicolas Braem Nikolay Kim Nikolay Novik +Oisin Aylward Olaf Conradi Pahaz Blinov Panagiotis Kolokotronis diff --git a/aiohttp/web_response.py b/aiohttp/web_response.py index c6e9afc71d0..f3fc59e43d6 100644 --- a/aiohttp/web_response.py +++ b/aiohttp/web_response.py @@ -131,6 +131,8 @@ def enable_compression(self, force=None): # Backwards compatibility for when force was a bool <0.17. if type(force) == bool: force = ContentCoding.deflate if force else ContentCoding.identity + warnings.warn("Using boolean for force is deprecated #3318", + DeprecationWarning) elif force is not None: assert isinstance(force, ContentCoding), ("force should one of " "None, bool or " diff --git a/tests/test_web_response.py b/tests/test_web_response.py index 5ae43ebb782..8e970fe1a66 100644 --- a/tests/test_web_response.py +++ b/tests/test_web_response.py @@ -326,7 +326,8 @@ async def test_force_compression_no_accept_backwards_compat() -> None: assert not resp.chunked assert not resp.compression - resp.enable_compression(force=True) + with pytest.warns(DeprecationWarning): + resp.enable_compression(force=True) assert resp.compression msg = await resp.prepare(req) @@ -339,7 +340,8 @@ async def test_force_compression_false_backwards_compat() -> None: resp = StreamResponse() assert not resp.compression - resp.enable_compression(force=False) + with pytest.warns(DeprecationWarning): + resp.enable_compression(force=False) assert resp.compression msg = await resp.prepare(req) From 08df96ac7e5734808ba1e2a90225f1865627c35f Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 16 Oct 2018 11:42:32 +0300 Subject: [PATCH 11/14] Update client_reqrep.py --- aiohttp/client_reqrep.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 8e49f37358e..37744b69418 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -298,12 +298,6 @@ def update_version(self, version): def update_headers(self, headers): """Update request headers.""" self.headers = CIMultiDict() - if headers: - if isinstance(headers, (dict, MultiDictProxy, MultiDict)): - headers = headers.items() - - for key, value in headers: - self.headers.add(key, value) # add host if hdrs.HOST not in self.headers: @@ -313,6 +307,14 @@ def update_headers(self, headers): if not self.url.is_default_port(): netloc += ':' + str(self.url.port) self.headers[hdrs.HOST] = netloc + + if headers: + if isinstance(headers, (dict, MultiDictProxy, MultiDict)): + headers = headers.items() + + for key, value in headers: + self.headers.add(key, value) + def update_auto_headers(self, skip_auto_headers): self.skip_auto_headers = CIMultiDict( From 8d8283135847f296b0adab7a798e97f1b464e874 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 16 Oct 2018 12:57:37 +0300 Subject: [PATCH 12/14] Fix flake8 --- aiohttp/client_reqrep.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 37744b69418..7cd437a95bd 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -307,7 +307,7 @@ def update_headers(self, headers): if not self.url.is_default_port(): netloc += ':' + str(self.url.port) self.headers[hdrs.HOST] = netloc - + if headers: if isinstance(headers, (dict, MultiDictProxy, MultiDict)): headers = headers.items() @@ -315,7 +315,6 @@ def update_headers(self, headers): for key, value in headers: self.headers.add(key, value) - def update_auto_headers(self, skip_auto_headers): self.skip_auto_headers = CIMultiDict( (hdr, None) for hdr in sorted(skip_auto_headers)) From 21175eefba252f977bbbc6e79b4a0307c5e48916 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 16 Oct 2018 14:05:22 +0300 Subject: [PATCH 13/14] Add a scpecial handling for Host header --- aiohttp/client_reqrep.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 7cd437a95bd..7029901617e 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -313,7 +313,11 @@ def update_headers(self, headers): headers = headers.items() for key, value in headers: - self.headers.add(key, value) + # A special case for Host header + if key.lower() == 'host': + self.headers[key] = value + else: + self.headers.add(key, value) def update_auto_headers(self, skip_auto_headers): self.skip_auto_headers = CIMultiDict( From ca05ee5dff7735b1795e1c493ca8a767cb3d78d3 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 16 Oct 2018 15:39:34 +0300 Subject: [PATCH 14/14] Drop always positive check --- aiohttp/client_reqrep.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 7029901617e..88805315f6e 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -300,13 +300,12 @@ def update_headers(self, headers): self.headers = CIMultiDict() # add host - if hdrs.HOST not in self.headers: - netloc = self.url.raw_host - if helpers.is_ipv6_address(netloc): - netloc = '[{}]'.format(netloc) - if not self.url.is_default_port(): - netloc += ':' + str(self.url.port) - self.headers[hdrs.HOST] = netloc + netloc = self.url.raw_host + if helpers.is_ipv6_address(netloc): + netloc = '[{}]'.format(netloc) + if not self.url.is_default_port(): + netloc += ':' + str(self.url.port) + self.headers[hdrs.HOST] = netloc if headers: if isinstance(headers, (dict, MultiDictProxy, MultiDict)):