Skip to content

Commit

Permalink
Merge pull request #1421 from dodge-ksv/proxy_fix
Browse files Browse the repository at this point in the history
Proxy fix
  • Loading branch information
asvetlov authored Nov 24, 2016
2 parents 49c71c3 + 6cf2caa commit deb0ec8
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 16 deletions.
4 changes: 2 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ CHANGES
- Call worker_int and worker_abort callbacks in
`Gunicorn[UVLoop]WebWorker` #1202

-
- Has functional tests for client proxy #1218

-
- Fix bugs with client proxy target path and proxy host with port #1413

-

Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ Sebastian Hüther
SeongSoo Cho
Sergey Ninua
Sergey Skripnick
Serhii Kostel
Simon Kennedy
Sin-Woo Bang
Stanislas Plum
Expand Down
16 changes: 13 additions & 3 deletions aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,9 +432,19 @@ def write_bytes(self, request, reader):
self._writer = None

def send(self, writer, reader):
path = self.url.raw_path
if self.url.raw_query_string:
path += '?' + self.url.raw_query_string
# Specify request target:
# - CONNECT request must send authority form URI
# - not CONNECT proxy must send absolute form URI
# - most common is origin form URI
if self.method == hdrs.METH_CONNECT:
path = '{}:{}'.format(self.url.host, self.url.port)
elif self.proxy and not self.ssl:
path = str(self.url)
else:
path = self.url.raw_path
if self.url.raw_query_string:
path += '?' + self.url.raw_query_string

request = aiohttp.Request(writer, self.method, path,
self.version)

Expand Down
6 changes: 2 additions & 4 deletions aiohttp/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ def _create_direct_connection(self, req):
def _create_proxy_connection(self, req):
proxy_req = ClientRequest(
hdrs.METH_GET, req.proxy,
headers={hdrs.HOST: req.host},
headers={hdrs.HOST: req.headers[hdrs.HOST]},
auth=req.proxy_auth,
loop=self._loop)
try:
Expand All @@ -644,8 +644,6 @@ def _create_proxy_connection(self, req):
except OSError as exc:
raise ProxyConnectionError(*exc.args) from exc

if not req.ssl:
req.path = str(req.url)
if hdrs.AUTHORIZATION in proxy_req.headers:
auth = proxy_req.headers[hdrs.AUTHORIZATION]
del proxy_req.headers[hdrs.AUTHORIZATION]
Expand All @@ -665,7 +663,7 @@ def _create_proxy_connection(self, req):
# to do this we must wrap raw socket into secure one
# asyncio handles this perfectly
proxy_req.method = hdrs.METH_CONNECT
proxy_req.path = '{}:{}'.format(req.host, req.port)
proxy_req.url = req.url
key = (req.host, req.port, req.ssl)
conn = Connection(self, key, proxy_req,
transport, proto, self._loop)
Expand Down
14 changes: 7 additions & 7 deletions tests/test_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_connect(self, ClientRequestMock):
tr, proto = mock.Mock(), mock.Mock()
self.loop.create_connection = make_mocked_coro((tr, proto))
conn = self.loop.run_until_complete(connector.connect(req))
self.assertEqual(req.path, 'http://www.python.org')
self.assertEqual(req.url, URL('http://www.python.org'))
self.assertIs(conn._transport, tr)
self.assertIs(conn._protocol, proto)

Expand Down Expand Up @@ -105,7 +105,7 @@ def test_auth(self, ClientRequestMock):
self.assertNotIn('PROXY-AUTHORIZATION', req.headers)
conn = self.loop.run_until_complete(connector.connect(req))

self.assertEqual(req.path, 'http://www.python.org')
self.assertEqual(req.url, URL('http://www.python.org'))
self.assertNotIn('AUTHORIZATION', req.headers)
self.assertIn('PROXY-AUTHORIZATION', req.headers)
self.assertNotIn('AUTHORIZATION', proxy_req.headers)
Expand Down Expand Up @@ -148,7 +148,7 @@ def test_auth_from_url(self, ClientRequestMock):
self.assertNotIn('PROXY-AUTHORIZATION', req.headers)
conn = self.loop.run_until_complete(connector.connect(req))

self.assertEqual(req.path, 'http://www.python.org')
self.assertEqual(req.url, URL('http://www.python.org'))
self.assertNotIn('AUTHORIZATION', req.headers)
self.assertIn('PROXY-AUTHORIZATION', req.headers)
self.assertNotIn('AUTHORIZATION', proxy_req.headers)
Expand Down Expand Up @@ -212,7 +212,7 @@ def test_https_connect(self, ClientRequestMock):

self.assertEqual(req.url.path, '/')
self.assertEqual(proxy_req.method, 'CONNECT')
self.assertEqual(proxy_req.path, 'www.python.org:443')
self.assertEqual(proxy_req.url, URL('https://www.python.org'))
tr.pause_reading.assert_called_once_with()
tr.get_extra_info.assert_called_with('socket', default=None)

Expand Down Expand Up @@ -341,7 +341,7 @@ def test_request_port(self, ClientRequestMock):
loop=self.loop,
)
self.loop.run_until_complete(connector._create_connection(req))
self.assertEqual(req.path, 'http://localhost:1234/path')
self.assertEqual(req.url, URL('http://localhost:1234/path'))

def test_proxy_auth_property(self):
req = aiohttp.ClientRequest(
Expand Down Expand Up @@ -393,7 +393,7 @@ def test_https_connect_pass_ssl_context(self, ClientRequestMock):

self.assertEqual(req.url.path, '/')
self.assertEqual(proxy_req.method, 'CONNECT')
self.assertEqual(proxy_req.path, 'www.python.org:443')
self.assertEqual(proxy_req.url, URL('https://www.python.org'))
tr.pause_reading.assert_called_once_with()
tr.get_extra_info.assert_called_with('socket', default=None)

Expand Down Expand Up @@ -494,7 +494,7 @@ def test_connect(self, ClientRequestMock):
tr, proto = mock.Mock(), mock.Mock()
self.loop.create_connection = make_mocked_coro((tr, proto))
conn = self.loop.run_until_complete(connector.connect(req))
self.assertEqual(req.path, 'http://www.python.org')
self.assertEqual(req.url, URL('http://www.python.org'))
self.assertIs(conn._transport, tr)
self.assertIs(conn._protocol, proto)

Expand Down
Loading

0 comments on commit deb0ec8

Please sign in to comment.