Repository: encode/httpx

Issue:
Erroneous Infinite Redirect Loop detected
Our redirect loop detection or redirects in general is broken somehow because this shouldn't error out:

```python
from httpx import Client

client = Client()
r = client.request("GET", "https://www.howsmyssl.com/a/check")  # Completes successfully

r = client.request("GET", "https://howsmyssl.com/a/check")  # Sends a redirect to 'www.howsmyssl.com' but then errors?
```

Discussion:

Patch:
diff --git a/httpx/__init__.py b/httpx/__init__.py
index fd17441..39b44aa 100644
--- a/httpx/__init__.py
+++ b/httpx/__init__.py
@@ -32,10 +32,10 @@ from .exceptions import (
 )
 from .interfaces import (
     AsyncDispatcher,
-    BaseReader,
-    BaseWriter,
     BaseBackgroundManager,
     BasePoolSemaphore,
+    BaseReader,
+    BaseWriter,
     ConcurrencyBackend,
     Dispatcher,
     Protocol,
diff --git a/httpx/client.py b/httpx/client.py
index e22d1a9..6b49797 100644
--- a/httpx/client.py
+++ b/httpx/client.py
@@ -20,11 +20,11 @@ from .dispatch.connection_pool import ConnectionPool
 from .dispatch.threaded import ThreadedDispatcher
 from .dispatch.wsgi import WSGIDispatch
 from .exceptions import (
+    HTTPError,
     InvalidURL,
     RedirectBodyUnavailable,
     RedirectLoop,
     TooManyRedirects,
-    HTTPError,
 )
 from .interfaces import AsyncDispatcher, ConcurrencyBackend, Dispatcher
 from .models import (
@@ -312,6 +312,7 @@ class BaseClient:
         headers = Headers(request.headers)
         if url.origin != request.url.origin:
             del headers["Authorization"]
+            del headers["host"]
         return headers
 
     def redirect_content(
diff --git a/httpx/exceptions.py b/httpx/exceptions.py
index 21dc7f4..ddccbf8 100644
--- a/httpx/exceptions.py
+++ b/httpx/exceptions.py
@@ -9,7 +9,9 @@ class HTTPError(Exception):
     Base class for Httpx exception
     """
 
-    def __init__(self, request: 'BaseRequest' = None, response: 'BaseResponse' = None, *args) -> None:
+    def __init__(
+        self, request: "BaseRequest" = None, response: "BaseResponse" = None, *args
+    ) -> None:
         self.response = response
         self.request = request or getattr(self.response, "request", None)
         super().__init__(*args)
diff --git a/httpx/models.py b/httpx/models.py
index e7e7a57..f397e78 100644
--- a/httpx/models.py
+++ b/httpx/models.py
@@ -33,7 +33,7 @@ from .utils import (
     is_known_encoding,
     normalize_header_key,
     normalize_header_value,
-    str_query_param
+    str_query_param,
 )
 
 PrimitiveData = typing.Union[str, int, float, bool, type(None)]


Test patch:
diff --git a/tests/client/test_headers.py b/tests/client/test_headers.py
index bf82a57..2d17c12 100755
--- a/tests/client/test_headers.py
+++ b/tests/client/test_headers.py
@@ -1,15 +1,16 @@
 #!/usr/bin/env python3
 
 import json
+
 from httpx import (
-    __version__,
-    Client,
+    AsyncDispatcher,
     AsyncRequest,
     AsyncResponse,
-    VerifyTypes,
     CertTypes,
+    Client,
     TimeoutTypes,
-    AsyncDispatcher,
+    VerifyTypes,
+    __version__,
 )
 
 
diff --git a/tests/client/test_redirects.py b/tests/client/test_redirects.py
index ff75475..f9c2075 100644
--- a/tests/client/test_redirects.py
+++ b/tests/client/test_redirects.py
@@ -86,6 +86,17 @@ class MockDispatch(AsyncDispatcher):
             body = json.dumps({"body": content.decode()}).encode()
             return AsyncResponse(codes.OK, content=body, request=request)
 
+        elif request.url.path == "/cross_subdomain":
+            if request.headers["host"] != "www.example.org":
+                headers = {"location": "https://www.example.org/cross_subdomain"}
+                return AsyncResponse(
+                    codes.PERMANENT_REDIRECT, headers=headers, request=request
+                )
+            else:
+                return AsyncResponse(
+                    codes.OK, content=b"Hello, world!", request=request
+                )
+
         return AsyncResponse(codes.OK, content=b"Hello, world!", request=request)
 
 
@@ -250,3 +261,11 @@ async def test_cannot_redirect_streaming_body():
 
     with pytest.raises(RedirectBodyUnavailable):
         await client.post(url, data=streaming_body())
+
+
+@pytest.mark.asyncio
+async def test_cross_dubdomain_redirect():
+    client = AsyncClient(dispatch=MockDispatch())
+    url = "https://example.com/cross_subdomain"
+    response = await client.get(url)
+    assert response.url == URL("https://www.example.org/cross_subdomain")