| 32 | self._wrapped_rc_stream = self.stream() |
| 33 | |
| 34 | async def wrapped_receive(self) -> Message: |
| 35 | # wrapped_rcv state 1: disconnected |
| 36 | if self._wrapped_rcv_disconnected: |
| 37 | # we've already sent a disconnect to the downstream app |
| 38 | # we don't need to wait to get another one |
| 39 | # (although most ASGI servers will just keep sending it) |
| 40 | return {"type": "http.disconnect"} |
| 41 | # wrapped_rcv state 1: consumed but not yet disconnected |
| 42 | if self._wrapped_rcv_consumed: |
| 43 | # since the downstream app has consumed us all that is left |
| 44 | # is to send it a disconnect |
| 45 | if self._is_disconnected: |
| 46 | # the middleware has already seen the disconnect |
| 47 | # since we know the client is disconnected no need to wait |
| 48 | # for the message |
| 49 | self._wrapped_rcv_disconnected = True |
| 50 | return {"type": "http.disconnect"} |
| 51 | # we don't know yet if the client is disconnected or not |
| 52 | # so we'll wait until we get that message |
| 53 | msg = await self.receive() |
| 54 | if msg["type"] != "http.disconnect": # pragma: no cover |
| 55 | # at this point a disconnect is all that we should be receiving |
| 56 | # if we get something else, things went wrong somewhere |
| 57 | raise RuntimeError(f"Unexpected message received: {msg['type']}") |
| 58 | self._wrapped_rcv_disconnected = True |
| 59 | return msg |
| 60 | |
| 61 | # wrapped_rcv state 3: not yet consumed |
| 62 | if getattr(self, "_body", None) is not None: |
| 63 | # body() was called, we return it even if the client disconnected |
| 64 | self._wrapped_rcv_consumed = True |
| 65 | return { |
| 66 | "type": "http.request", |
| 67 | "body": self._body, |
| 68 | "more_body": False, |
| 69 | } |
| 70 | elif self._stream_consumed: |
| 71 | # stream() was called to completion |
| 72 | # return an empty body so that downstream apps don't hang |
| 73 | # waiting for a disconnect |
| 74 | self._wrapped_rcv_consumed = True |
| 75 | return { |
| 76 | "type": "http.request", |
| 77 | "body": b"", |
| 78 | "more_body": False, |
| 79 | } |
| 80 | else: |
| 81 | # body() was never called and stream() wasn't consumed |
| 82 | try: |
| 83 | stream = self.stream() |
| 84 | chunk = await stream.__anext__() |
| 85 | self._wrapped_rcv_consumed = self._stream_consumed |
| 86 | return { |
| 87 | "type": "http.request", |
| 88 | "body": chunk, |
| 89 | "more_body": not self._stream_consumed, |
| 90 | } |
| 91 | except ClientDisconnect: |