We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Uvicorn ignores listeners errors
**Describe the bug**
When an exception happens on a listener the error is not reported and the server doesn't crash when using Uvicorn.


**Code snippet**
```python
from sanic import Sanic
from sanic.response import text

app = Sanic("MyHelloWorldApp")

@app.listener("before_server_start")
async def raises(app, loop):
    print("Trying to run faster")
    raise Exception("oh noes")

@app.get("/")
async def hello_world(request):
    return text("Hello, world.")
```

```
~ uvicorn app:app
INFO:     Started server process [49837]
INFO:     Waiting for application startup.
[2022-01-25 14:57:34 +0100] [49837] [INFO]
  ┌────────────────────────────────────────────────────────────────┐
  │                         Sanic v21.12.1                         │
  │                                                                │
  ├───────────────────────┬────────────────────────────────────────┤
  │                       │     mode: production, ASGI             │
  │     ▄███ █████ ██     │   server: sanic                        │
  │    ██                 │   python: 3.9.10                       │
  │     ▀███████ ███▄     │ platform: macOS-12.1-x86_64-i386-64bit │
  │                 ██    │ packages: sanic-routing==0.7.2         │
  │    ████ ████████▀     │                                        │
  │                       │                                        │
  │ Build Fast. Run Fast. │                                        │
  └───────────────────────┴────────────────────────────────────────┘

/Users/andre.ericson/projects/sanic-uvicorn/.venv/lib/python3.9/site-packages/sanic/asgi.py:27: UserWarning: You have set a listener for "before_server_start" in ASGI mode. It will be executed as early as possible, but not before the ASGI server is started.
  warnings.warn(
Trying to run faster
INFO:     ASGI 'lifespan' protocol appears unsupported.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
``` 
**Expected behavior**
The server should crash, or at least log an error.


**Environment (please complete the following information):**
 - MacOS
 - python 3.9.10
 ```
 pip list
Package       Version
------------- ------------
aiofiles      0.8.0
asgiref       3.5.0
click         8.0.3
h11           0.13.0
httptools     0.3.0
multidict     5.2.0
pip           21.3.1
sanic         21.12.1
sanic-routing 0.7.2
setuptools    58.1.0
ujson         5.1.0
uvicorn       0.17.0.post1
uvloop        0.16.0
websockets    10.1
 ```


**Additional context**
Works as expected with `sanic app.app` and also with GunicornWorker.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sanic/asgi.py`
Content:
```
1 from __future__ import annotations
2 
3 import warnings
4 
5 from typing import TYPE_CHECKING, Optional
6 from urllib.parse import quote
7 
8 from sanic.compat import Header
9 from sanic.exceptions import ServerError
10 from sanic.helpers import Default
11 from sanic.http import Stage
12 from sanic.log import logger
13 from sanic.models.asgi import ASGIReceive, ASGIScope, ASGISend, MockTransport
14 from sanic.request import Request
15 from sanic.response import BaseHTTPResponse
16 from sanic.server import ConnInfo
17 from sanic.server.websockets.connection import WebSocketConnection
18 
19 
20 if TYPE_CHECKING:
21     from sanic import Sanic
22 
23 
24 class Lifespan:
25     def __init__(self, asgi_app: ASGIApp) -> None:
26         self.asgi_app = asgi_app
27 
28         if (
29             "server.init.before"
30             in self.asgi_app.sanic_app.signal_router.name_index
31         ):
32             logger.debug(
33                 'You have set a listener for "before_server_start" '
34                 "in ASGI mode. "
35                 "It will be executed as early as possible, but not before "
36                 "the ASGI server is started.",
37                 extra={"verbosity": 1},
38             )
39         if (
40             "server.shutdown.after"
41             in self.asgi_app.sanic_app.signal_router.name_index
42         ):
43             logger.debug(
44                 'You have set a listener for "after_server_stop" '
45                 "in ASGI mode. "
46                 "It will be executed as late as possible, but not after "
47                 "the ASGI server is stopped.",
48                 extra={"verbosity": 1},
49             )
50 
51     async def startup(self) -> None:
52         """
53         Gather the listeners to fire on server start.
54         Because we are using a third-party server and not Sanic server, we do
55         not have access to fire anything BEFORE the server starts.
56         Therefore, we fire before_server_start and after_server_start
57         in sequence since the ASGI lifespan protocol only supports a single
58         startup event.
59         """
60         await self.asgi_app.sanic_app._startup()
61         await self.asgi_app.sanic_app._server_event("init", "before")
62         await self.asgi_app.sanic_app._server_event("init", "after")
63 
64         if not isinstance(self.asgi_app.sanic_app.config.USE_UVLOOP, Default):
65             warnings.warn(
66                 "You have set the USE_UVLOOP configuration option, but Sanic "
67                 "cannot control the event loop when running in ASGI mode."
68                 "This option will be ignored."
69             )
70 
71     async def shutdown(self) -> None:
72         """
73         Gather the listeners to fire on server stop.
74         Because we are using a third-party server and not Sanic server, we do
75         not have access to fire anything AFTER the server stops.
76         Therefore, we fire before_server_stop and after_server_stop
77         in sequence since the ASGI lifespan protocol only supports a single
78         shutdown event.
79         """
80         await self.asgi_app.sanic_app._server_event("shutdown", "before")
81         await self.asgi_app.sanic_app._server_event("shutdown", "after")
82 
83     async def __call__(
84         self, scope: ASGIScope, receive: ASGIReceive, send: ASGISend
85     ) -> None:
86         message = await receive()
87         if message["type"] == "lifespan.startup":
88             await self.startup()
89             await send({"type": "lifespan.startup.complete"})
90 
91         message = await receive()
92         if message["type"] == "lifespan.shutdown":
93             await self.shutdown()
94             await send({"type": "lifespan.shutdown.complete"})
95 
96 
97 class ASGIApp:
98     sanic_app: Sanic
99     request: Request
100     transport: MockTransport
101     lifespan: Lifespan
102     ws: Optional[WebSocketConnection]
103     stage: Stage
104     response: Optional[BaseHTTPResponse]
105 
106     def __init__(self) -> None:
107         self.ws = None
108 
109     @classmethod
110     async def create(
111         cls, sanic_app, scope: ASGIScope, receive: ASGIReceive, send: ASGISend
112     ) -> "ASGIApp":
113         instance = cls()
114         instance.sanic_app = sanic_app
115         instance.transport = MockTransport(scope, receive, send)
116         instance.transport.loop = sanic_app.loop
117         instance.stage = Stage.IDLE
118         instance.response = None
119         setattr(instance.transport, "add_task", sanic_app.loop.create_task)
120 
121         headers = Header(
122             [
123                 (key.decode("latin-1"), value.decode("latin-1"))
124                 for key, value in scope.get("headers", [])
125             ]
126         )
127         instance.lifespan = Lifespan(instance)
128 
129         if scope["type"] == "lifespan":
130             await instance.lifespan(scope, receive, send)
131         else:
132             path = (
133                 scope["path"][1:]
134                 if scope["path"].startswith("/")
135                 else scope["path"]
136             )
137             url = "/".join([scope.get("root_path", ""), quote(path)])
138             url_bytes = url.encode("latin-1")
139             url_bytes += b"?" + scope["query_string"]
140 
141             if scope["type"] == "http":
142                 version = scope["http_version"]
143                 method = scope["method"]
144             elif scope["type"] == "websocket":
145                 version = "1.1"
146                 method = "GET"
147 
148                 instance.ws = instance.transport.create_websocket_connection(
149                     send, receive
150                 )
151             else:
152                 raise ServerError("Received unknown ASGI scope")
153 
154             request_class = sanic_app.request_class or Request
155             instance.request = request_class(
156                 url_bytes,
157                 headers,
158                 version,
159                 method,
160                 instance.transport,
161                 sanic_app,
162             )
163             instance.request.stream = instance
164             instance.request_body = True
165             instance.request.conn_info = ConnInfo(instance.transport)
166 
167             await sanic_app.dispatch(
168                 "http.lifecycle.request",
169                 inline=True,
170                 context={"request": instance.request},
171                 fail_not_found=False,
172             )
173 
174         return instance
175 
176     async def read(self) -> Optional[bytes]:
177         """
178         Read and stream the body in chunks from an incoming ASGI message.
179         """
180         if self.stage is Stage.IDLE:
181             self.stage = Stage.REQUEST
182         message = await self.transport.receive()
183         body = message.get("body", b"")
184         if not message.get("more_body", False):
185             self.request_body = False
186             if not body:
187                 return None
188         return body
189 
190     async def __aiter__(self):
191         while self.request_body:
192             data = await self.read()
193             if data:
194                 yield data
195 
196     def respond(self, response: BaseHTTPResponse):
197         if self.stage is not Stage.HANDLER:
198             self.stage = Stage.FAILED
199             raise RuntimeError("Response already started")
200         if self.response is not None:
201             self.response.stream = None
202         response.stream, self.response = self, response
203         return response
204 
205     async def send(self, data, end_stream):
206         self.stage = Stage.IDLE if end_stream else Stage.RESPONSE
207         if self.response:
208             response, self.response = self.response, None
209             await self.transport.send(
210                 {
211                     "type": "http.response.start",
212                     "status": response.status,
213                     "headers": response.processed_headers,
214                 }
215             )
216             response_body = getattr(response, "body", None)
217             if response_body:
218                 data = response_body + data if data else response_body
219         await self.transport.send(
220             {
221                 "type": "http.response.body",
222                 "body": data.encode() if hasattr(data, "encode") else data,
223                 "more_body": not end_stream,
224             }
225         )
226 
227     _asgi_single_callable = True  # We conform to ASGI 3.0 single-callable
228 
229     async def __call__(self) -> None:
230         """
231         Handle the incoming request.
232         """
233         try:
234             self.stage = Stage.HANDLER
235             await self.sanic_app.handle_request(self.request)
236         except Exception as e:
237             try:
238                 await self.sanic_app.handle_exception(self.request, e)
239             except Exception as exc:
240                 await self.sanic_app.handle_exception(self.request, exc, False)
241
```
--- 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/sanic/asgi.py b/sanic/asgi.py
--- a/sanic/asgi.py
+++ b/sanic/asgi.py
@@ -9,7 +9,7 @@
 from sanic.exceptions import ServerError
 from sanic.helpers import Default
 from sanic.http import Stage
-from sanic.log import logger
+from sanic.log import error_logger, logger
 from sanic.models.asgi import ASGIReceive, ASGIScope, ASGISend, MockTransport
 from sanic.request import Request
 from sanic.response import BaseHTTPResponse
@@ -85,13 +85,27 @@
     ) -> None:
         message = await receive()
         if message["type"] == "lifespan.startup":
-            await self.startup()
-            await send({"type": "lifespan.startup.complete"})
+            try:
+                await self.startup()
+            except Exception as e:
+                error_logger.exception(e)
+                await send(
+                    {"type": "lifespan.startup.failed", "message": str(e)}
+                )
+            else:
+                await send({"type": "lifespan.startup.complete"})
 
         message = await receive()
         if message["type"] == "lifespan.shutdown":
-            await self.shutdown()
-            await send({"type": "lifespan.shutdown.complete"})
+            try:
+                await self.shutdown()
+            except Exception as e:
+                error_logger.exception(e)
+                await send(
+                    {"type": "lifespan.shutdown.failed", "message": str(e)}
+                )
+            else:
+                await send({"type": "lifespan.shutdown.complete"})
 
 
 class ASGIApp:

{"golden_diff": "diff --git a/sanic/asgi.py b/sanic/asgi.py\n--- a/sanic/asgi.py\n+++ b/sanic/asgi.py\n@@ -9,7 +9,7 @@\n from sanic.exceptions import ServerError\n from sanic.helpers import Default\n from sanic.http import Stage\n-from sanic.log import logger\n+from sanic.log import error_logger, logger\n from sanic.models.asgi import ASGIReceive, ASGIScope, ASGISend, MockTransport\n from sanic.request import Request\n from sanic.response import BaseHTTPResponse\n@@ -85,13 +85,27 @@\n     ) -> None:\n         message = await receive()\n         if message[\"type\"] == \"lifespan.startup\":\n-            await self.startup()\n-            await send({\"type\": \"lifespan.startup.complete\"})\n+            try:\n+                await self.startup()\n+            except Exception as e:\n+                error_logger.exception(e)\n+                await send(\n+                    {\"type\": \"lifespan.startup.failed\", \"message\": str(e)}\n+                )\n+            else:\n+                await send({\"type\": \"lifespan.startup.complete\"})\n \n         message = await receive()\n         if message[\"type\"] == \"lifespan.shutdown\":\n-            await self.shutdown()\n-            await send({\"type\": \"lifespan.shutdown.complete\"})\n+            try:\n+                await self.shutdown()\n+            except Exception as e:\n+                error_logger.exception(e)\n+                await send(\n+                    {\"type\": \"lifespan.shutdown.failed\", \"message\": str(e)}\n+                )\n+            else:\n+                await send({\"type\": \"lifespan.shutdown.complete\"})\n \n \n class ASGIApp:\n", "issue": "Uvicorn ignores listeners errors\n**Describe the bug**\r\nWhen an exception happens on a listener the error is not reported and the server doesn't crash when using Uvicorn.\r\n\r\n\r\n**Code snippet**\r\n```python\r\nfrom sanic import Sanic\r\nfrom sanic.response import text\r\n\r\napp = Sanic(\"MyHelloWorldApp\")\r\n\r\n@app.listener(\"before_server_start\")\r\nasync def raises(app, loop):\r\n    print(\"Trying to run faster\")\r\n    raise Exception(\"oh noes\")\r\n\r\n@app.get(\"/\")\r\nasync def hello_world(request):\r\n    return text(\"Hello, world.\")\r\n```\r\n\r\n```\r\n~ uvicorn app:app\r\nINFO:     Started server process [49837]\r\nINFO:     Waiting for application startup.\r\n[2022-01-25 14:57:34 +0100] [49837] [INFO]\r\n  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\r\n  \u2502                         Sanic v21.12.1                         \u2502\r\n  \u2502                                                                \u2502\r\n  \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\r\n  \u2502                       \u2502     mode: production, ASGI             \u2502\r\n  \u2502     \u2584\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588     \u2502   server: sanic                        \u2502\r\n  \u2502    \u2588\u2588                 \u2502   python: 3.9.10                       \u2502\r\n  \u2502     \u2580\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2584     \u2502 platform: macOS-12.1-x86_64-i386-64bit \u2502\r\n  \u2502                 \u2588\u2588    \u2502 packages: sanic-routing==0.7.2         \u2502\r\n  \u2502    \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2580     \u2502                                        \u2502\r\n  \u2502                       \u2502                                        \u2502\r\n  \u2502 Build Fast. Run Fast. \u2502                                        \u2502\r\n  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\r\n\r\n/Users/andre.ericson/projects/sanic-uvicorn/.venv/lib/python3.9/site-packages/sanic/asgi.py:27: UserWarning: You have set a listener for \"before_server_start\" in ASGI mode. It will be executed as early as possible, but not before the ASGI server is started.\r\n  warnings.warn(\r\nTrying to run faster\r\nINFO:     ASGI 'lifespan' protocol appears unsupported.\r\nINFO:     Application startup complete.\r\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\r\n``` \r\n**Expected behavior**\r\nThe server should crash, or at least log an error.\r\n\r\n\r\n**Environment (please complete the following information):**\r\n - MacOS\r\n - python 3.9.10\r\n ```\r\n pip list\r\nPackage       Version\r\n------------- ------------\r\naiofiles      0.8.0\r\nasgiref       3.5.0\r\nclick         8.0.3\r\nh11           0.13.0\r\nhttptools     0.3.0\r\nmultidict     5.2.0\r\npip           21.3.1\r\nsanic         21.12.1\r\nsanic-routing 0.7.2\r\nsetuptools    58.1.0\r\nujson         5.1.0\r\nuvicorn       0.17.0.post1\r\nuvloop        0.16.0\r\nwebsockets    10.1\r\n ```\r\n\r\n\r\n**Additional context**\r\nWorks as expected with `sanic app.app` and also with GunicornWorker.\n", "before_files": [{"content": "from __future__ import annotations\n\nimport warnings\n\nfrom typing import TYPE_CHECKING, Optional\nfrom urllib.parse import quote\n\nfrom sanic.compat import Header\nfrom sanic.exceptions import ServerError\nfrom sanic.helpers import Default\nfrom sanic.http import Stage\nfrom sanic.log import logger\nfrom sanic.models.asgi import ASGIReceive, ASGIScope, ASGISend, MockTransport\nfrom sanic.request import Request\nfrom sanic.response import BaseHTTPResponse\nfrom sanic.server import ConnInfo\nfrom sanic.server.websockets.connection import WebSocketConnection\n\n\nif TYPE_CHECKING:\n    from sanic import Sanic\n\n\nclass Lifespan:\n    def __init__(self, asgi_app: ASGIApp) -> None:\n        self.asgi_app = asgi_app\n\n        if (\n            \"server.init.before\"\n            in self.asgi_app.sanic_app.signal_router.name_index\n        ):\n            logger.debug(\n                'You have set a listener for \"before_server_start\" '\n                \"in ASGI mode. \"\n                \"It will be executed as early as possible, but not before \"\n                \"the ASGI server is started.\",\n                extra={\"verbosity\": 1},\n            )\n        if (\n            \"server.shutdown.after\"\n            in self.asgi_app.sanic_app.signal_router.name_index\n        ):\n            logger.debug(\n                'You have set a listener for \"after_server_stop\" '\n                \"in ASGI mode. \"\n                \"It will be executed as late as possible, but not after \"\n                \"the ASGI server is stopped.\",\n                extra={\"verbosity\": 1},\n            )\n\n    async def startup(self) -> None:\n        \"\"\"\n        Gather the listeners to fire on server start.\n        Because we are using a third-party server and not Sanic server, we do\n        not have access to fire anything BEFORE the server starts.\n        Therefore, we fire before_server_start and after_server_start\n        in sequence since the ASGI lifespan protocol only supports a single\n        startup event.\n        \"\"\"\n        await self.asgi_app.sanic_app._startup()\n        await self.asgi_app.sanic_app._server_event(\"init\", \"before\")\n        await self.asgi_app.sanic_app._server_event(\"init\", \"after\")\n\n        if not isinstance(self.asgi_app.sanic_app.config.USE_UVLOOP, Default):\n            warnings.warn(\n                \"You have set the USE_UVLOOP configuration option, but Sanic \"\n                \"cannot control the event loop when running in ASGI mode.\"\n                \"This option will be ignored.\"\n            )\n\n    async def shutdown(self) -> None:\n        \"\"\"\n        Gather the listeners to fire on server stop.\n        Because we are using a third-party server and not Sanic server, we do\n        not have access to fire anything AFTER the server stops.\n        Therefore, we fire before_server_stop and after_server_stop\n        in sequence since the ASGI lifespan protocol only supports a single\n        shutdown event.\n        \"\"\"\n        await self.asgi_app.sanic_app._server_event(\"shutdown\", \"before\")\n        await self.asgi_app.sanic_app._server_event(\"shutdown\", \"after\")\n\n    async def __call__(\n        self, scope: ASGIScope, receive: ASGIReceive, send: ASGISend\n    ) -> None:\n        message = await receive()\n        if message[\"type\"] == \"lifespan.startup\":\n            await self.startup()\n            await send({\"type\": \"lifespan.startup.complete\"})\n\n        message = await receive()\n        if message[\"type\"] == \"lifespan.shutdown\":\n            await self.shutdown()\n            await send({\"type\": \"lifespan.shutdown.complete\"})\n\n\nclass ASGIApp:\n    sanic_app: Sanic\n    request: Request\n    transport: MockTransport\n    lifespan: Lifespan\n    ws: Optional[WebSocketConnection]\n    stage: Stage\n    response: Optional[BaseHTTPResponse]\n\n    def __init__(self) -> None:\n        self.ws = None\n\n    @classmethod\n    async def create(\n        cls, sanic_app, scope: ASGIScope, receive: ASGIReceive, send: ASGISend\n    ) -> \"ASGIApp\":\n        instance = cls()\n        instance.sanic_app = sanic_app\n        instance.transport = MockTransport(scope, receive, send)\n        instance.transport.loop = sanic_app.loop\n        instance.stage = Stage.IDLE\n        instance.response = None\n        setattr(instance.transport, \"add_task\", sanic_app.loop.create_task)\n\n        headers = Header(\n            [\n                (key.decode(\"latin-1\"), value.decode(\"latin-1\"))\n                for key, value in scope.get(\"headers\", [])\n            ]\n        )\n        instance.lifespan = Lifespan(instance)\n\n        if scope[\"type\"] == \"lifespan\":\n            await instance.lifespan(scope, receive, send)\n        else:\n            path = (\n                scope[\"path\"][1:]\n                if scope[\"path\"].startswith(\"/\")\n                else scope[\"path\"]\n            )\n            url = \"/\".join([scope.get(\"root_path\", \"\"), quote(path)])\n            url_bytes = url.encode(\"latin-1\")\n            url_bytes += b\"?\" + scope[\"query_string\"]\n\n            if scope[\"type\"] == \"http\":\n                version = scope[\"http_version\"]\n                method = scope[\"method\"]\n            elif scope[\"type\"] == \"websocket\":\n                version = \"1.1\"\n                method = \"GET\"\n\n                instance.ws = instance.transport.create_websocket_connection(\n                    send, receive\n                )\n            else:\n                raise ServerError(\"Received unknown ASGI scope\")\n\n            request_class = sanic_app.request_class or Request\n            instance.request = request_class(\n                url_bytes,\n                headers,\n                version,\n                method,\n                instance.transport,\n                sanic_app,\n            )\n            instance.request.stream = instance\n            instance.request_body = True\n            instance.request.conn_info = ConnInfo(instance.transport)\n\n            await sanic_app.dispatch(\n                \"http.lifecycle.request\",\n                inline=True,\n                context={\"request\": instance.request},\n                fail_not_found=False,\n            )\n\n        return instance\n\n    async def read(self) -> Optional[bytes]:\n        \"\"\"\n        Read and stream the body in chunks from an incoming ASGI message.\n        \"\"\"\n        if self.stage is Stage.IDLE:\n            self.stage = Stage.REQUEST\n        message = await self.transport.receive()\n        body = message.get(\"body\", b\"\")\n        if not message.get(\"more_body\", False):\n            self.request_body = False\n            if not body:\n                return None\n        return body\n\n    async def __aiter__(self):\n        while self.request_body:\n            data = await self.read()\n            if data:\n                yield data\n\n    def respond(self, response: BaseHTTPResponse):\n        if self.stage is not Stage.HANDLER:\n            self.stage = Stage.FAILED\n            raise RuntimeError(\"Response already started\")\n        if self.response is not None:\n            self.response.stream = None\n        response.stream, self.response = self, response\n        return response\n\n    async def send(self, data, end_stream):\n        self.stage = Stage.IDLE if end_stream else Stage.RESPONSE\n        if self.response:\n            response, self.response = self.response, None\n            await self.transport.send(\n                {\n                    \"type\": \"http.response.start\",\n                    \"status\": response.status,\n                    \"headers\": response.processed_headers,\n                }\n            )\n            response_body = getattr(response, \"body\", None)\n            if response_body:\n                data = response_body + data if data else response_body\n        await self.transport.send(\n            {\n                \"type\": \"http.response.body\",\n                \"body\": data.encode() if hasattr(data, \"encode\") else data,\n                \"more_body\": not end_stream,\n            }\n        )\n\n    _asgi_single_callable = True  # We conform to ASGI 3.0 single-callable\n\n    async def __call__(self) -> None:\n        \"\"\"\n        Handle the incoming request.\n        \"\"\"\n        try:\n            self.stage = Stage.HANDLER\n            await self.sanic_app.handle_request(self.request)\n        except Exception as e:\n            try:\n                await self.sanic_app.handle_exception(self.request, e)\n            except Exception as exc:\n                await self.sanic_app.handle_exception(self.request, exc, False)\n", "path": "sanic/asgi.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport warnings\n\nfrom typing import TYPE_CHECKING, Optional\nfrom urllib.parse import quote\n\nfrom sanic.compat import Header\nfrom sanic.exceptions import ServerError\nfrom sanic.helpers import Default\nfrom sanic.http import Stage\nfrom sanic.log import error_logger, logger\nfrom sanic.models.asgi import ASGIReceive, ASGIScope, ASGISend, MockTransport\nfrom sanic.request import Request\nfrom sanic.response import BaseHTTPResponse\nfrom sanic.server import ConnInfo\nfrom sanic.server.websockets.connection import WebSocketConnection\n\n\nif TYPE_CHECKING:\n    from sanic import Sanic\n\n\nclass Lifespan:\n    def __init__(self, asgi_app: ASGIApp) -> None:\n        self.asgi_app = asgi_app\n\n        if (\n            \"server.init.before\"\n            in self.asgi_app.sanic_app.signal_router.name_index\n        ):\n            logger.debug(\n                'You have set a listener for \"before_server_start\" '\n                \"in ASGI mode. \"\n                \"It will be executed as early as possible, but not before \"\n                \"the ASGI server is started.\",\n                extra={\"verbosity\": 1},\n            )\n        if (\n            \"server.shutdown.after\"\n            in self.asgi_app.sanic_app.signal_router.name_index\n        ):\n            logger.debug(\n                'You have set a listener for \"after_server_stop\" '\n                \"in ASGI mode. \"\n                \"It will be executed as late as possible, but not after \"\n                \"the ASGI server is stopped.\",\n                extra={\"verbosity\": 1},\n            )\n\n    async def startup(self) -> None:\n        \"\"\"\n        Gather the listeners to fire on server start.\n        Because we are using a third-party server and not Sanic server, we do\n        not have access to fire anything BEFORE the server starts.\n        Therefore, we fire before_server_start and after_server_start\n        in sequence since the ASGI lifespan protocol only supports a single\n        startup event.\n        \"\"\"\n        await self.asgi_app.sanic_app._startup()\n        await self.asgi_app.sanic_app._server_event(\"init\", \"before\")\n        await self.asgi_app.sanic_app._server_event(\"init\", \"after\")\n\n        if not isinstance(self.asgi_app.sanic_app.config.USE_UVLOOP, Default):\n            warnings.warn(\n                \"You have set the USE_UVLOOP configuration option, but Sanic \"\n                \"cannot control the event loop when running in ASGI mode.\"\n                \"This option will be ignored.\"\n            )\n\n    async def shutdown(self) -> None:\n        \"\"\"\n        Gather the listeners to fire on server stop.\n        Because we are using a third-party server and not Sanic server, we do\n        not have access to fire anything AFTER the server stops.\n        Therefore, we fire before_server_stop and after_server_stop\n        in sequence since the ASGI lifespan protocol only supports a single\n        shutdown event.\n        \"\"\"\n        await self.asgi_app.sanic_app._server_event(\"shutdown\", \"before\")\n        await self.asgi_app.sanic_app._server_event(\"shutdown\", \"after\")\n\n    async def __call__(\n        self, scope: ASGIScope, receive: ASGIReceive, send: ASGISend\n    ) -> None:\n        message = await receive()\n        if message[\"type\"] == \"lifespan.startup\":\n            try:\n                await self.startup()\n            except Exception as e:\n                error_logger.exception(e)\n                await send(\n                    {\"type\": \"lifespan.startup.failed\", \"message\": str(e)}\n                )\n            else:\n                await send({\"type\": \"lifespan.startup.complete\"})\n\n        message = await receive()\n        if message[\"type\"] == \"lifespan.shutdown\":\n            try:\n                await self.shutdown()\n            except Exception as e:\n                error_logger.exception(e)\n                await send(\n                    {\"type\": \"lifespan.shutdown.failed\", \"message\": str(e)}\n                )\n            else:\n                await send({\"type\": \"lifespan.shutdown.complete\"})\n\n\nclass ASGIApp:\n    sanic_app: Sanic\n    request: Request\n    transport: MockTransport\n    lifespan: Lifespan\n    ws: Optional[WebSocketConnection]\n    stage: Stage\n    response: Optional[BaseHTTPResponse]\n\n    def __init__(self) -> None:\n        self.ws = None\n\n    @classmethod\n    async def create(\n        cls, sanic_app, scope: ASGIScope, receive: ASGIReceive, send: ASGISend\n    ) -> \"ASGIApp\":\n        instance = cls()\n        instance.sanic_app = sanic_app\n        instance.transport = MockTransport(scope, receive, send)\n        instance.transport.loop = sanic_app.loop\n        instance.stage = Stage.IDLE\n        instance.response = None\n        setattr(instance.transport, \"add_task\", sanic_app.loop.create_task)\n\n        headers = Header(\n            [\n                (key.decode(\"latin-1\"), value.decode(\"latin-1\"))\n                for key, value in scope.get(\"headers\", [])\n            ]\n        )\n        instance.lifespan = Lifespan(instance)\n\n        if scope[\"type\"] == \"lifespan\":\n            await instance.lifespan(scope, receive, send)\n        else:\n            path = (\n                scope[\"path\"][1:]\n                if scope[\"path\"].startswith(\"/\")\n                else scope[\"path\"]\n            )\n            url = \"/\".join([scope.get(\"root_path\", \"\"), quote(path)])\n            url_bytes = url.encode(\"latin-1\")\n            url_bytes += b\"?\" + scope[\"query_string\"]\n\n            if scope[\"type\"] == \"http\":\n                version = scope[\"http_version\"]\n                method = scope[\"method\"]\n            elif scope[\"type\"] == \"websocket\":\n                version = \"1.1\"\n                method = \"GET\"\n\n                instance.ws = instance.transport.create_websocket_connection(\n                    send, receive\n                )\n            else:\n                raise ServerError(\"Received unknown ASGI scope\")\n\n            request_class = sanic_app.request_class or Request\n            instance.request = request_class(\n                url_bytes,\n                headers,\n                version,\n                method,\n                instance.transport,\n                sanic_app,\n            )\n            instance.request.stream = instance\n            instance.request_body = True\n            instance.request.conn_info = ConnInfo(instance.transport)\n\n            await sanic_app.dispatch(\n                \"http.lifecycle.request\",\n                inline=True,\n                context={\"request\": instance.request},\n                fail_not_found=False,\n            )\n\n        return instance\n\n    async def read(self) -> Optional[bytes]:\n        \"\"\"\n        Read and stream the body in chunks from an incoming ASGI message.\n        \"\"\"\n        if self.stage is Stage.IDLE:\n            self.stage = Stage.REQUEST\n        message = await self.transport.receive()\n        body = message.get(\"body\", b\"\")\n        if not message.get(\"more_body\", False):\n            self.request_body = False\n            if not body:\n                return None\n        return body\n\n    async def __aiter__(self):\n        while self.request_body:\n            data = await self.read()\n            if data:\n                yield data\n\n    def respond(self, response: BaseHTTPResponse):\n        if self.stage is not Stage.HANDLER:\n            self.stage = Stage.FAILED\n            raise RuntimeError(\"Response already started\")\n        if self.response is not None:\n            self.response.stream = None\n        response.stream, self.response = self, response\n        return response\n\n    async def send(self, data, end_stream):\n        self.stage = Stage.IDLE if end_stream else Stage.RESPONSE\n        if self.response:\n            response, self.response = self.response, None\n            await self.transport.send(\n                {\n                    \"type\": \"http.response.start\",\n                    \"status\": response.status,\n                    \"headers\": response.processed_headers,\n                }\n            )\n            response_body = getattr(response, \"body\", None)\n            if response_body:\n                data = response_body + data if data else response_body\n        await self.transport.send(\n            {\n                \"type\": \"http.response.body\",\n                \"body\": data.encode() if hasattr(data, \"encode\") else data,\n                \"more_body\": not end_stream,\n            }\n        )\n\n    _asgi_single_callable = True  # We conform to ASGI 3.0 single-callable\n\n    async def __call__(self) -> None:\n        \"\"\"\n        Handle the incoming request.\n        \"\"\"\n        try:\n            self.stage = Stage.HANDLER\n            await self.sanic_app.handle_request(self.request)\n        except Exception as e:\n            try:\n                await self.sanic_app.handle_exception(self.request, e)\n            except Exception as exc:\n                await self.sanic_app.handle_exception(self.request, exc, False)\n", "path": "sanic/asgi.py"}]}