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

Switch event hooks to also run on redirects. #1806

Merged
merged 6 commits into from
Aug 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,19 @@ def raise_on_4xx_5xx(response):
client = httpx.Client(event_hooks={'response': [raise_on_4xx_5xx]})
```

!!! note
Response event hooks are called before determining if the response body
should be read or not.

If you need access to the response body inside an event hook, you'll
need to call `response.read()`.

The hooks are also allowed to modify `request` and `response` objects.

```python
def add_timestamp(request):
request.headers['x-request-timestamp'] = datetime.now(tz=datetime.utc).isoformat()

client = httpx.Client(event_hooks={'request': [add_timestamp]})
```

Expand Down
25 changes: 12 additions & 13 deletions httpx/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -886,9 +886,6 @@ def send(
if not stream:
response.read()

for hook in self._event_hooks["response"]:
hook(response)

return response

except Exception as exc:
Expand All @@ -907,9 +904,6 @@ def _send_handling_auth(
try:
request = next(auth_flow)

for hook in self._event_hooks["request"]:
hook(request)

while True:
response = self._send_handling_redirects(
request,
Expand Down Expand Up @@ -947,8 +941,13 @@ def _send_handling_redirects(
"Exceeded maximum allowed redirects.", request=request
)

for hook in self._event_hooks["request"]:
hook(request)

response = self._send_single_request(request, timeout)
try:
for hook in self._event_hooks["response"]:
hook(response)
response.history = list(history)

if not response.is_redirect:
Expand Down Expand Up @@ -1595,12 +1594,9 @@ async def send(
if not stream:
await response.aread()

for hook in self._event_hooks["response"]:
await hook(response)

return response

except Exception as exc:
except Exception as exc: # pragma: no cover
await response.aclose()
raise exc

Expand All @@ -1616,9 +1612,6 @@ async def _send_handling_auth(
try:
request = await auth_flow.__anext__()

for hook in self._event_hooks["request"]:
await hook(request)

while True:
response = await self._send_handling_redirects(
request,
Expand Down Expand Up @@ -1656,8 +1649,14 @@ async def _send_handling_redirects(
"Exceeded maximum allowed redirects.", request=request
)

for hook in self._event_hooks["request"]:
await hook(request)

response = await self._send_single_request(request, timeout)
try:
for hook in self._event_hooks["response"]:
await hook(response)

response.history = list(history)

if not response.is_redirect:
Expand Down
34 changes: 32 additions & 2 deletions tests/client/test_event_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ async def raise_on_4xx_5xx(response):

def test_event_hooks_with_redirect():
"""
A redirect request should not trigger a second 'request' event hook.
A redirect request should trigger additional 'request' and 'response' event hooks.
"""

events = []
Expand All @@ -136,6 +136,21 @@ def on_response(response):
http.get("http://127.0.0.1:8000/redirect", auth=("username", "password"))

assert events == [
{
"event": "request",
"headers": {
"host": "127.0.0.1:8000",
"user-agent": f"python-httpx/{httpx.__version__}",
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"connection": "keep-alive",
"authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
},
},
{
"event": "response",
"headers": {"location": "/", "server": "testserver"},
},
{
"event": "request",
"headers": {
Expand All @@ -157,7 +172,7 @@ def on_response(response):
@pytest.mark.usefixtures("async_environment")
async def test_async_event_hooks_with_redirect():
"""
A redirect request should not trigger a second 'request' event hook.
A redirect request should trigger additional 'request' and 'response' event hooks.
"""

events = []
Expand All @@ -176,6 +191,21 @@ async def on_response(response):
await http.get("http://127.0.0.1:8000/redirect", auth=("username", "password"))

assert events == [
{
"event": "request",
"headers": {
"host": "127.0.0.1:8000",
"user-agent": f"python-httpx/{httpx.__version__}",
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"connection": "keep-alive",
"authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
},
},
{
"event": "response",
"headers": {"location": "/", "server": "testserver"},
},
{
"event": "request",
"headers": {
Expand Down