fix: keep multi-step auth responses under the response body cap - #153
Merged
Merged
Conversation
httpx2 reads every intermediate auth-flow response (a DigestAuth challenge, a token-refresh call) without a limit. With a cap set, httpware now drives the auth flow itself around its redirect loop.
Also cover stream() with auth flows and share the capped read-and-close step between the terminal and the auth loop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
httpx2's
_send_handling_authreads every intermediate auth-flow response with an unboundedresponse.read(). Anyauth=that takes more than one step therefore bypassedmax_response_body_bytes, with or without redirects: the 401 challenge ofhttpx2.DigestAuth, and custom flows such as a token refresh that retries after calling a token endpoint.auth=has been forwarded since 0.18, so a server could make a capped client buffer an arbitrarily large challenge body.How
With a cap set, httpware now drives the auth flow itself (
auth.async_auth_flow/sync_auth_flow, public API), wrapped around the redirect loop from #152, the same nesting httpx2 uses.httpx2.Auth(), so httpx2 never applies auth on its own. Which auth runs is decided like httpx2 does:client.auth, else Basic from URL credentials, else none (_request_auth, a public-API copy of the private_build_request_auth).history. An auth withrequires_response_body = Truegets each response buffered under the cap instead, so an oversized token response raisesResponseTooLargeError.max_redirects(checked before every send), nested.historyof each hop, history order across auth steps, and the error raised for a malformed Digest challenge.Side effects
DigestAuthnow answers a challenge that arrives after a redirect under a cap. In 0.20.0 it could not (noted in that release).Locationare no longer applied on the capped path, matching httpx2 (0.20.0 sent hops withauth=None, which applied them).stream()with arequires_response_bodyauth yields a body already read under the cap. httpx2 reads that body anyway;docs/errors.mdnow says so._read_capped_and_close[_async]is shared by_terminaland the auth loop.Tests
tests/test_client_body_cap_auth.py, sync and async mirrored: Digest challenge body read only without a cap (verbs andstream()), token refresh under and over the cap (verbs andstream()), URL credentials with and without a cap, Digest after a redirect with identical nested history with and without a cap, auth steps counting towardmax_redirects, and a malformed challenge raising the sameTransportError. The Digest and stream tests fail againstmain.Verification
just lint-ci,just test-ci(1001 passed, 100% coverage),just docs-build,just adr-check.