We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `httpx/_transports/wsgi.py`
Content:
```
1 import io
2 import itertools
3 import typing
4 
5 import httpcore
6 
7 
8 def _skip_leading_empty_chunks(body: typing.Iterable) -> typing.Iterable:
9     body = iter(body)
10     for chunk in body:
11         if chunk:
12             return itertools.chain([chunk], body)
13     return []
14 
15 
16 class WSGITransport(httpcore.SyncHTTPTransport):
17     """
18     A custom transport that handles sending requests directly to an WSGI app.
19     The simplest way to use this functionality is to use the `app` argument.
20 
21     ```
22     client = httpx.Client(app=app)
23     ```
24 
25     Alternatively, you can setup the transport instance explicitly.
26     This allows you to include any additional configuration arguments specific
27     to the WSGITransport class:
28 
29     ```
30     transport = httpx.WSGITransport(
31         app=app,
32         script_name="/submount",
33         remote_addr="1.2.3.4"
34     )
35     client = httpx.Client(transport=transport)
36     ```
37 
38     Arguments:
39 
40     * `app` - The ASGI application.
41     * `raise_app_exceptions` - Boolean indicating if exceptions in the application
42        should be raised. Default to `True`. Can be set to `False` for use cases
43        such as testing the content of a client 500 response.
44     * `script_name` - The root path on which the ASGI application should be mounted.
45     * `remote_addr` - A string indicating the client IP of incoming requests.
46     ```
47     """
48 
49     def __init__(
50         self,
51         app: typing.Callable,
52         raise_app_exceptions: bool = True,
53         script_name: str = "",
54         remote_addr: str = "127.0.0.1",
55     ) -> None:
56         self.app = app
57         self.raise_app_exceptions = raise_app_exceptions
58         self.script_name = script_name
59         self.remote_addr = remote_addr
60 
61     def request(
62         self,
63         method: bytes,
64         url: typing.Tuple[bytes, bytes, typing.Optional[int], bytes],
65         headers: typing.List[typing.Tuple[bytes, bytes]] = None,
66         stream: httpcore.SyncByteStream = None,
67         ext: dict = None,
68     ) -> typing.Tuple[
69         int, typing.List[typing.Tuple[bytes, bytes]], httpcore.SyncByteStream, dict
70     ]:
71         headers = [] if headers is None else headers
72         stream = httpcore.PlainByteStream(content=b"") if stream is None else stream
73 
74         scheme, host, port, full_path = url
75         path, _, query = full_path.partition(b"?")
76         environ = {
77             "wsgi.version": (1, 0),
78             "wsgi.url_scheme": scheme.decode("ascii"),
79             "wsgi.input": io.BytesIO(b"".join(stream)),
80             "wsgi.errors": io.BytesIO(),
81             "wsgi.multithread": True,
82             "wsgi.multiprocess": False,
83             "wsgi.run_once": False,
84             "REQUEST_METHOD": method.decode(),
85             "SCRIPT_NAME": self.script_name,
86             "PATH_INFO": path.decode("ascii"),
87             "QUERY_STRING": query.decode("ascii"),
88             "SERVER_NAME": host.decode("ascii"),
89             "SERVER_PORT": str(port),
90             "REMOTE_ADDR": self.remote_addr,
91         }
92         for header_key, header_value in headers:
93             key = header_key.decode("ascii").upper().replace("-", "_")
94             if key not in ("CONTENT_TYPE", "CONTENT_LENGTH"):
95                 key = "HTTP_" + key
96             environ[key] = header_value.decode("ascii")
97 
98         seen_status = None
99         seen_response_headers = None
100         seen_exc_info = None
101 
102         def start_response(
103             status: str, response_headers: list, exc_info: typing.Any = None
104         ) -> None:
105             nonlocal seen_status, seen_response_headers, seen_exc_info
106             seen_status = status
107             seen_response_headers = response_headers
108             seen_exc_info = exc_info
109 
110         result = self.app(environ, start_response)
111         # This is needed because the status returned by start_response
112         # shouldn't be used until the first non-empty chunk has been served.
113         result = _skip_leading_empty_chunks(result)
114 
115         assert seen_status is not None
116         assert seen_response_headers is not None
117         if seen_exc_info and self.raise_app_exceptions:
118             raise seen_exc_info[1]
119 
120         status_code = int(seen_status.split()[0])
121         headers = [
122             (key.encode("ascii"), value.encode("ascii"))
123             for key, value in seen_response_headers
124         ]
125         stream = httpcore.IteratorByteStream(iterator=result)
126         ext = {}
127 
128         return (status_code, headers, stream, ext)
129
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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 @@
             "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),

{"golden_diff": "diff --git a/httpx/_transports/wsgi.py b/httpx/_transports/wsgi.py\n--- a/httpx/_transports/wsgi.py\n+++ b/httpx/_transports/wsgi.py\n@@ -1,6 +1,7 @@\n import io\n import itertools\n import typing\n+from urllib.parse import unquote\n \n import httpcore\n \n@@ -83,7 +84,7 @@\n             \"wsgi.run_once\": False,\n             \"REQUEST_METHOD\": method.decode(),\n             \"SCRIPT_NAME\": self.script_name,\n-            \"PATH_INFO\": path.decode(\"ascii\"),\n+            \"PATH_INFO\": unquote(path.decode(\"ascii\")),\n             \"QUERY_STRING\": query.decode(\"ascii\"),\n             \"SERVER_NAME\": host.decode(\"ascii\"),\n             \"SERVER_PORT\": str(port),\n", "issue": "Path encoding broken for non-ASCII in WSGI mode\n### Describe the bug\r\n\r\nWhen using httpx to call into a WSGI application (my preferred way to test Flask app nowadays), the web view receives urlencoded paths.\r\n\r\nI'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.\r\n\r\n### To reproduce\r\n\r\n```python\r\nfrom flask import Flask, request\r\n\r\nimport httpx\r\n\r\n\r\napp = Flask(__name__)\r\n\r\n@app.route('/<path>')\r\ndef hello_world(path):\r\n    return f\"path: { path }, query: { request.args['a'] }, url: { request.url }\"\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    with httpx.Client(app=app, base_url=\"http://testserver\") as client:\r\n        resp = client.get(\"/\u00e4\", params={\"a\": \"\u00e4\"})\r\n\r\n    print(\"httpx\", resp.text)\r\n\r\n    with app.test_client() as client:\r\n        resp = client.get(\"/\u00e4?a=%C3%A4\")\r\n\r\n    print(\"flask\", resp.get_data().decode(\"utf-8\"))\r\n```\r\n\r\n### Expected behavior\r\n\r\n```\r\nhttpx path: \u00e4, query: \u00e4, url: http://testserver/\u00e4?a=\u00e4\r\nflask path: \u00e4, query: \u00e4, url: http://localhost/\u00e4?a=\u00e4\r\n```\r\n\r\n### Actual behavior\r\n\r\n```\r\nhttpx path: %C3%A4, query: \u00e4, url: http://testserver/%25C3%25A4?a=\u00e4\r\nflask path: \u00e4, query: \u00e4, url: http://localhost/\u00e4?a=\u00e4\r\n```\r\n\r\nNB\r\n\r\n-  it seems to handle query parameters just fine.\r\n- `%25` is the ASCII code of the percent sign\r\n\r\n### Environment\r\n\r\n- OS: macOS\r\n- Python version: 3.8.6\r\n- HTTPX version: 0.16.1\r\n- Async environment: n/a\r\n- HTTP proxy: n/a\r\n- Custom certificates: no\r\n\n", "before_files": [{"content": "import io\nimport itertools\nimport typing\n\nimport httpcore\n\n\ndef _skip_leading_empty_chunks(body: typing.Iterable) -> typing.Iterable:\n    body = iter(body)\n    for chunk in body:\n        if chunk:\n            return itertools.chain([chunk], body)\n    return []\n\n\nclass WSGITransport(httpcore.SyncHTTPTransport):\n    \"\"\"\n    A custom transport that handles sending requests directly to an WSGI app.\n    The simplest way to use this functionality is to use the `app` argument.\n\n    ```\n    client = httpx.Client(app=app)\n    ```\n\n    Alternatively, you can setup the transport instance explicitly.\n    This allows you to include any additional configuration arguments specific\n    to the WSGITransport class:\n\n    ```\n    transport = httpx.WSGITransport(\n        app=app,\n        script_name=\"/submount\",\n        remote_addr=\"1.2.3.4\"\n    )\n    client = httpx.Client(transport=transport)\n    ```\n\n    Arguments:\n\n    * `app` - The ASGI application.\n    * `raise_app_exceptions` - Boolean indicating if exceptions in the application\n       should be raised. Default to `True`. Can be set to `False` for use cases\n       such as testing the content of a client 500 response.\n    * `script_name` - The root path on which the ASGI application should be mounted.\n    * `remote_addr` - A string indicating the client IP of incoming requests.\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        app: typing.Callable,\n        raise_app_exceptions: bool = True,\n        script_name: str = \"\",\n        remote_addr: str = \"127.0.0.1\",\n    ) -> None:\n        self.app = app\n        self.raise_app_exceptions = raise_app_exceptions\n        self.script_name = script_name\n        self.remote_addr = remote_addr\n\n    def request(\n        self,\n        method: bytes,\n        url: typing.Tuple[bytes, bytes, typing.Optional[int], bytes],\n        headers: typing.List[typing.Tuple[bytes, bytes]] = None,\n        stream: httpcore.SyncByteStream = None,\n        ext: dict = None,\n    ) -> typing.Tuple[\n        int, typing.List[typing.Tuple[bytes, bytes]], httpcore.SyncByteStream, dict\n    ]:\n        headers = [] if headers is None else headers\n        stream = httpcore.PlainByteStream(content=b\"\") if stream is None else stream\n\n        scheme, host, port, full_path = url\n        path, _, query = full_path.partition(b\"?\")\n        environ = {\n            \"wsgi.version\": (1, 0),\n            \"wsgi.url_scheme\": scheme.decode(\"ascii\"),\n            \"wsgi.input\": io.BytesIO(b\"\".join(stream)),\n            \"wsgi.errors\": io.BytesIO(),\n            \"wsgi.multithread\": True,\n            \"wsgi.multiprocess\": False,\n            \"wsgi.run_once\": False,\n            \"REQUEST_METHOD\": method.decode(),\n            \"SCRIPT_NAME\": self.script_name,\n            \"PATH_INFO\": path.decode(\"ascii\"),\n            \"QUERY_STRING\": query.decode(\"ascii\"),\n            \"SERVER_NAME\": host.decode(\"ascii\"),\n            \"SERVER_PORT\": str(port),\n            \"REMOTE_ADDR\": self.remote_addr,\n        }\n        for header_key, header_value in headers:\n            key = header_key.decode(\"ascii\").upper().replace(\"-\", \"_\")\n            if key not in (\"CONTENT_TYPE\", \"CONTENT_LENGTH\"):\n                key = \"HTTP_\" + key\n            environ[key] = header_value.decode(\"ascii\")\n\n        seen_status = None\n        seen_response_headers = None\n        seen_exc_info = None\n\n        def start_response(\n            status: str, response_headers: list, exc_info: typing.Any = None\n        ) -> None:\n            nonlocal seen_status, seen_response_headers, seen_exc_info\n            seen_status = status\n            seen_response_headers = response_headers\n            seen_exc_info = exc_info\n\n        result = self.app(environ, start_response)\n        # This is needed because the status returned by start_response\n        # shouldn't be used until the first non-empty chunk has been served.\n        result = _skip_leading_empty_chunks(result)\n\n        assert seen_status is not None\n        assert seen_response_headers is not None\n        if seen_exc_info and self.raise_app_exceptions:\n            raise seen_exc_info[1]\n\n        status_code = int(seen_status.split()[0])\n        headers = [\n            (key.encode(\"ascii\"), value.encode(\"ascii\"))\n            for key, value in seen_response_headers\n        ]\n        stream = httpcore.IteratorByteStream(iterator=result)\n        ext = {}\n\n        return (status_code, headers, stream, ext)\n", "path": "httpx/_transports/wsgi.py"}], "after_files": [{"content": "import io\nimport itertools\nimport typing\nfrom urllib.parse import unquote\n\nimport httpcore\n\n\ndef _skip_leading_empty_chunks(body: typing.Iterable) -> typing.Iterable:\n    body = iter(body)\n    for chunk in body:\n        if chunk:\n            return itertools.chain([chunk], body)\n    return []\n\n\nclass WSGITransport(httpcore.SyncHTTPTransport):\n    \"\"\"\n    A custom transport that handles sending requests directly to an WSGI app.\n    The simplest way to use this functionality is to use the `app` argument.\n\n    ```\n    client = httpx.Client(app=app)\n    ```\n\n    Alternatively, you can setup the transport instance explicitly.\n    This allows you to include any additional configuration arguments specific\n    to the WSGITransport class:\n\n    ```\n    transport = httpx.WSGITransport(\n        app=app,\n        script_name=\"/submount\",\n        remote_addr=\"1.2.3.4\"\n    )\n    client = httpx.Client(transport=transport)\n    ```\n\n    Arguments:\n\n    * `app` - The ASGI application.\n    * `raise_app_exceptions` - Boolean indicating if exceptions in the application\n       should be raised. Default to `True`. Can be set to `False` for use cases\n       such as testing the content of a client 500 response.\n    * `script_name` - The root path on which the ASGI application should be mounted.\n    * `remote_addr` - A string indicating the client IP of incoming requests.\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        app: typing.Callable,\n        raise_app_exceptions: bool = True,\n        script_name: str = \"\",\n        remote_addr: str = \"127.0.0.1\",\n    ) -> None:\n        self.app = app\n        self.raise_app_exceptions = raise_app_exceptions\n        self.script_name = script_name\n        self.remote_addr = remote_addr\n\n    def request(\n        self,\n        method: bytes,\n        url: typing.Tuple[bytes, bytes, typing.Optional[int], bytes],\n        headers: typing.List[typing.Tuple[bytes, bytes]] = None,\n        stream: httpcore.SyncByteStream = None,\n        ext: dict = None,\n    ) -> typing.Tuple[\n        int, typing.List[typing.Tuple[bytes, bytes]], httpcore.SyncByteStream, dict\n    ]:\n        headers = [] if headers is None else headers\n        stream = httpcore.PlainByteStream(content=b\"\") if stream is None else stream\n\n        scheme, host, port, full_path = url\n        path, _, query = full_path.partition(b\"?\")\n        environ = {\n            \"wsgi.version\": (1, 0),\n            \"wsgi.url_scheme\": scheme.decode(\"ascii\"),\n            \"wsgi.input\": io.BytesIO(b\"\".join(stream)),\n            \"wsgi.errors\": io.BytesIO(),\n            \"wsgi.multithread\": True,\n            \"wsgi.multiprocess\": False,\n            \"wsgi.run_once\": False,\n            \"REQUEST_METHOD\": method.decode(),\n            \"SCRIPT_NAME\": self.script_name,\n            \"PATH_INFO\": unquote(path.decode(\"ascii\")),\n            \"QUERY_STRING\": query.decode(\"ascii\"),\n            \"SERVER_NAME\": host.decode(\"ascii\"),\n            \"SERVER_PORT\": str(port),\n            \"REMOTE_ADDR\": self.remote_addr,\n        }\n        for header_key, header_value in headers:\n            key = header_key.decode(\"ascii\").upper().replace(\"-\", \"_\")\n            if key not in (\"CONTENT_TYPE\", \"CONTENT_LENGTH\"):\n                key = \"HTTP_\" + key\n            environ[key] = header_value.decode(\"ascii\")\n\n        seen_status = None\n        seen_response_headers = None\n        seen_exc_info = None\n\n        def start_response(\n            status: str, response_headers: list, exc_info: typing.Any = None\n        ) -> None:\n            nonlocal seen_status, seen_response_headers, seen_exc_info\n            seen_status = status\n            seen_response_headers = response_headers\n            seen_exc_info = exc_info\n\n        result = self.app(environ, start_response)\n        # This is needed because the status returned by start_response\n        # shouldn't be used until the first non-empty chunk has been served.\n        result = _skip_leading_empty_chunks(result)\n\n        assert seen_status is not None\n        assert seen_response_headers is not None\n        if seen_exc_info and self.raise_app_exceptions:\n            raise seen_exc_info[1]\n\n        status_code = int(seen_status.split()[0])\n        headers = [\n            (key.encode(\"ascii\"), value.encode(\"ascii\"))\n            for key, value in seen_response_headers\n        ]\n        stream = httpcore.IteratorByteStream(iterator=result)\n        ext = {}\n\n        return (status_code, headers, stream, ext)\n", "path": "httpx/_transports/wsgi.py"}]}