Skip to content
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

fix HTTP proxying #1415

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,11 @@ def send(self, writer, reader):
path = self.url.raw_path
if self.url.raw_query_string:
path += '?' + self.url.raw_query_string
if self.proxy:
# path attribute is set by:
# aiohttp.connector._create_proxy_connection and its meaning
# is different. It is actual request.url requested via proxy.
path = self.path
request = aiohttp.Request(writer, self.method, path,
self.version)

Expand Down
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ ipdb==0.10.1
pytest-sugar==0.7.1
ipython==5.1.0
aiodns==1.1.1
mitmproxy==0.18.2
51 changes: 51 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import collections
import logging
import pathlib
import signal
import socket
import sys
import time
from subprocess import Popen

import pytest

Expand Down Expand Up @@ -82,3 +87,49 @@ def pytest_ignore_collect(path, config):
if 'test_py35' in str(path):
if sys.version_info < (3, 5, 0):
return True


def get_ephemeral_port():
s = socket.socket()
s.bind(("", 0))
return s.getsockname()[1]


def _wait_for_port(portnum, delay=0.1, attempts=100):
while attempts > 0:
s = socket.socket()
if s.connect_ex(('127.0.0.1', portnum)) == 0:
s.close()
return
time.sleep(delay)
attempts -= 1
raise RuntimeError("Port %d is not open" % portnum)


class FakeProxyProcess(object):
def __init__(self):
self.port = get_ephemeral_port()
script_file = pathlib.Path(__file__).parent / 'mitmdump_script.py'
self.args = ['mitmdump', '-p', str(self.port), '-s',
str(script_file), '--no-http2']

def __enter__(self):
self.proc = Popen(self.args)
self.proc.poll()
_wait_for_port(self.port)
return self

def __exit__(self, *args):
if self.proc is not None:
self.proc.send_signal(signal.SIGINT)
self.proc.wait()
self.proc = None

def url(self):
return "http://localhost:{}/".format(self.port)


@pytest.yield_fixture
def fake_proxy():
with FakeProxyProcess() as fake_proxy:
yield fake_proxy
2 changes: 2 additions & 0 deletions tests/mitmdump_script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def response(flow):
flow.response.headers["X-Mitmdump"] = "1"
27 changes: 27 additions & 0 deletions tests/test_proxy_functional.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import asyncio
import os
from asyncio.compat import PY35

import pytest

from aiohttp import web


# TODO fix me check what's going on with this test on Windows?
@pytest.mark.skipif(not PY35 or os.name == 'nt',
reason='mitmdump does not support python 3.4')
@asyncio.coroutine
def test_proxy_via_mitmdump(loop, test_client, fake_proxy):
@asyncio.coroutine
def handler(request):
return web.Response(text=request.method)

app = web.Application(loop=loop)
app.router.add_get('/', handler)

client = yield from test_client(app)
resp = yield from client.get('/', proxy=fake_proxy.url())
assert 200 == resp.status
assert 'X-Mitmdump' in resp.headers
assert resp.headers['X-Mitmdump'] == '1'
resp.close()