From 0c45e4d070edbdb50b5b0967f56ed146b36bc5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Peter=20S=C3=B8ndergaard?= Date: Mon, 2 Nov 2015 20:34:32 +0100 Subject: [PATCH 1/5] Collect history of responses if redirects occur. --- aiohttp/client.py | 3 +++ aiohttp/client_reqrep.py | 1 + 2 files changed, 4 insertions(+) diff --git a/aiohttp/client.py b/aiohttp/client.py index 07f69de8237..5a7c95a1045 100644 --- a/aiohttp/client.py +++ b/aiohttp/client.py @@ -141,6 +141,7 @@ def _request(self, method, url, *, raise RuntimeError('Session is closed') redirects = 0 + history = [] if not isinstance(method, upstr): method = upstr(method) @@ -193,6 +194,7 @@ def _request(self, method, url, *, # redirects if resp.status in (301, 302, 303, 307) and allow_redirects: redirects += 1 + history.append(resp) if max_redirects and redirects >= max_redirects: resp.close(force=True) break @@ -221,6 +223,7 @@ def _request(self, method, url, *, break + resp.history = history return resp def ws_connect(self, url, *, diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 544f06e7513..0655ae3f34c 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -512,6 +512,7 @@ class ClientResponse: cookies = None # Response cookies (Set-Cookie) content = None # Payload stream headers = None # Response headers, CIMultiDictProxy + history = None # List of responses, if redirects occured _connection = None # current connection flow_control_class = FlowControlStreamReader # reader flow control From 3dcad36f770bd7a19707cca7d370c33b3f03f580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Peter=20S=C3=B8ndergaard?= Date: Mon, 2 Nov 2015 21:49:02 +0100 Subject: [PATCH 2/5] Updating docs. --- docs/client.rst | 16 ++++++++++++++++ docs/client_reference.rst | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/docs/client.rst b/docs/client.rst index 461df90e858..a4fb39771cd 100644 --- a/docs/client.rst +++ b/docs/client.rst @@ -527,6 +527,22 @@ If a response contains some Cookies, you can quickly access them:: ` object. +Response History +---------------- + +If a request was redirected, it is possible to view previous responses using +the history attribute:: + + >>> r = await aiohttp.get('http://example.com/some/redirect/') + >>> r + + >>> r.history + [] + +If no redirects occured or ``allow_redirects`` is set to ``False``, history will +be an empty list. + + Timeouts -------- diff --git a/docs/client_reference.rst b/docs/client_reference.rst index 7feaf4ebd97..1aa0f47042e 100644 --- a/docs/client_reference.rst +++ b/docs/client_reference.rst @@ -954,6 +954,11 @@ Response object HTTP headers of response, :class:`CIMultiDictProxy`. + .. attribute:: history + + List of :class:`ClientResponse` objects of preceding requests, if there + were redirects. + .. method:: close() Close response and underlying connection. From f874e5d16376db43c49dd88b02bc364220ea3e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Peter=20S=C3=B8ndergaard?= Date: Mon, 2 Nov 2015 22:14:19 +0100 Subject: [PATCH 3/5] Add test for redirect history attribute. --- tests/test_client_functional.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py index d4f387ea360..d4be45a1fd4 100644 --- a/tests/test_client_functional.py +++ b/tests/test_client_functional.py @@ -333,3 +333,27 @@ def handler(request): assert 200 == resp.status finally: yield from resp.release() + + +@pytest.mark.run_loop +def test_history(create_app_and_client): + @asyncio.coroutine + def handler_redirect(request): + return web.Response(status=301, headers={'Location': '/ok'}) + + @asyncio.coroutine + def handler_ok(request): + return web.Response(status=200) + + app, client = yield from create_app_and_client() + app.router.add_route('GET', '/ok', handler_ok) + app.router.add_route('GET', '/redirect', handler_redirect) + + resp = yield from client.get('/ok') + assert resp.history == [] + assert resp.status == 200 + + resp_redirect = yield from client.get('/redirect') + assert len(resp_redirect.history) == 1 + assert resp_redirect.history[0].status == 301 + assert resp_redirect.status == 200 From 84c07f90dd3a608aa622dbcffa459a7cfd05b84a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Peter=20S=C3=B8ndergaard?= Date: Mon, 2 Nov 2015 22:15:08 +0100 Subject: [PATCH 4/5] Update docs. --- docs/client_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/client_reference.rst b/docs/client_reference.rst index 1aa0f47042e..81b5747821c 100644 --- a/docs/client_reference.rst +++ b/docs/client_reference.rst @@ -956,7 +956,7 @@ Response object .. attribute:: history - List of :class:`ClientResponse` objects of preceding requests, if there + :class:`list` of :class:`ClientResponse` objects of preceding requests, if there were redirects. .. method:: close() From 4e586c898266c6a34adb02359897380fd89c7616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Peter=20S=C3=B8ndergaard?= Date: Mon, 2 Nov 2015 22:31:01 +0100 Subject: [PATCH 5/5] Update test to release responses. --- tests/test_client_functional.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py index d4be45a1fd4..88ad293785c 100644 --- a/tests/test_client_functional.py +++ b/tests/test_client_functional.py @@ -350,10 +350,16 @@ def handler_ok(request): app.router.add_route('GET', '/redirect', handler_redirect) resp = yield from client.get('/ok') - assert resp.history == [] - assert resp.status == 200 + try: + assert resp.history == [] + assert resp.status == 200 + finally: + resp.release() resp_redirect = yield from client.get('/redirect') - assert len(resp_redirect.history) == 1 - assert resp_redirect.history[0].status == 301 - assert resp_redirect.status == 200 + try: + assert len(resp_redirect.history) == 1 + assert resp_redirect.history[0].status == 301 + assert resp_redirect.status == 200 + finally: + resp_redirect.release()