From 24d9cf0fc88b6d616e0c62fd001d099357a73735 Mon Sep 17 00:00:00 2001 From: kousik Date: Wed, 25 Dec 2019 17:02:36 +0530 Subject: [PATCH 1/8] DigestAuth will raise exception if non-replayble request is passed #670 --- httpx/auth.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/httpx/auth.py b/httpx/auth.py index e0ef50c3a0..27720be14b 100644 --- a/httpx/auth.py +++ b/httpx/auth.py @@ -6,7 +6,7 @@ from base64 import b64encode from urllib.request import parse_http_list -from .exceptions import ProtocolError +from .exceptions import ProtocolError, RedirectBodyUnavailable from .models import Request, Response from .utils import to_bytes, to_str, unquote @@ -104,6 +104,8 @@ def __init__( self.password = to_bytes(password) def __call__(self, request: Request) -> AuthFlow: + if not request.stream.can_replay(): + raise RedirectBodyUnavailable("Non-replayable request is passed") response = yield request if response.status_code != 401 or "www-authenticate" not in response.headers: From 21a943f13c2e8045abf5980ce5e7b48a6596f681 Mon Sep 17 00:00:00 2001 From: kousik Date: Thu, 26 Dec 2019 14:02:45 +0530 Subject: [PATCH 2/8] Added new exception RequestBodyUnavailble exception to raise non replayable request error #670 --- httpx/exceptions.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/httpx/exceptions.py b/httpx/exceptions.py index 2d8d27dc4c..56fd048f62 100644 --- a/httpx/exceptions.py +++ b/httpx/exceptions.py @@ -92,6 +92,11 @@ class RedirectBodyUnavailable(RedirectError): no longer available. """ +class RequestBodyUnavailable(RedirectBodyUnavailable): + """ + Got a request body, but the request body is no longer available. + """ + class RedirectLoop(RedirectError): """ From 97222cb485bc9f9540db8544fb74fb91280c6cd7 Mon Sep 17 00:00:00 2001 From: kousik Date: Thu, 26 Dec 2019 14:03:07 +0530 Subject: [PATCH 3/8] Changed RedirectBodyUnavailable exception to RequestBodyUnavailble to raise non-replayable exception #670 --- httpx/auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpx/auth.py b/httpx/auth.py index 27720be14b..e412c5707f 100644 --- a/httpx/auth.py +++ b/httpx/auth.py @@ -6,7 +6,7 @@ from base64 import b64encode from urllib.request import parse_http_list -from .exceptions import ProtocolError, RedirectBodyUnavailable +from .exceptions import ProtocolError, RequestBodyUnavailable from .models import Request, Response from .utils import to_bytes, to_str, unquote @@ -105,7 +105,7 @@ def __init__( def __call__(self, request: Request) -> AuthFlow: if not request.stream.can_replay(): - raise RedirectBodyUnavailable("Non-replayable request is passed") + raise RequestBodyUnavailable("Request body is no longer available.") response = yield request if response.status_code != 401 or "www-authenticate" not in response.headers: From caabe532c1271cb1f17c05ae01266bd3fea425ba Mon Sep 17 00:00:00 2001 From: kousik Date: Thu, 26 Dec 2019 14:17:16 +0530 Subject: [PATCH 4/8] fixed class declaration --- httpx/exceptions.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/httpx/exceptions.py b/httpx/exceptions.py index 56fd048f62..2d8d27dc4c 100644 --- a/httpx/exceptions.py +++ b/httpx/exceptions.py @@ -92,11 +92,6 @@ class RedirectBodyUnavailable(RedirectError): no longer available. """ -class RequestBodyUnavailable(RedirectBodyUnavailable): - """ - Got a request body, but the request body is no longer available. - """ - class RedirectLoop(RedirectError): """ From 971fc03dcbe7af149b33844e60952f42ed4a49e7 Mon Sep 17 00:00:00 2001 From: kousik Date: Thu, 26 Dec 2019 14:22:31 +0530 Subject: [PATCH 5/8] Added RequestBodyUnavailable exception. Imported it in module level --- httpx/__init__.py | 1 + httpx/exceptions.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/httpx/__init__.py b/httpx/__init__.py index ce92f88593..7bf4e41988 100644 --- a/httpx/__init__.py +++ b/httpx/__init__.py @@ -18,6 +18,7 @@ ProxyError, ReadTimeout, RedirectBodyUnavailable, + RequestBodyUnavailable, RedirectLoop, ResponseClosed, ResponseNotRead, diff --git a/httpx/exceptions.py b/httpx/exceptions.py index 2d8d27dc4c..56fd048f62 100644 --- a/httpx/exceptions.py +++ b/httpx/exceptions.py @@ -92,6 +92,11 @@ class RedirectBodyUnavailable(RedirectError): no longer available. """ +class RequestBodyUnavailable(RedirectBodyUnavailable): + """ + Got a request body, but the request body is no longer available. + """ + class RedirectLoop(RedirectError): """ From 89bb482c18a93dd92aba25679f38d43b0e10a754 Mon Sep 17 00:00:00 2001 From: kousik Date: Thu, 26 Dec 2019 14:26:43 +0530 Subject: [PATCH 6/8] Added RequestBodyUnavailable in the module list --- httpx/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/httpx/__init__.py b/httpx/__init__.py index 7bf4e41988..670f8a2fb9 100644 --- a/httpx/__init__.py +++ b/httpx/__init__.py @@ -64,6 +64,7 @@ "ProtocolError", "ReadTimeout", "RedirectBodyUnavailable", + "RequestBodyUnavailable", "RedirectLoop", "ResponseClosed", "ResponseNotRead", From 11a3fbef98d0772fc591c66b8deb2341c6034de1 Mon Sep 17 00:00:00 2001 From: kousik Date: Thu, 26 Dec 2019 15:08:12 +0530 Subject: [PATCH 7/8] Code reformat --- httpx/__init__.py | 2 +- httpx/exceptions.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/httpx/__init__.py b/httpx/__init__.py index 670f8a2fb9..405c3af7af 100644 --- a/httpx/__init__.py +++ b/httpx/__init__.py @@ -18,8 +18,8 @@ ProxyError, ReadTimeout, RedirectBodyUnavailable, - RequestBodyUnavailable, RedirectLoop, + RequestBodyUnavailable, ResponseClosed, ResponseNotRead, StreamConsumed, diff --git a/httpx/exceptions.py b/httpx/exceptions.py index 56fd048f62..e9d636a2e5 100644 --- a/httpx/exceptions.py +++ b/httpx/exceptions.py @@ -92,6 +92,7 @@ class RedirectBodyUnavailable(RedirectError): no longer available. """ + class RequestBodyUnavailable(RedirectBodyUnavailable): """ Got a request body, but the request body is no longer available. From 6d26a0825f4929bb832e6530cd82e0a59d7f24fe Mon Sep 17 00:00:00 2001 From: kousik Date: Sat, 4 Jan 2020 14:15:32 +0530 Subject: [PATCH 8/8] Added Test to check if exception is raising if non-replayble request body is passed to DigestAuth #670 --- tests/client/test_auth.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/client/test_auth.py b/tests/client/test_auth.py index ea6ff8acac..34ec77eb4b 100644 --- a/tests/client/test_auth.py +++ b/tests/client/test_auth.py @@ -5,7 +5,15 @@ import pytest -from httpx import URL, AsyncClient, DigestAuth, ProtocolError, Request, Response +from httpx import ( + URL, + AsyncClient, + DigestAuth, + ProtocolError, + Request, + RequestBodyUnavailable, + Response, +) from httpx.auth import Auth, AuthFlow from httpx.config import CertTypes, TimeoutTypes, VerifyTypes from httpx.dispatch.base import Dispatcher @@ -442,3 +450,16 @@ def __call__(self, request: Request) -> AuthFlow: assert resp2.history == [resp1] assert len(resp1.history) == 0 + + +@pytest.mark.asyncio +async def test_digest_auth_unavailable_streaming_body(): + url = "https://example.org/" + auth = DigestAuth(username="tomchristie", password="password123") + client = AsyncClient(dispatch=MockDispatch()) + + async def streaming_body(): + yield b"Example request body" + + with pytest.raises(RequestBodyUnavailable): + await client.post(url, data=streaming_body(), auth=auth)