Repository: encode/httpx

Issue:
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:852)
Hi guys by any chance any of you have seen this issue when using httpx + trio, if so how did you manage to fix it?
This is happening when starting a request to an IP on port 80 that then redirects to 443.

```
Traceback (most recent call last):
  File "/home/project/lib/python3.6/site-packages/trio/_ssl.py", line 466, in _retry
    ret = fn(*args)
  File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:852)
```

Discussion:

Patch:
diff --git a/httpx/client.py b/httpx/client.py
index a6c22d8..1ceea14 100644
--- a/httpx/client.py
+++ b/httpx/client.py
@@ -338,7 +338,8 @@ class Client:
         """
         url = self.base_url.join(relative_url=url)
         if url.scheme == "http" and hstspreload.in_hsts_preload(url.host):
-            url = url.copy_with(scheme="https")
+            port = None if url.port == 80 else url.port
+            url = url.copy_with(scheme="https", port=port)
         return url
 
     def merge_cookies(
diff --git a/httpx/models.py b/httpx/models.py
index ba19f43..ad3599b 100644
--- a/httpx/models.py
+++ b/httpx/models.py
@@ -112,6 +112,10 @@ class URL:
 
     @property
     def authority(self) -> str:
+        port_str = self._uri_reference.port
+        default_port_str = {"https": "443", "http": "80"}.get(self.scheme, "")
+        if port_str is None or port_str == default_port_str:
+            return self._uri_reference.host or ""
         return self._uri_reference.authority or ""
 
     @property
@@ -203,9 +207,9 @@ class URL:
             authority = host
             if port is not None:
                 authority += f":{port}"
-            if username is not None:
+            if username:
                 userpass = username
-                if password is not None:
+                if password:
                     userpass += f":{password}"
                 authority = f"{userpass}@{authority}"
 


Test patch:
diff --git a/tests/client/test_headers.py b/tests/client/test_headers.py
index 37a5683..168b6a0 100755
--- a/tests/client/test_headers.py
+++ b/tests/client/test_headers.py
@@ -130,7 +130,12 @@ def test_header_does_not_exist():
 
 
 @pytest.mark.asyncio
-async def test_host_without_auth_in_header():
+async def test_host_with_auth_and_port_in_url():
+    """
+    The Host header should only include the hostname, or hostname:port
+    (for non-default ports only). Any userinfo or default port should not
+    be present.
+    """
     url = "http://username:password@example.org:80/echo_headers"
 
     client = Client(dispatch=MockDispatch())
@@ -142,7 +147,31 @@ async def test_host_without_auth_in_header():
             "accept": "*/*",
             "accept-encoding": "gzip, deflate, br",
             "connection": "keep-alive",
-            "host": "example.org:80",
+            "host": "example.org",
+            "user-agent": f"python-httpx/{__version__}",
+            "authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
+        }
+    }
+
+
+@pytest.mark.asyncio
+async def test_host_with_non_default_port_in_url():
+    """
+    If the URL includes a non-default port, then it should be included in
+    the Host header.
+    """
+    url = "http://username:password@example.org:123/echo_headers"
+
+    client = Client(dispatch=MockDispatch())
+    response = await client.get(url)
+
+    assert response.status_code == 200
+    assert response.json() == {
+        "headers": {
+            "accept": "*/*",
+            "accept-encoding": "gzip, deflate, br",
+            "connection": "keep-alive",
+            "host": "example.org:123",
             "user-agent": f"python-httpx/{__version__}",
             "authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
         }
diff --git a/tests/models/test_url.py b/tests/models/test_url.py
index f6c7ab4..1415ee9 100644
--- a/tests/models/test_url.py
+++ b/tests/models/test_url.py
@@ -73,8 +73,8 @@ def test_url():
         repr(url) == "URL('https://example.org:123/path/to/somewhere?abc=123#anchor')"
     )
 
-    new = url.copy_with(scheme="http")
-    assert new == URL("http://example.org:123/path/to/somewhere?abc=123#anchor")
+    new = url.copy_with(scheme="http", port=None)
+    assert new == URL("http://example.org/path/to/somewhere?abc=123#anchor")
     assert new.scheme == "http"