| 372 | |
| 373 | |
| 374 | class RequestResponseCycle: |
| 375 | def __init__( |
| 376 | self, |
| 377 | scope: HTTPScope, |
| 378 | conn: h11.Connection, |
| 379 | transport: asyncio.Transport, |
| 380 | flow: FlowControl, |
| 381 | logger: logging.Logger, |
| 382 | access_logger: logging.Logger, |
| 383 | access_log: bool, |
| 384 | default_headers: list[tuple[bytes, bytes]], |
| 385 | message_event: asyncio.Event, |
| 386 | on_response: Callable[..., None], |
| 387 | ) -> None: |
| 388 | self.scope = scope |
| 389 | self.conn = conn |
| 390 | self.transport = transport |
| 391 | self.flow = flow |
| 392 | self.logger = logger |
| 393 | self.access_logger = access_logger |
| 394 | self.access_log = access_log |
| 395 | self.default_headers = default_headers |
| 396 | self.message_event = message_event |
| 397 | self.on_response = on_response |
| 398 | |
| 399 | # Connection state |
| 400 | self.disconnected = False |
| 401 | self.keep_alive = True |
| 402 | self.waiting_for_100_continue = conn.they_are_waiting_for_100_continue |
| 403 | |
| 404 | # Request state |
| 405 | self.body = bytearray() |
| 406 | self.more_body = True |
| 407 | |
| 408 | # Response state |
| 409 | self.response_started = False |
| 410 | self.response_complete = False |
| 411 | |
| 412 | # ASGI exception wrapper |
| 413 | async def run_asgi(self, app: ASGI3Application) -> None: |
| 414 | try: |
| 415 | result = await app( # type: ignore[func-returns-value] |
| 416 | self.scope, self.receive, self.send |
| 417 | ) |
| 418 | except BaseException as exc: |
| 419 | msg = "Exception in ASGI application\n" |
| 420 | self.logger.error(msg, exc_info=exc) |
| 421 | if not self.response_started: |
| 422 | await self.send_500_response() |
| 423 | else: |
| 424 | self.transport.close() |
| 425 | else: |
| 426 | if result is not None: |
| 427 | msg = "ASGI callable should return None, but returned '%s'." |
| 428 | self.logger.error(msg, result) |
| 429 | self.transport.close() |
| 430 | elif not self.response_started and not self.disconnected: |
| 431 | msg = "ASGI callable returned without starting response." |