Repository: encode/httpx

Issue:
Path encoding broken for non-ASCII in WSGI mode
### Describe the bug

When using httpx to call into a WSGI application (my preferred way to test Flask app nowadays), the web view receives urlencoded paths.

I'm not sure where this really belongs to (is it a bug in httpx or Flask!?), but I've been working around it for months, so I guess I'll make myself unpopular and try it here first. If it turns out to be Flask's fault, I'l headl over and bother the Pallets folks.

### To reproduce

```python
from flask import Flask, request

import httpx


app = Flask(__name__)

@app.route('/<path>')
def hello_world(path):
    return f"path: { path }, query: { request.args['a'] }, url: { request.url }"


if __name__ == "__main__":
    with httpx.Client(app=app, base_url="http://testserver") as client:
        resp = client.get("/ä", params={"a": "ä"})

    print("httpx", resp.text)

    with app.test_client() as client:
        resp = client.get("/ä?a=%C3%A4")

    print("flask", resp.get_data().decode("utf-8"))
```

### Expected behavior

```
httpx path: ä, query: ä, url: http://testserver/ä?a=ä
flask path: ä, query: ä, url: http://localhost/ä?a=ä
```

### Actual behavior

```
httpx path: %C3%A4, query: ä, url: http://testserver/%25C3%25A4?a=ä
flask path: ä, query: ä, url: http://localhost/ä?a=ä
```

NB

-  it seems to handle query parameters just fine.
- `%25` is the ASCII code of the percent sign

### Environment

- OS: macOS
- Python version: 3.8.6
- HTTPX version: 0.16.1
- Async environment: n/a
- HTTP proxy: n/a
- Custom certificates: no



Discussion:
This does look like a bug in httpx. Although I can't see where in [PEP-3333](https://www.python.org/dev/peps/pep-3333/) it's specified that paths should be unquoted by WSGI servers, it does seem like a thing that is widely done. You can see some discussion of a sorta related issue to this here: https://github.com/pallets/flask/issues/900

* Werkzeug's EnvironBuilder (that Flask's TestClient uses) unquotes paths: https://github.com/pallets/werkzeug/blob/1.0.1/src/werkzeug/test.py#L704-L705
* Gunicorn unquotes paths: https://github.com/benoitc/gunicorn/blob/20.0.4/gunicorn/http/wsgi.py#L184
* uWSGI seems to (so much C 😱): https://github.com/unbit/uwsgi/blob/2.0.19.1/plugins/http/http.c#L266

There are probably also some areas in the WSGI integration where we should be using latin1 encoding instead of ascii.
So the implication of https://www.python.org/dev/peps/pep-3333/#url-reconstruction is that `PATH_INFO` should be unquoted.

Which, yeah, we're not doing...

https://github.com/encode/httpx/blob/f8f543057a9feb5330784401b5fed168c5288e36/httpx/_transports/wsgi.py#L86

Although we are doing so for ASGI...

https://github.com/encode/httpx/blob/f8f543057a9feb5330784401b5fed168c5288e36/httpx/_transports/asgi.py#L92

Resolving patch:
diff --git a/httpx/_transports/wsgi.py b/httpx/_transports/wsgi.py
--- a/httpx/_transports/wsgi.py
+++ b/httpx/_transports/wsgi.py
@@ -1,6 +1,7 @@
 import io
 import itertools
 import typing
+from urllib.parse import unquote
 
 import httpcore
 
@@ -83,7 +84,7 @@ def request(
             "wsgi.run_once": False,
             "REQUEST_METHOD": method.decode(),
             "SCRIPT_NAME": self.script_name,
-            "PATH_INFO": path.decode("ascii"),
+            "PATH_INFO": unquote(path.decode("ascii")),
             "QUERY_STRING": query.decode("ascii"),
             "SERVER_NAME": host.decode("ascii"),
             "SERVER_PORT": str(port),


Test patch: