URLPattern,
get_environment_proxies,
get_logger,
+ is_https_redirect,
same_origin,
)
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")
)
+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"""
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"
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.
get_ca_bundle_from_env,
get_environment_proxies,
guess_json_utf,
+ is_https_redirect,
obfuscate_sensitive_headers,
parse_header_links,
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"],
[