* Preserve Authorization header on HTTPS redirect (#1850) * Update httpx/_client.py Co-authored-by: Tom Christie <tom@tomchristie.com>
This commit is contained in:
parent
4f8068a7ad
commit
4401d55ecf
@ -51,6 +51,7 @@ from ._utils import (
|
||||
URLPattern,
|
||||
get_environment_proxies,
|
||||
get_logger,
|
||||
is_https_redirect,
|
||||
same_origin,
|
||||
)
|
||||
|
||||
@ -532,9 +533,10 @@ class BaseClient:
|
||||
headers = Headers(request.headers)
|
||||
|
||||
if not same_origin(url, request.url):
|
||||
# Strip Authorization headers when responses are redirected away from
|
||||
# the origin.
|
||||
headers.pop("Authorization", None)
|
||||
if not is_https_redirect(request.url, url):
|
||||
# Strip Authorization headers when responses are redirected
|
||||
# away from the origin. (Except for direct HTTP to HTTPS redirects.)
|
||||
headers.pop("Authorization", None)
|
||||
|
||||
# Update the Host header.
|
||||
headers["Host"] = url.netloc.decode("ascii")
|
||||
|
||||
@ -282,6 +282,21 @@ def same_origin(url: "URL", other: "URL") -> bool:
|
||||
)
|
||||
|
||||
|
||||
def is_https_redirect(url: "URL", location: "URL") -> bool:
|
||||
"""
|
||||
Return 'True' if 'location' is a HTTPS upgrade of 'url'
|
||||
"""
|
||||
if url.host != location.host:
|
||||
return False
|
||||
|
||||
return (
|
||||
url.scheme == "http"
|
||||
and port_or_default(url) == 80
|
||||
and location.scheme == "https"
|
||||
and port_or_default(location) == 443
|
||||
)
|
||||
|
||||
|
||||
def get_environment_proxies() -> typing.Dict[str, typing.Optional[str]]:
|
||||
"""Gets proxy information from the environment"""
|
||||
|
||||
|
||||
@ -270,6 +270,15 @@ def test_cross_domain_redirect_with_auth_header():
|
||||
assert "authorization" not in response.json()["headers"]
|
||||
|
||||
|
||||
def test_cross_domain_https_redirect_with_auth_header():
|
||||
client = httpx.Client(transport=httpx.MockTransport(redirects))
|
||||
url = "http://example.com/cross_domain"
|
||||
headers = {"Authorization": "abc"}
|
||||
response = client.get(url, headers=headers, follow_redirects=True)
|
||||
assert response.url == "https://example.org/cross_domain_target"
|
||||
assert "authorization" not in response.json()["headers"]
|
||||
|
||||
|
||||
def test_cross_domain_redirect_with_auth():
|
||||
client = httpx.Client(transport=httpx.MockTransport(redirects))
|
||||
url = "https://example.com/cross_domain"
|
||||
@ -287,6 +296,15 @@ def test_same_domain_redirect():
|
||||
assert response.json()["headers"]["authorization"] == "abc"
|
||||
|
||||
|
||||
def test_same_domain_https_redirect_with_auth_header():
|
||||
client = httpx.Client(transport=httpx.MockTransport(redirects))
|
||||
url = "http://example.org/cross_domain"
|
||||
headers = {"Authorization": "abc"}
|
||||
response = client.get(url, headers=headers, follow_redirects=True)
|
||||
assert response.url == "https://example.org/cross_domain_target"
|
||||
assert response.json()["headers"]["authorization"] == "abc"
|
||||
|
||||
|
||||
def test_body_redirect():
|
||||
"""
|
||||
A 308 redirect should preserve the request body.
|
||||
|
||||
@ -10,6 +10,7 @@ from httpx._utils import (
|
||||
get_ca_bundle_from_env,
|
||||
get_environment_proxies,
|
||||
guess_json_utf,
|
||||
is_https_redirect,
|
||||
obfuscate_sensitive_headers,
|
||||
parse_header_links,
|
||||
same_origin,
|
||||
@ -221,6 +222,24 @@ def test_not_same_origin():
|
||||
assert not same_origin(origin1, origin2)
|
||||
|
||||
|
||||
def test_is_https_redirect():
|
||||
url = httpx.URL("http://example.com")
|
||||
location = httpx.URL("https://example.com")
|
||||
assert is_https_redirect(url, location)
|
||||
|
||||
|
||||
def test_is_not_https_redirect():
|
||||
url = httpx.URL("http://example.com")
|
||||
location = httpx.URL("https://www.example.com")
|
||||
assert not is_https_redirect(url, location)
|
||||
|
||||
|
||||
def test_is_not_https_redirect_if_not_default_ports():
|
||||
url = httpx.URL("http://example.com:9999")
|
||||
location = httpx.URL("https://example.com:1337")
|
||||
assert not is_https_redirect(url, location)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["pattern", "url", "expected"],
|
||||
[
|
||||
|
||||
Loading…
Reference in New Issue
Block a user