prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Deprecate `WSGIMiddleware` in favor of `a2wsgi`
  ### Checklist
  
  - [X] There are no similar issues or pull requests for this yet.
  - [X] I discussed this idea on the [community chat](https://gitter.im/encode/community) and feedback is positive.
  
  ### Is your feature related to a problem? Please describe.
  
  I want to deprecate `WSGIMiddleware` and recommend [a2wsgi](https://github.com/abersheeran/a2wsgi) on the documentation.
  
  Right now, the `WSGIMiddleware` is not documented, so not that harmful to deprecate. I expect the deprecation message to inform about `a2wsgi` or recommend the specific page on the docs so users using the middleware can fix the warning easily.
  
  ### Describe the solution you would like.
  
  _No response_
  
  ### Describe alternatives you considered
  
  _No response_
  
  ### Additional context
  
  Gitter conversation about the topic:
  
  ![image](https://user-images.githubusercontent.com/7353520/153407199-f31ff3cf-8406-4801-b034-db28601fbca6.png)
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `starlette/middleware/wsgi.py`
  Content:
  ```
  1 import io
  2 import math
  3 import sys
  4 import typing
  5 
  6 import anyio
  7 
  8 from starlette.types import Receive, Scope, Send
  9 
  10 
  11 def build_environ(scope: Scope, body: bytes) -> dict:
  12     """
  13     Builds a scope and request body into a WSGI environ object.
  14     """
  15     environ = {
  16         "REQUEST_METHOD": scope["method"],
  17         "SCRIPT_NAME": scope.get("root_path", "").encode("utf8").decode("latin1"),
  18         "PATH_INFO": scope["path"].encode("utf8").decode("latin1"),
  19         "QUERY_STRING": scope["query_string"].decode("ascii"),
  20         "SERVER_PROTOCOL": f"HTTP/{scope['http_version']}",
  21         "wsgi.version": (1, 0),
  22         "wsgi.url_scheme": scope.get("scheme", "http"),
  23         "wsgi.input": io.BytesIO(body),
  24         "wsgi.errors": sys.stdout,
  25         "wsgi.multithread": True,
  26         "wsgi.multiprocess": True,
  27         "wsgi.run_once": False,
  28     }
  29 
  30     # Get server name and port - required in WSGI, not in ASGI
  31     server = scope.get("server") or ("localhost", 80)
  32     environ["SERVER_NAME"] = server[0]
  33     environ["SERVER_PORT"] = server[1]
  34 
  35     # Get client IP address
  36     if scope.get("client"):
  37         environ["REMOTE_ADDR"] = scope["client"][0]
  38 
  39     # Go through headers and make them into environ entries
  40     for name, value in scope.get("headers", []):
  41         name = name.decode("latin1")
  42         if name == "content-length":
  43             corrected_name = "CONTENT_LENGTH"
  44         elif name == "content-type":
  45             corrected_name = "CONTENT_TYPE"
  46         else:
  47             corrected_name = f"HTTP_{name}".upper().replace("-", "_")
  48         # HTTPbis say only ASCII chars are allowed in headers, but we latin1 just in
  49         # case
  50         value = value.decode("latin1")
  51         if corrected_name in environ:
  52             value = environ[corrected_name] + "," + value
  53         environ[corrected_name] = value
  54     return environ
  55 
  56 
  57 class WSGIMiddleware:
  58     def __init__(self, app: typing.Callable) -> None:
  59         self.app = app
  60 
  61     async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
  62         assert scope["type"] == "http"
  63         responder = WSGIResponder(self.app, scope)
  64         await responder(receive, send)
  65 
  66 
  67 class WSGIResponder:
  68     def __init__(self, app: typing.Callable, scope: Scope) -> None:
  69         self.app = app
  70         self.scope = scope
  71         self.status = None
  72         self.response_headers = None
  73         self.stream_send, self.stream_receive = anyio.create_memory_object_stream(
  74             math.inf
  75         )
  76         self.response_started = False
  77         self.exc_info: typing.Any = None
  78 
  79     async def __call__(self, receive: Receive, send: Send) -> None:
  80         body = b""
  81         more_body = True
  82         while more_body:
  83             message = await receive()
  84             body += message.get("body", b"")
  85             more_body = message.get("more_body", False)
  86         environ = build_environ(self.scope, body)
  87 
  88         async with anyio.create_task_group() as task_group:
  89             task_group.start_soon(self.sender, send)
  90             async with self.stream_send:
  91                 await anyio.to_thread.run_sync(self.wsgi, environ, self.start_response)
  92         if self.exc_info is not None:
  93             raise self.exc_info[0].with_traceback(self.exc_info[1], self.exc_info[2])
  94 
  95     async def sender(self, send: Send) -> None:
  96         async with self.stream_receive:
  97             async for message in self.stream_receive:
  98                 await send(message)
  99 
  100     def start_response(
  101         self,
  102         status: str,
  103         response_headers: typing.List[typing.Tuple[str, str]],
  104         exc_info: typing.Any = None,
  105     ) -> None:
  106         self.exc_info = exc_info
  107         if not self.response_started:
  108             self.response_started = True
  109             status_code_string, _ = status.split(" ", 1)
  110             status_code = int(status_code_string)
  111             headers = [
  112                 (name.strip().encode("ascii").lower(), value.strip().encode("ascii"))
  113                 for name, value in response_headers
  114             ]
  115             anyio.from_thread.run(
  116                 self.stream_send.send,
  117                 {
  118                     "type": "http.response.start",
  119                     "status": status_code,
  120                     "headers": headers,
  121                 },
  122             )
  123 
  124     def wsgi(self, environ: dict, start_response: typing.Callable) -> None:
  125         for chunk in self.app(environ, start_response):
  126             anyio.from_thread.run(
  127                 self.stream_send.send,
  128                 {"type": "http.response.body", "body": chunk, "more_body": True},
  129             )
  130 
  131         anyio.from_thread.run(
  132             self.stream_send.send, {"type": "http.response.body", "body": b""}
  133         )
  134
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/starlette/middleware/wsgi.py b/starlette/middleware/wsgi.py
  --- a/starlette/middleware/wsgi.py
  +++ b/starlette/middleware/wsgi.py
  @@ -2,11 +2,18 @@
   import math
   import sys
   import typing
  +import warnings
   
   import anyio
   
   from starlette.types import Receive, Scope, Send
   
  +warnings.warn(
  +    "starlette.middleware.wsgi is deprecated and will be removed in a future release. "
  +    "Please refer to https://github.com/abersheeran/a2wsgi as a replacement.",
  +    DeprecationWarning,
  +)
  +
   
   def build_environ(scope: Scope, body: bytes) -> dict:
       """
  
verification_info: {"golden_diff": "diff --git a/starlette/middleware/wsgi.py b/starlette/middleware/wsgi.py\n--- a/starlette/middleware/wsgi.py\n+++ b/starlette/middleware/wsgi.py\n@@ -2,11 +2,18 @@\n import math\n import sys\n import typing\n+import warnings\n \n import anyio\n \n from starlette.types import Receive, Scope, Send\n \n+warnings.warn(\n+    \"starlette.middleware.wsgi is deprecated and will be removed in a future release. \"\n+    \"Please refer to https://github.com/abersheeran/a2wsgi as a replacement.\",\n+    DeprecationWarning,\n+)\n+\n \n def build_environ(scope: Scope, body: bytes) -> dict:\n     \"\"\"\n", "issue": "Deprecate `WSGIMiddleware` in favor of `a2wsgi`\n### Checklist\n\n- [X] There are no similar issues or pull requests for this yet.\n- [X] I discussed this idea on the [community chat](https://gitter.im/encode/community) and feedback is positive.\n\n### Is your feature related to a problem? Please describe.\n\nI want to deprecate `WSGIMiddleware` and recommend [a2wsgi](https://github.com/abersheeran/a2wsgi) on the documentation.\r\n\r\nRight now, the `WSGIMiddleware` is not documented, so not that harmful to deprecate. I expect the deprecation message to inform about `a2wsgi` or recommend the specific page on the docs so users using the middleware can fix the warning easily.\n\n### Describe the solution you would like.\n\n_No response_\n\n### Describe alternatives you considered\n\n_No response_\n\n### Additional context\n\nGitter conversation about the topic:\r\n\r\n![image](https://user-images.githubusercontent.com/7353520/153407199-f31ff3cf-8406-4801-b034-db28601fbca6.png)\r\n\n", "before_files": [{"content": "import io\nimport math\nimport sys\nimport typing\n\nimport anyio\n\nfrom starlette.types import Receive, Scope, Send\n\n\ndef build_environ(scope: Scope, body: bytes) -> dict:\n    \"\"\"\n    Builds a scope and request body into a WSGI environ object.\n    \"\"\"\n    environ = {\n        \"REQUEST_METHOD\": scope[\"method\"],\n        \"SCRIPT_NAME\": scope.get(\"root_path\", \"\").encode(\"utf8\").decode(\"latin1\"),\n        \"PATH_INFO\": scope[\"path\"].encode(\"utf8\").decode(\"latin1\"),\n        \"QUERY_STRING\": scope[\"query_string\"].decode(\"ascii\"),\n        \"SERVER_PROTOCOL\": f\"HTTP/{scope['http_version']}\",\n        \"wsgi.version\": (1, 0),\n        \"wsgi.url_scheme\": scope.get(\"scheme\", \"http\"),\n        \"wsgi.input\": io.BytesIO(body),\n        \"wsgi.errors\": sys.stdout,\n        \"wsgi.multithread\": True,\n        \"wsgi.multiprocess\": True,\n        \"wsgi.run_once\": False,\n    }\n\n    # Get server name and port - required in WSGI, not in ASGI\n    server = scope.get(\"server\") or (\"localhost\", 80)\n    environ[\"SERVER_NAME\"] = server[0]\n    environ[\"SERVER_PORT\"] = server[1]\n\n    # Get client IP address\n    if scope.get(\"client\"):\n        environ[\"REMOTE_ADDR\"] = scope[\"client\"][0]\n\n    # Go through headers and make them into environ entries\n    for name, value in scope.get(\"headers\", []):\n        name = name.decode(\"latin1\")\n        if name == \"content-length\":\n            corrected_name = \"CONTENT_LENGTH\"\n        elif name == \"content-type\":\n            corrected_name = \"CONTENT_TYPE\"\n        else:\n            corrected_name = f\"HTTP_{name}\".upper().replace(\"-\", \"_\")\n        # HTTPbis say only ASCII chars are allowed in headers, but we latin1 just in\n        # case\n        value = value.decode(\"latin1\")\n        if corrected_name in environ:\n            value = environ[corrected_name] + \",\" + value\n        environ[corrected_name] = value\n    return environ\n\n\nclass WSGIMiddleware:\n    def __init__(self, app: typing.Callable) -> None:\n        self.app = app\n\n    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        assert scope[\"type\"] == \"http\"\n        responder = WSGIResponder(self.app, scope)\n        await responder(receive, send)\n\n\nclass WSGIResponder:\n    def __init__(self, app: typing.Callable, scope: Scope) -> None:\n        self.app = app\n        self.scope = scope\n        self.status = None\n        self.response_headers = None\n        self.stream_send, self.stream_receive = anyio.create_memory_object_stream(\n            math.inf\n        )\n        self.response_started = False\n        self.exc_info: typing.Any = None\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        body = b\"\"\n        more_body = True\n        while more_body:\n            message = await receive()\n            body += message.get(\"body\", b\"\")\n            more_body = message.get(\"more_body\", False)\n        environ = build_environ(self.scope, body)\n\n        async with anyio.create_task_group() as task_group:\n            task_group.start_soon(self.sender, send)\n            async with self.stream_send:\n                await anyio.to_thread.run_sync(self.wsgi, environ, self.start_response)\n        if self.exc_info is not None:\n            raise self.exc_info[0].with_traceback(self.exc_info[1], self.exc_info[2])\n\n    async def sender(self, send: Send) -> None:\n        async with self.stream_receive:\n            async for message in self.stream_receive:\n                await send(message)\n\n    def start_response(\n        self,\n        status: str,\n        response_headers: typing.List[typing.Tuple[str, str]],\n        exc_info: typing.Any = None,\n    ) -> None:\n        self.exc_info = exc_info\n        if not self.response_started:\n            self.response_started = True\n            status_code_string, _ = status.split(\" \", 1)\n            status_code = int(status_code_string)\n            headers = [\n                (name.strip().encode(\"ascii\").lower(), value.strip().encode(\"ascii\"))\n                for name, value in response_headers\n            ]\n            anyio.from_thread.run(\n                self.stream_send.send,\n                {\n                    \"type\": \"http.response.start\",\n                    \"status\": status_code,\n                    \"headers\": headers,\n                },\n            )\n\n    def wsgi(self, environ: dict, start_response: typing.Callable) -> None:\n        for chunk in self.app(environ, start_response):\n            anyio.from_thread.run(\n                self.stream_send.send,\n                {\"type\": \"http.response.body\", \"body\": chunk, \"more_body\": True},\n            )\n\n        anyio.from_thread.run(\n            self.stream_send.send, {\"type\": \"http.response.body\", \"body\": b\"\"}\n        )\n", "path": "starlette/middleware/wsgi.py"}], "after_files": [{"content": "import io\nimport math\nimport sys\nimport typing\nimport warnings\n\nimport anyio\n\nfrom starlette.types import Receive, Scope, Send\n\nwarnings.warn(\n    \"starlette.middleware.wsgi is deprecated and will be removed in a future release. \"\n    \"Please refer to https://github.com/abersheeran/a2wsgi as a replacement.\",\n    DeprecationWarning,\n)\n\n\ndef build_environ(scope: Scope, body: bytes) -> dict:\n    \"\"\"\n    Builds a scope and request body into a WSGI environ object.\n    \"\"\"\n    environ = {\n        \"REQUEST_METHOD\": scope[\"method\"],\n        \"SCRIPT_NAME\": scope.get(\"root_path\", \"\").encode(\"utf8\").decode(\"latin1\"),\n        \"PATH_INFO\": scope[\"path\"].encode(\"utf8\").decode(\"latin1\"),\n        \"QUERY_STRING\": scope[\"query_string\"].decode(\"ascii\"),\n        \"SERVER_PROTOCOL\": f\"HTTP/{scope['http_version']}\",\n        \"wsgi.version\": (1, 0),\n        \"wsgi.url_scheme\": scope.get(\"scheme\", \"http\"),\n        \"wsgi.input\": io.BytesIO(body),\n        \"wsgi.errors\": sys.stdout,\n        \"wsgi.multithread\": True,\n        \"wsgi.multiprocess\": True,\n        \"wsgi.run_once\": False,\n    }\n\n    # Get server name and port - required in WSGI, not in ASGI\n    server = scope.get(\"server\") or (\"localhost\", 80)\n    environ[\"SERVER_NAME\"] = server[0]\n    environ[\"SERVER_PORT\"] = server[1]\n\n    # Get client IP address\n    if scope.get(\"client\"):\n        environ[\"REMOTE_ADDR\"] = scope[\"client\"][0]\n\n    # Go through headers and make them into environ entries\n    for name, value in scope.get(\"headers\", []):\n        name = name.decode(\"latin1\")\n        if name == \"content-length\":\n            corrected_name = \"CONTENT_LENGTH\"\n        elif name == \"content-type\":\n            corrected_name = \"CONTENT_TYPE\"\n        else:\n            corrected_name = f\"HTTP_{name}\".upper().replace(\"-\", \"_\")\n        # HTTPbis say only ASCII chars are allowed in headers, but we latin1 just in\n        # case\n        value = value.decode(\"latin1\")\n        if corrected_name in environ:\n            value = environ[corrected_name] + \",\" + value\n        environ[corrected_name] = value\n    return environ\n\n\nclass WSGIMiddleware:\n    def __init__(self, app: typing.Callable) -> None:\n        self.app = app\n\n    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        assert scope[\"type\"] == \"http\"\n        responder = WSGIResponder(self.app, scope)\n        await responder(receive, send)\n\n\nclass WSGIResponder:\n    def __init__(self, app: typing.Callable, scope: Scope) -> None:\n        self.app = app\n        self.scope = scope\n        self.status = None\n        self.response_headers = None\n        self.stream_send, self.stream_receive = anyio.create_memory_object_stream(\n            math.inf\n        )\n        self.response_started = False\n        self.exc_info: typing.Any = None\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        body = b\"\"\n        more_body = True\n        while more_body:\n            message = await receive()\n            body += message.get(\"body\", b\"\")\n            more_body = message.get(\"more_body\", False)\n        environ = build_environ(self.scope, body)\n\n        async with anyio.create_task_group() as task_group:\n            task_group.start_soon(self.sender, send)\n            async with self.stream_send:\n                await anyio.to_thread.run_sync(self.wsgi, environ, self.start_response)\n        if self.exc_info is not None:\n            raise self.exc_info[0].with_traceback(self.exc_info[1], self.exc_info[2])\n\n    async def sender(self, send: Send) -> None:\n        async with self.stream_receive:\n            async for message in self.stream_receive:\n                await send(message)\n\n    def start_response(\n        self,\n        status: str,\n        response_headers: typing.List[typing.Tuple[str, str]],\n        exc_info: typing.Any = None,\n    ) -> None:\n        self.exc_info = exc_info\n        if not self.response_started:\n            self.response_started = True\n            status_code_string, _ = status.split(\" \", 1)\n            status_code = int(status_code_string)\n            headers = [\n                (name.strip().encode(\"ascii\").lower(), value.strip().encode(\"ascii\"))\n                for name, value in response_headers\n            ]\n            anyio.from_thread.run(\n                self.stream_send.send,\n                {\n                    \"type\": \"http.response.start\",\n                    \"status\": status_code,\n                    \"headers\": headers,\n                },\n            )\n\n    def wsgi(self, environ: dict, start_response: typing.Callable) -> None:\n        for chunk in self.app(environ, start_response):\n            anyio.from_thread.run(\n                self.stream_send.send,\n                {\"type\": \"http.response.body\", \"body\": chunk, \"more_body\": True},\n            )\n\n        anyio.from_thread.run(\n            self.stream_send.send, {\"type\": \"http.response.body\", \"body\": b\"\"}\n        )\n", "path": "starlette/middleware/wsgi.py"}]}