Repository: elastic/elasticsearch-py

Issue:
user:password in hosts are not url decoded
Hello,

If I have a character like "]" in my username or password I must urlencode it or `urlparse` will interpret the host as IPv6. Unfortunately, `urlparse` does not urldecode fragments : 
```
The components are not broken up in smaller parts (for example, the network location is a single string), and % escapes are not expanded.
```
(https://docs.python.org/3/library/urllib.parse.html)

`_normalize_hosts` should urldecode explicitely, which I will propose in a PR.

Discussion:

Patch:
diff --git a/elasticsearch/client/__init__.py b/elasticsearch/client/__init__.py
index c735b70a..488cf8be 100644
--- a/elasticsearch/client/__init__.py
+++ b/elasticsearch/client/__init__.py
@@ -3,7 +3,7 @@ import logging
 
 from ..transport import Transport
 from ..exceptions import TransportError
-from ..compat import string_types, urlparse
+from ..compat import string_types, urlparse, unquote
 from .indices import IndicesClient
 from .ingest import IngestClient
 from .cluster import ClusterClient
@@ -49,7 +49,8 @@ def _normalize_hosts(hosts):
                 h['scheme'] = parsed_url.scheme
 
             if parsed_url.username or parsed_url.password:
-                h['http_auth'] = '%s:%s' % (parsed_url.username, parsed_url.password)
+                h['http_auth'] = '%s:%s' % (unquote(parsed_url.username),
+                                            unquote(parsed_url.password))
 
             if parsed_url.path and parsed_url.path != '/':
                 h['url_prefix'] = parsed_url.path
diff --git a/elasticsearch/compat.py b/elasticsearch/compat.py
index deee3c52..a5b615d2 100644
--- a/elasticsearch/compat.py
+++ b/elasticsearch/compat.py
@@ -4,10 +4,10 @@ PY2 = sys.version_info[0] == 2
 
 if PY2:
     string_types = basestring,
-    from urllib import quote_plus, urlencode
+    from urllib import quote_plus, urlencode, unquote
     from urlparse import  urlparse
     from itertools import imap as map
 else:
     string_types = str, bytes
-    from urllib.parse import quote_plus, urlencode, urlparse
+    from urllib.parse import quote_plus, urlencode, urlparse, unquote
     map = map


Test patch:
diff --git a/test_elasticsearch/test_client/__init__.py b/test_elasticsearch/test_client/__init__.py
index 4bf2978c..ec01145e 100644
--- a/test_elasticsearch/test_client/__init__.py
+++ b/test_elasticsearch/test_client/__init__.py
@@ -13,8 +13,8 @@ class TestNormalizeHosts(TestCase):
 
     def test_strings_are_parsed_for_port_and_user(self):
         self.assertEquals(
-            [{"host": "elastic.co", "port": 42}, {"host": "elastic.co", "http_auth": "user:secret"}],
-            _normalize_hosts(["elastic.co:42", "user:secret@elastic.co"])
+            [{"host": "elastic.co", "port": 42}, {"host": "elastic.co", "http_auth": "user:secre]"}],
+            _normalize_hosts(["elastic.co:42", "user:secre%5D@elastic.co"])
         )
 
     def test_strings_are_parsed_for_scheme(self):