From: Kousik Mitra Date: Sat, 4 Jan 2020 09:00:34 +0000 (+0530) Subject: Raise an exception in DigestAuth if non-replayable request is passed (#685) X-Git-Tag: 0.11.0~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0ed03145694b7b8a4f872b131e1407e5ae8f3008;p=thirdparty%2Fhttpx.git Raise an exception in DigestAuth if non-replayable request is passed (#685) * DigestAuth will raise exception if non-replayble request is passed #670 * Added new exception RequestBodyUnavailble exception to raise non replayable request error #670 * Changed RedirectBodyUnavailable exception to RequestBodyUnavailble to raise non-replayable exception #670 * fixed class declaration * Added RequestBodyUnavailable exception. Imported it in module level * Added RequestBodyUnavailable in the module list * Code reformat * Added Test to check if exception is raising if non-replayble request body is passed to DigestAuth #670 --- diff --git a/httpx/auth.py b/httpx/auth.py index e0ef50c3..e412c570 100644 --- a/httpx/auth.py +++ b/httpx/auth.py @@ -6,7 +6,7 @@ import typing from base64 import b64encode from urllib.request import parse_http_list -from .exceptions import ProtocolError +from .exceptions import ProtocolError, RequestBodyUnavailable from .models import Request, Response from .utils import to_bytes, to_str, unquote @@ -104,6 +104,8 @@ class DigestAuth(Auth): self.password = to_bytes(password) def __call__(self, request: Request) -> AuthFlow: + if not request.stream.can_replay(): + raise RequestBodyUnavailable("Request body is no longer available.") response = yield request if response.status_code != 401 or "www-authenticate" not in response.headers: diff --git a/tests/client/test_auth.py b/tests/client/test_auth.py index ea6ff8ac..34ec77eb 100644 --- a/tests/client/test_auth.py +++ b/tests/client/test_auth.py @@ -5,7 +5,15 @@ import typing 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 @@ async def test_auth_history() -> None: 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)