Repository: urllib3/urllib3

Issue:
Unexpected HostChangedError due to downcasing of hostname
On version 1.19

```urllib3.exceptions.HostChangedError``` is thrown when a pool is created for a host with uppercase letters, and then a request is made with url containing this hostname.
```python
from urllib3 import HTTPConnectionPool

pool = HTTPConnectionPool("Example.com")
response = pool.request('GET', "http://Example.com")
```

Gives:
```
Traceback (most recent call last):
  File "minimum.py", line 5, in <module>
    response = pool.request('GET', "http://Example.com")
  File "/usr/local/lib/python3.5/dist-packages/urllib3/request.py", line 66, in request
    **urlopen_kw)
  File "/usr/local/lib/python3.5/dist-packages/urllib3/request.py", line 87, in request_encode_url
    return self.urlopen(method, url, **extra_kw)
  File "/usr/local/lib/python3.5/dist-packages/urllib3/connectionpool.py", line 549, in urlopen
    raise HostChangedError(self, url, retries)
urllib3.exceptions.HostChangedError: HTTPConnectionPool(host='Example.com', port=None): Tried to open a foreign host with url: http://Example.com
```

Is this the expected behavior, or should a ConnectionPools host also be downcased when doing is_same_host() ?


Discussion:
Hmmm. I don't think that this is necessarily _intended_ behavior, but I don't think it's necessarily incorrect either. Can I ask why you're specifically using ConnectionPool instead of PoolManager? In general, we'd suggest using the higher-level API to avoid issues like this.

I'm not sure why I was using ConnectionPool, I will use PoolManager instead. I only noticed this in some old code after I upgraded urllib3 via pip.
As to whether this is the correct behavior, rfc952 declares that no distinction is made between upper and lower case.

So the biggest issue here is probably that we should forcibly lowercase the hostname in the base `ConnectionPool` class. I'd accept a patch that does that.

@Lukasa Is a blind `lower()` call appropriate? I thought that function was too smart for it's own good with some non-ASCII characters.

urllib3 doesn't tolerate non-ascii characters so I don't really mind how smart it is. ;)

Ah okay nevermind. :)

@SethMichaelLarson @NickMolloy are either of you planning on putting this together? If not, I've got some time to cobble this together.

@nateprewitt I can add this change with some tests tonight, should be easy enough.


Resolving patch:
diff --git a/urllib3/connectionpool.py b/urllib3/connectionpool.py
--- a/urllib3/connectionpool.py
+++ b/urllib3/connectionpool.py
@@ -73,7 +73,7 @@ def __init__(self, host, port=None):
         # Instead, we need to make sure we never pass ``None`` as the port.
         # However, for backward compatibility reasons we can't actually
         # *assert* that.
-        self.host = host.strip('[]')
+        self.host = host.strip('[]').lower()
         self.port = port
 
     def __str__(self):


Test patch:
diff --git a/test/test_connectionpool.py b/test/test_connectionpool.py
--- a/test/test_connectionpool.py
+++ b/test/test_connectionpool.py
@@ -275,6 +275,11 @@ def test_contextmanager(self):
         self.assertRaises(ClosedPoolError, pool._get_conn)
         self.assertRaises(Empty, old_pool_queue.get, block=False)
 
+    def test_mixed_case_url(self):
+        pool = HTTPConnectionPool('Example.com')
+        response = pool.request('GET', "http://Example.com")
+        self.assertEqual(response.status, 200)
+
     def test_absolute_url(self):
         c = connection_from_url('http://google.com:80')
         self.assertEqual(