From bc431fceb64396f190508c9aa829eec39a9329f3 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sat, 29 Aug 2015 13:30:34 -0400 Subject: [PATCH 1/9] Add skip_auto_headers parameter --- aiohttp/client.py | 11 +++++++++-- aiohttp/client_reqrep.py | 26 ++++++++++++++++++++++---- aiohttp/protocol.py | 5 ----- tests/test_client_request.py | 20 ++++++++++++++++++++ tests/test_http_protocol.py | 16 ---------------- 5 files changed, 51 insertions(+), 27 deletions(-) diff --git a/aiohttp/client.py b/aiohttp/client.py index dc0a8b176c8..cd3d0b3b95a 100644 --- a/aiohttp/client.py +++ b/aiohttp/client.py @@ -32,7 +32,8 @@ class ClientSession: _connector = None def __init__(self, *, connector=None, loop=None, cookies=None, - headers=None, auth=None, request_class=ClientRequest, + headers=None, skip_auto_headers=None, + auth=None, request_class=ClientRequest, response_class=ClientResponse, ws_response_class=ClientWebSocketResponse): @@ -65,6 +66,10 @@ def __init__(self, *, connector=None, loop=None, cookies=None, else: headers = CIMultiDict() self._default_headers = headers + if skip_auto_headers is not None: + self._skip_auto_headers = frozenset(skip_auto_headers) + else: + self._skip_auto_headers = frozenset() self._request_class = request_class self._response_class = response_class @@ -88,6 +93,7 @@ def request(self, method, url, *, params=None, data=None, headers=None, + skip_auto_headers=None, files=None, auth=None, allow_redirects=True, @@ -121,7 +127,8 @@ def request(self, method, url, *, while True: req = self._request_class( - method, url, params=params, headers=headers, data=data, + method, url, params=params, headers=headers, + skip_auto_headers=skip_auto_headers, data=data, cookies=self.cookies, files=files, encoding=encoding, auth=auth, version=version, compress=compress, chunked=chunked, expect100=expect100, diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 9b235c62604..cafcbac341f 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -18,8 +18,10 @@ from . import hdrs, helpers, streams from .log import client_logger from .streams import EOF_MARKER, FlowControlStreamReader -from .multidict import CIMultiDictProxy, MultiDictProxy, MultiDict, CIMultiDict +from .multidict import (CIMultiDictProxy, MultiDictProxy, MultiDict, + CIMultiDict, upstr) from .multipart import MultipartWriter +from .protocol import HttpMessage PY_341 = sys.version_info >= (3, 4, 1) @@ -39,6 +41,8 @@ class ClientRequest: hdrs.ACCEPT_ENCODING: 'gzip, deflate', } + SERVER_SOFTWARE = HttpMessage.SERVER_SOFTWARE + body = b'' auth = None response = None @@ -53,7 +57,8 @@ class ClientRequest: # Until writer has finished finalizer will not be called. def __init__(self, method, url, *, - params=None, headers=None, data=None, cookies=None, + params=None, headers=None, skip_auto_headers=None, + data=None, cookies=None, files=None, auth=None, encoding='utf-8', version=aiohttp.HttpVersion11, compress=None, chunked=None, expect100=False, @@ -77,6 +82,7 @@ def __init__(self, method, url, *, self.update_host(url) self.update_path(params) self.update_headers(headers) + self.update_auto_headers(skip_auto_headers) self.update_cookies(cookies) self.update_content_encoding() self.update_auth(auth) @@ -191,14 +197,26 @@ def update_headers(self, headers): for key, value in headers: self.headers.add(key, value) + def update_auto_headers(self, skip_auto_headers): + used_headers = set(self.headers) + if skip_auto_headers is not None: + for i in skip_auto_headers: + if not isinstance(i, upstr): + raise ValueError( + 'skip_auto_headers should be set of upstr') + used_headers.add(i) + for hdr, val in self.DEFAULT_HEADERS.items(): - if hdr not in self.headers: + if hdr not in used_headers: self.headers[hdr] = val # add host - if hdrs.HOST not in self.headers: + if hdrs.HOST not in used_headers: self.headers[hdrs.HOST] = self.netloc + if hdrs.USER_AGENT not in used_headers: + self.headers[hdrs.USER_AGENT] = self.SERVER_SOFTWARE + def update_cookies(self, cookies): """Update request cookies header.""" if not cookies: diff --git a/aiohttp/protocol.py b/aiohttp/protocol.py index 6fc23d1c39b..c99eb09245f 100644 --- a/aiohttp/protocol.py +++ b/aiohttp/protocol.py @@ -857,8 +857,3 @@ def __init__(self, transport, method, path, self.path = path self.status_line = '{0} {1} HTTP/{2[0]}.{2[1]}\r\n'.format( method, path, http_version) - - def _add_default_headers(self): - super()._add_default_headers() - - self.headers.setdefault(hdrs.USER_AGENT, self.SERVER_SOFTWARE) diff --git a/tests/test_client_request.py b/tests/test_client_request.py index ca88def9701..70cc0cc0630 100644 --- a/tests/test_client_request.py +++ b/tests/test_client_request.py @@ -10,6 +10,7 @@ import aiohttp from aiohttp.client_reqrep import ClientRequest, ClientResponse +from aiohttp.multidict import upstr PY_341 = sys.version_info >= (3, 4, 1) @@ -101,6 +102,25 @@ def test_host_header(self): self.assertEqual(req.headers['HOST'], 'example.com:99') self.loop.run_until_complete(req.close()) + def test_default_headers_useragent(self): + req = ClientRequest('get', 'http://python.org/', loop=self.loop) + + self.assertNotIn('SERVER', req.headers) + self.assertIn('USER-AGENT', req.headers) + + def test_default_headers_useragent_custom(self): + req = ClientRequest('get', 'http://python.org/', loop=self.loop, + headers={'user-agent': 'my custom agent'}) + + self.assertIn('USER-Agent', req.headers) + self.assertEqual('my custom agent', req.headers['User-Agent']) + + def test_skip_default_useragent_header(self): + req = ClientRequest('get', 'http://python.org/', loop=self.loop, + skip_auto_headers=(upstr('user-agent'),)) + + self.assertNotIn('User-Agent', req.headers) + def test_headers(self): req = ClientRequest('get', 'http://python.org/', headers={'Content-Type': 'text/plain'}, diff --git a/tests/test_http_protocol.py b/tests/test_http_protocol.py index f472026a148..b8a01aadca3 100644 --- a/tests/test_http_protocol.py +++ b/tests/test_http_protocol.py @@ -172,22 +172,6 @@ def test_default_headers_server(self): self.assertIn('SERVER', msg.headers) - def test_default_headers_useragent(self): - msg = protocol.Request(self.transport, 'GET', '/') - msg._add_default_headers() - - self.assertNotIn('SERVER', msg.headers) - self.assertIn('USER-AGENT', msg.headers) - - def test_default_headers_useragent_custom(self): - msg = protocol.Request(self.transport, 'GET', '/') - msg.add_headers(('user-agent', 'my custom agent')) - msg._add_default_headers() - - headers = [r for r, _ in msg.headers.items() - if r.lower() == 'user-agent'] - self.assertEqual(len(headers), 1) - def test_default_headers_chunked(self): msg = protocol.Response(self.transport, 200) msg._add_default_headers() From 0b17644a24dfc2febaf05ffaeddfe42dd102aee4 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sat, 29 Aug 2015 15:23:56 -0400 Subject: [PATCH 2/9] Merge passed and default skip lists for client headers --- aiohttp/client.py | 10 ++++++++-- tests/test_client_session.py | 32 +++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/aiohttp/client.py b/aiohttp/client.py index cd3d0b3b95a..20feea05c07 100644 --- a/aiohttp/client.py +++ b/aiohttp/client.py @@ -67,7 +67,8 @@ def __init__(self, *, connector=None, loop=None, cookies=None, headers = CIMultiDict() self._default_headers = headers if skip_auto_headers is not None: - self._skip_auto_headers = frozenset(skip_auto_headers) + self._skip_auto_headers = frozenset([upstr(i) + for i in skip_auto_headers]) else: self._skip_auto_headers = frozenset() @@ -125,10 +126,15 @@ def request(self, method, url, *, raise ValueError("Can't combine `Authorization` header with " "`auth` argument") + skip_headers = self._skip_auto_headers + if skip_auto_headers is not None: + for i in self.skip_auto_headers: + skip_headers.add(upstr(i)) + while True: req = self._request_class( method, url, params=params, headers=headers, - skip_auto_headers=skip_auto_headers, data=data, + skip_auto_headers=skip_headers, data=data, cookies=self.cookies, files=files, encoding=encoding, auth=auth, version=version, compress=compress, chunked=chunked, expect100=expect100, diff --git a/tests/test_client_session.py b/tests/test_client_session.py index 0ef2cfb84bf..7dbd4c70e7f 100644 --- a/tests/test_client_session.py +++ b/tests/test_client_session.py @@ -9,7 +9,7 @@ import aiohttp from aiohttp.client import ClientSession -from aiohttp.multidict import MultiDict, CIMultiDict, CIMultiDictProxy +from aiohttp.multidict import MultiDict, CIMultiDict, CIMultiDictProxy, upstr from aiohttp.connector import BaseConnector, TCPConnector from aiohttp.client_reqrep import ClientRequest, ClientResponse from http.cookies import SimpleCookie @@ -141,8 +141,8 @@ def test_merge_headers_with_list_of_tuples(self): ])) session.close() - def _make_one(self): - session = ClientSession(loop=self.loop) + def _make_one(self, **kwargs): + session = ClientSession(loop=self.loop, **kwargs) params = dict( headers={"Authorization": "Basic ..."}, max_redirects=2, @@ -375,6 +375,32 @@ def test_borrow_connector_loop(self): session = ClientSession(connector=conn) self.assertIs(session._loop, self.loop) + @mock.patch("aiohttp.client.ClientSession.request") + def test_skip_auto_headers(self, patched): + session, params = self._make_one() + skip = [upstr('user-agent')] + self.run(session.get("http://example.com", + skip_auto_headers=skip, + **params)) + params['skip_auto_headers'] = skip + self.assertTrue(patched.called, "`ClientSession.request` not called") + self.assertEqual(patched.call_args[1]['skip_auto_headers'], skip) + session.close() + + @mock.patch("aiohttp.client.ClientSession.request") + def test_skip_auto_headers_default(self, patched): + skip = ['user-agent'] + uskip = [upstr(i) for i in skip] + import ipdb;ipdb.set_trace() + session, params = self._make_one(skip_auto_headers=skip) + self.run(session.get("http://example.com", + **params)) + params['skip_auto_headers'] = skip + self.assertTrue(patched.called, "`ClientSession.request` not called") + print(patched.call_args) + self.assertEqual(patched.call_args[1]['skip_auto_headers'], uskip) + session.close() + class TestCLientRequest(unittest.TestCase): From b6bfb7afbe1b786ca396757c5a88c3822fc4057a Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 30 Aug 2015 23:07:48 -0400 Subject: [PATCH 3/9] Write functional tests for skipping headers --- aiohttp/client.py | 4 +- tests/test_client_functional2.py | 98 ++++++++++++++++++++++++++++++++ tests/test_client_session.py | 28 +-------- 3 files changed, 101 insertions(+), 29 deletions(-) create mode 100644 tests/test_client_functional2.py diff --git a/aiohttp/client.py b/aiohttp/client.py index 20feea05c07..d9525ecbfab 100644 --- a/aiohttp/client.py +++ b/aiohttp/client.py @@ -126,9 +126,9 @@ def request(self, method, url, *, raise ValueError("Can't combine `Authorization` header with " "`auth` argument") - skip_headers = self._skip_auto_headers + skip_headers = set(self._skip_auto_headers) if skip_auto_headers is not None: - for i in self.skip_auto_headers: + for i in skip_auto_headers: skip_headers.add(upstr(i)) while True: diff --git a/tests/test_client_functional2.py b/tests/test_client_functional2.py new file mode 100644 index 00000000000..0b65d95be02 --- /dev/null +++ b/tests/test_client_functional2.py @@ -0,0 +1,98 @@ +import asyncio +import socket +import unittest + +import aiohttp +from aiohttp import hdrs, log, web + + +class TestClientFunctional2(unittest.TestCase): + + def setUp(self): + self.handler = None + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(None) + self.client = aiohttp.ClientSession(loop=self.loop) + + def tearDown(self): + if self.handler: + self.loop.run_until_complete(self.handler.finish_connections()) + self.client.close() + self.loop.stop() + self.loop.run_forever() + self.loop.close() + + def find_unused_port(self): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(('127.0.0.1', 0)) + port = s.getsockname()[1] + s.close() + return port + + @asyncio.coroutine + def create_server(self): + app = web.Application(loop=self.loop) + + port = self.find_unused_port() + self.handler = app.make_handler( + debug=True, keep_alive_on=False, + access_log=log.access_logger) + srv = yield from self.loop.create_server( + self.handler, '127.0.0.1', port) + url = "http://127.0.0.1:{}".format(port) + self.addCleanup(srv.close) + return app, srv, url + + def test_auto_header_user_agent(self): + @asyncio.coroutine + def handler(request): + self.assertIn('aiohttp', request.headers['user-agent']) + return web.Response() + + @asyncio.coroutine + def go(): + app, srv, url = yield from self.create_server() + app.router.add_route('get', '/', handler) + resp = yield from self.client.get(url+'/') + self.assertEqual(200, resp.status) + yield from resp.release() + + self.loop.run_until_complete(go()) + + def test_skip_auto_headers_user_agent(self): + @asyncio.coroutine + def handler(request): + self.assertNotIn(hdrs.USER_AGENT, request.headers) + return web.Response() + + @asyncio.coroutine + def go(): + app, srv, url = yield from self.create_server() + app.router.add_route('get', '/', handler) + resp = yield from self.client.get(url+'/', + skip_auto_headers=['user-agent']) + self.assertEqual(200, resp.status) + yield from resp.release() + + self.loop.run_until_complete(go()) + + def test_skip_default_auto_headers_user_agent(self): + @asyncio.coroutine + def handler(request): + self.assertNotIn(hdrs.USER_AGENT, request.headers) + return web.Response() + + @asyncio.coroutine + def go(): + app, srv, url = yield from self.create_server() + app.router.add_route('get', '/', handler) + + client = aiohttp.ClientSession(loop=self.loop, + skip_auto_headers=['user-agent']) + resp = yield from client.get(url+'/') + self.assertEqual(200, resp.status) + yield from resp.release() + + client.close() + + self.loop.run_until_complete(go()) diff --git a/tests/test_client_session.py b/tests/test_client_session.py index 7dbd4c70e7f..6120da9b888 100644 --- a/tests/test_client_session.py +++ b/tests/test_client_session.py @@ -9,7 +9,7 @@ import aiohttp from aiohttp.client import ClientSession -from aiohttp.multidict import MultiDict, CIMultiDict, CIMultiDictProxy, upstr +from aiohttp.multidict import MultiDict, CIMultiDict, CIMultiDictProxy from aiohttp.connector import BaseConnector, TCPConnector from aiohttp.client_reqrep import ClientRequest, ClientResponse from http.cookies import SimpleCookie @@ -375,32 +375,6 @@ def test_borrow_connector_loop(self): session = ClientSession(connector=conn) self.assertIs(session._loop, self.loop) - @mock.patch("aiohttp.client.ClientSession.request") - def test_skip_auto_headers(self, patched): - session, params = self._make_one() - skip = [upstr('user-agent')] - self.run(session.get("http://example.com", - skip_auto_headers=skip, - **params)) - params['skip_auto_headers'] = skip - self.assertTrue(patched.called, "`ClientSession.request` not called") - self.assertEqual(patched.call_args[1]['skip_auto_headers'], skip) - session.close() - - @mock.patch("aiohttp.client.ClientSession.request") - def test_skip_auto_headers_default(self, patched): - skip = ['user-agent'] - uskip = [upstr(i) for i in skip] - import ipdb;ipdb.set_trace() - session, params = self._make_one(skip_auto_headers=skip) - self.run(session.get("http://example.com", - **params)) - params['skip_auto_headers'] = skip - self.assertTrue(patched.called, "`ClientSession.request` not called") - print(patched.call_args) - self.assertEqual(patched.call_args[1]['skip_auto_headers'], uskip) - session.close() - class TestCLientRequest(unittest.TestCase): From ce4150a7bd4a8a2441eb0ef368785fb72dbac688 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Mon, 31 Aug 2015 00:22:36 -0400 Subject: [PATCH 4/9] Add skip_auto_headers check for content-type --- aiohttp/client_reqrep.py | 4 ++++ tests/test_client_functional2.py | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index cafcbac341f..0e5c7646295 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -209,6 +209,7 @@ def update_auto_headers(self, skip_auto_headers): for hdr, val in self.DEFAULT_HEADERS.items(): if hdr not in used_headers: self.headers[hdr] = val + used_headers.add(hdr) # add host if hdrs.HOST not in used_headers: @@ -217,6 +218,8 @@ def update_auto_headers(self, skip_auto_headers): if hdrs.USER_AGENT not in used_headers: self.headers[hdrs.USER_AGENT] = self.SERVER_SOFTWARE + self.skip_auto_headers = used_headers + def update_cookies(self, cookies): """Update request cookies header.""" if not cookies: @@ -463,6 +466,7 @@ def send(self, writer, reader): # set default content-type if (self.method in self.POST_METHODS and + hdrs.CONTENT_TYPE not in self.skip_auto_headers and hdrs.CONTENT_TYPE not in self.headers): self.headers[hdrs.CONTENT_TYPE] = 'application/octet-stream' diff --git a/tests/test_client_functional2.py b/tests/test_client_functional2.py index 0b65d95be02..b2c53e2cb58 100644 --- a/tests/test_client_functional2.py +++ b/tests/test_client_functional2.py @@ -96,3 +96,21 @@ def go(): client.close() self.loop.run_until_complete(go()) + + def test_skip_auto_headers_content_type(self): + @asyncio.coroutine + def handler(request): + self.assertNotIn(hdrs.CONTENT_TYPE, request.headers) + return web.Response() + + @asyncio.coroutine + def go(): + app, srv, url = yield from self.create_server() + app.router.add_route('get', '/', handler) + resp = yield from self.client.get( + url+'/', + skip_auto_headers=['content-type']) + self.assertEqual(200, resp.status) + yield from resp.release() + + self.loop.run_until_complete(go()) From 82efc7cd44a8fe8d59bc218b715837178eab3433 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 1 Sep 2015 22:55:18 -0400 Subject: [PATCH 5/9] Fix pep8 --- tests/test_client_session.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_client_session.py b/tests/test_client_session.py index 56aba46bb08..2f01d6d9076 100644 --- a/tests/test_client_session.py +++ b/tests/test_client_session.py @@ -398,6 +398,7 @@ def test_custom_req_rep(self): @asyncio.coroutine def go(): conn = None + class CustomResponse(ClientResponse): @asyncio.coroutine def start(self, connection, read_until_eof=False): From b2fa1d02b289a2464d1eee7bf28b802ea0f62799 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 1 Sep 2015 23:48:53 -0400 Subject: [PATCH 6/9] Cleanup code --- aiohttp/client_reqrep.py | 18 +++++------------- tests/test_client_request.py | 2 +- tests/test_client_session.py | 13 +++++++++++++ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index b41601b8c20..5e7a18d891e 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -19,7 +19,7 @@ from .log import client_logger from .streams import EOF_MARKER, FlowControlStreamReader from .multidict import (CIMultiDictProxy, MultiDictProxy, MultiDict, - CIMultiDict, upstr) + CIMultiDict) from .multipart import MultipartWriter from .protocol import HttpMessage @@ -57,7 +57,7 @@ class ClientRequest: # Until writer has finished finalizer will not be called. def __init__(self, method, url, *, - params=None, headers=None, skip_auto_headers=None, + params=None, headers=None, skip_auto_headers=frozenset(), data=None, cookies=None, files=None, auth=None, encoding='utf-8', version=aiohttp.HttpVersion11, compress=None, @@ -198,18 +198,12 @@ def update_headers(self, headers): self.headers.add(key, value) def update_auto_headers(self, skip_auto_headers): - used_headers = set(self.headers) - if skip_auto_headers is not None: - for i in skip_auto_headers: - if not isinstance(i, upstr): - raise ValueError( - 'skip_auto_headers should be set of upstr') - used_headers.add(i) + self.skip_auto_headers = skip_auto_headers + used_headers = set(self.headers) | skip_auto_headers for hdr, val in self.DEFAULT_HEADERS.items(): if hdr not in used_headers: - self.headers[hdr] = val - used_headers.add(hdr) + self.headers.add(hdr, val) # add host if hdrs.HOST not in used_headers: @@ -218,8 +212,6 @@ def update_auto_headers(self, skip_auto_headers): if hdrs.USER_AGENT not in used_headers: self.headers[hdrs.USER_AGENT] = self.SERVER_SOFTWARE - self.skip_auto_headers = used_headers - def update_cookies(self, cookies): """Update request cookies header.""" if not cookies: diff --git a/tests/test_client_request.py b/tests/test_client_request.py index c361a32b404..fa7469b3b6a 100644 --- a/tests/test_client_request.py +++ b/tests/test_client_request.py @@ -132,7 +132,7 @@ def test_default_headers_useragent_custom(self): def test_skip_default_useragent_header(self): req = ClientRequest('get', 'http://python.org/', loop=self.loop, - skip_auto_headers=(upstr('user-agent'),)) + skip_auto_headers=set([upstr('user-agent')])) self.assertNotIn('User-Agent', req.headers) diff --git a/tests/test_client_session.py b/tests/test_client_session.py index 2f01d6d9076..4445ebe030f 100644 --- a/tests/test_client_session.py +++ b/tests/test_client_session.py @@ -76,6 +76,19 @@ def test_init_headers_MultiDict(self): ("H3", "header3")])) session.close() + def test_init_headers_list_of_tuples_with_duplicates(self): + session = ClientSession( + headers=[("h1", "header11"), + ("h2", "header21"), + ("h1", "header12")], + loop=self.loop) + self.assertEqual( + session._default_headers, + CIMultiDict([("H1", "header11"), + ("H2", "header21"), + ("H1", "header12")])) + session.close() + def test_init_cookies_with_simple_dict(self): session = ClientSession( cookies={ From 568adcffcb049707d98464c85f89c77b69ac35a6 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 1 Sep 2015 23:52:56 -0400 Subject: [PATCH 7/9] More tests --- tests/test_client_session.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_client_session.py b/tests/test_client_session.py index 4445ebe030f..72bedeb7898 100644 --- a/tests/test_client_session.py +++ b/tests/test_client_session.py @@ -155,6 +155,22 @@ def test_merge_headers_with_list_of_tuples(self): ])) session.close() + def test_merge_headers_with_list_of_tuples_duplicated_names(self): + session = ClientSession( + headers={ + "h1": "header1", + "h2": "header2" + }, loop=self.loop) + headers = session._prepare_headers([("h1", "v1"), + ("h1", "v2")]) + self.assertIsInstance(headers, CIMultiDict) + self.assertEqual(headers, CIMultiDict([ + ("H2", "header2"), + ("H1", "v1"), + ("H1", "v2"), + ])) + session.close() + def _make_one(self, **kwargs): session = ClientSession(loop=self.loop, **kwargs) params = dict( From 3f82d25e009de5debeee92834c9488a8a9c09b4a Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 3 Sep 2015 18:06:44 -0400 Subject: [PATCH 8/9] Document skip_auto_headers parameter --- docs/client_reference.rst | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/docs/client_reference.rst b/docs/client_reference.rst index 26e3c505153..cac850ddeb3 100644 --- a/docs/client_reference.rst +++ b/docs/client_reference.rst @@ -41,7 +41,8 @@ The client session supports context manager protocol for self closing:: .. class:: ClientSession(*, connector=None, loop=None, cookies=None,\ - headers=None, auth=None, request_class=ClientRequest,\ + headers=None, skip_auto_headers=None, \ + auth=None, request_class=ClientRequest,\ response_class=ClientResponse, \ ws_response_class=ClientWebSocketResponse) @@ -61,8 +62,23 @@ The client session supports context manager protocol for self closing:: :param dict cookies: Cookies to send with the request (optional) - :param dict headers: HTTP Headers to send with - the request (optional) + :param headers: HTTP Headers to send with + the request (optional). + + May be either *iterable of key-value pairs* or + :class:`~collections.abc.Mapping` + (e.g. :class:`dict`, + :class:`~aiohttp.multidict.CIMultiDict`). + + :param skip_auto_headers: set of headers for which autogeneration + should be skipped. + + *aiohttp* autogenerates headers like ``User-Agent`` or + ``Content-Type`` if these headers are not explicitly + passed. Using ``skip_auto_headers`` parameter allows to skip + that generation. + + Iterable of :class:`str` or :class:`~aiohttp.multidict.upstr` (optional) :param aiohttp.helpers.BasicAuth auth: BasicAuth named tuple that represents HTTP Basic Authorization (optional) @@ -106,7 +122,8 @@ The client session supports context manager protocol for self closing:: .. coroutinemethod:: request(method, url, *, params=None, data=None,\ - headers=None, auth=None, allow_redirects=True,\ + headers=None, skip_auto_headers=None, \ + auth=None, allow_redirects=True,\ max_redirects=10, encoding='utf-8',\ version=HttpVersion(major=1, minor=1),\ compress=None, chunked=None, expect100=False,\ @@ -128,6 +145,17 @@ The client session supports context manager protocol for self closing:: :param dict headers: HTTP Headers to send with the request (optional) + :param skip_auto_headers: set of headers for which autogeneration + should be skipped. + + *aiohttp* autogenerates headers like ``User-Agent`` or + ``Content-Type`` if these headers are not explicitly + passed. Using ``skip_auto_headers`` parameter allows to skip + that generation. + + Iterable of :class:`str` or :class:`~aiohttp.multidict.upstr` + (optional) + :param aiohttp.helpers.BasicAuth auth: BasicAuth named tuple that represents HTTP Basic Authorization (optional) From 5c5743e2d15520a06ee014603dad2b22d4989542 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 3 Sep 2015 18:08:18 -0400 Subject: [PATCH 9/9] Update CHANGES --- CHANGES.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 9ced23a2ee0..29caca832f5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -20,3 +20,5 @@ CHANGES Using `force` parameter for the method is deprecated: use `.release()` instead. * Properly requote URL's path #480 + +* add `skip_auto_headers` parameter for client API #486