Repository: encode/httpx

Issue:
urllib3.ProxyManager() instantiation is broken.
python 3.7.5
httpx 0.11.0
urllib3 1.25.7

```
$ ipython3 -c 'import httpx; r = httpx.get("https://www.google.com")'
parse_url http://127.0.0.1:1234 <class 'httpx.models.URL'>
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-1-d6fe3101235f> in <module>
----> 1 import httpx; r = httpx.get("https://www.google.com")

/usr/local/lib/python3.7/site-packages/httpx/api.py in get(url, params, headers, cookies, auth, allow_redirects, cert, verify, timeout, trust_env)
    168         verify=verify,
    169         timeout=timeout,
--> 170         trust_env=trust_env,
    171     )
    172

/usr/local/lib/python3.7/site-packages/httpx/api.py in request(method, url, params, data, files, json, headers, cookies, auth, timeout, allow_redirects, verify, cert, trust_env)
     82     """
     83     with Client(
---> 84         cert=cert, verify=verify, timeout=timeout, trust_env=trust_env,
     85     ) as client:
     86         return client.request(

/usr/local/lib/python3.7/site-packages/httpx/client.py in __init__(self, auth, params, headers, cookies, verify, cert, proxies, timeout, pool_limits, max_redirects, base_url, dispatch, app, trust_env)
    477                 trust_env=trust_env,
    478             )
--> 479             for key, proxy in proxy_map.items()
    480         }
    481

/usr/local/lib/python3.7/site-packages/httpx/client.py in <dictcomp>(.0)
    477                 trust_env=trust_env,
    478             )
--> 479             for key, proxy in proxy_map.items()
    480         }
    481

/usr/local/lib/python3.7/site-packages/httpx/client.py in init_proxy_dispatch(self, proxy, verify, cert, pool_limits, trust_env)
    512             cert=cert,
    513             pool_limits=pool_limits,
--> 514             trust_env=trust_env,
    515         )
    516

/usr/local/lib/python3.7/site-packages/httpx/dispatch/urllib3.py in __init__(self, proxy, verify, cert, trust_env, pool_limits)
     58             num_pools=num_pools,
     59             maxsize=maxsize,
---> 60             block=block,
     61         )
     62

/usr/local/lib/python3.7/site-packages/httpx/dispatch/urllib3.py in init_pool_manager(self, proxy, ssl_context, num_pools, maxsize, block)
     83                 num_pools=num_pools,
     84                 maxsize=maxsize,
---> 85                 block=block,
     86             )
     87

/usr/local/lib/python3.7/site-packages/urllib3/poolmanager.py in __init__(self, proxy_url, num_pools, headers, proxy_headers, **connection_pool_kw)
    412                 proxy_url.port,
    413             )
--> 414         proxy = parse_url(proxy_url)
    415         if not proxy.port:
    416             port = port_by_scheme.get(proxy.scheme, 80)

/usr/local/lib/python3.7/site-packages/urllib3/util/url.py in parse_url(url)
    361     print('parse_url', url, type(url))
    362     source_url = url
--> 363     if not SCHEME_RE.search(url):
    364         url = "//" + url
    365

TypeError: expected string or bytes-like object
```

Discussion:

Patch:
diff --git a/README.md b/README.md
index cf6b9b3..27fd542 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,18 @@ Let's get started...
 '<!doctype html>\n<html>\n<head>\n<title>Example Domain</title>...'
 ```
 
+Or, using the async API...
+
+_Use [IPython](https://ipython.readthedocs.io/en/stable/) or Python 3.8+ with `python -m asyncio` to try this code interactively._
+
+```python
+>>> import httpx
+>>> async with httpx.AsyncClient() as client:
+>>>     r = await client.get('https://www.example.org/')
+>>> r
+<Response [200 OK]>
+```
+
 ## Features
 
 HTTPX builds on the well-established usability of `requests`, and gives you:
diff --git a/docs/index.md b/docs/index.md
index e3d6e2a..476f62a 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -51,6 +51,18 @@ Let's get started...
 '<!doctype html>\n<html>\n<head>\n<title>Example Domain</title>...'
 ```
 
+Or, using the async API...
+
+_Use [IPython](https://ipython.readthedocs.io/en/stable/) or Python 3.8+ with `python -m asyncio` to try this code interactively._
+
+```python
+>>> import httpx
+>>> async with httpx.AsyncClient() as client:
+>>>     r = await client.get('https://www.example.org/')
+>>> r
+<Response [200 OK]>
+```
+
 ## Features
 
 HTTPX is a high performance asynchronous HTTP client, that builds on the
diff --git a/httpx/decoders.py b/httpx/decoders.py
index 75d980d..454ec4a 100644
--- a/httpx/decoders.py
+++ b/httpx/decoders.py
@@ -45,12 +45,18 @@ class DeflateDecoder(Decoder):
     """
 
     def __init__(self) -> None:
-        self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
+        self.first_attempt = True
+        self.decompressor = zlib.decompressobj()
 
     def decode(self, data: bytes) -> bytes:
+        was_first_attempt = self.first_attempt
+        self.first_attempt = False
         try:
             return self.decompressor.decompress(data)
         except zlib.error as exc:
+            if was_first_attempt:
+                self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
+                return self.decode(data)
             raise DecodingError from exc
 
     def flush(self) -> bytes:
diff --git a/httpx/dispatch/urllib3.py b/httpx/dispatch/urllib3.py
index 1782834..2728170 100644
--- a/httpx/dispatch/urllib3.py
+++ b/httpx/dispatch/urllib3.py
@@ -77,7 +77,7 @@ class URLLib3Dispatcher(SyncDispatcher):
             )
         else:
             return urllib3.ProxyManager(
-                proxy_url=proxy.url,
+                proxy_url=str(proxy.url),
                 proxy_headers=dict(proxy.headers),
                 ssl_context=ssl_context,
                 num_pools=num_pools,


Test patch:
diff --git a/tests/test_decoders.py b/tests/test_decoders.py
index f320d94..d9e82f7 100644
--- a/tests/test_decoders.py
+++ b/tests/test_decoders.py
@@ -18,6 +18,11 @@ REQUEST = httpx.Request("GET", "https://example.org")
 
 
 def test_deflate():
+    """
+    Deflate encoding may use either 'zlib' or 'deflate' in the wild.
+
+    https://stackoverflow.com/questions/1838699/how-can-i-decompress-a-gzip-stream-with-zlib#answer-22311297
+    """
     body = b"test 123"
     compressor = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS)
     compressed_body = compressor.compress(body) + compressor.flush()
@@ -29,6 +34,22 @@ def test_deflate():
     assert response.content == body
 
 
+def test_zlib():
+    """
+    Deflate encoding may use either 'zlib' or 'deflate' in the wild.
+
+    https://stackoverflow.com/questions/1838699/how-can-i-decompress-a-gzip-stream-with-zlib#answer-22311297
+    """
+    body = b"test 123"
+    compressed_body = zlib.compress(body)
+
+    headers = [(b"Content-Encoding", b"deflate")]
+    response = httpx.Response(
+        200, headers=headers, content=compressed_body, request=REQUEST
+    )
+    assert response.content == body
+
+
 def test_gzip():
     body = b"test 123"
     compressor = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16)