| 30 | |
| 31 | |
| 32 | class IdentityResponder: |
| 33 | content_encoding: str |
| 34 | |
| 35 | def __init__(self, app: ASGIApp, minimum_size: int) -> None: |
| 36 | self.app = app |
| 37 | self.minimum_size = minimum_size |
| 38 | self.send: Send = unattached_send |
| 39 | self.initial_message: Message = {} |
| 40 | self.started = False |
| 41 | self.content_encoding_set = False |
| 42 | self.content_type_is_excluded = False |
| 43 | |
| 44 | async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: |
| 45 | self.send = send |
| 46 | await self.app(scope, receive, self.send_with_compression) |
| 47 | |
| 48 | async def send_with_compression(self, message: Message) -> None: |
| 49 | message_type = message["type"] |
| 50 | if message_type == "http.response.start": |
| 51 | # Don't send the initial message until we've determined how to |
| 52 | # modify the outgoing headers correctly. |
| 53 | self.initial_message = message |
| 54 | headers = Headers(raw=self.initial_message["headers"]) |
| 55 | self.content_encoding_set = "content-encoding" in headers |
| 56 | self.content_type_is_excluded = headers.get("content-type", "").startswith(DEFAULT_EXCLUDED_CONTENT_TYPES) |
| 57 | elif message_type == "http.response.body" and (self.content_encoding_set or self.content_type_is_excluded): |
| 58 | if not self.started: |
| 59 | self.started = True |
| 60 | await self.send(self.initial_message) |
| 61 | await self.send(message) |
| 62 | elif message_type == "http.response.body" and not self.started: |
| 63 | self.started = True |
| 64 | body = message.get("body", b"") |
| 65 | more_body = message.get("more_body", False) |
| 66 | if len(body) < self.minimum_size and not more_body: |
| 67 | # Don't apply compression to small outgoing responses. |
| 68 | await self.send(self.initial_message) |
| 69 | await self.send(message) |
| 70 | elif not more_body: |
| 71 | # Standard response. |
| 72 | body = self.apply_compression(body, more_body=False) |
| 73 | |
| 74 | headers = MutableHeaders(raw=self.initial_message["headers"]) |
| 75 | headers.add_vary_header("Accept-Encoding") |
| 76 | if body != message["body"]: |
| 77 | headers["Content-Encoding"] = self.content_encoding |
| 78 | headers["Content-Length"] = str(len(body)) |
| 79 | message["body"] = body |
| 80 | |
| 81 | await self.send(self.initial_message) |
| 82 | await self.send(message) |
| 83 | else: |
| 84 | # Initial body in streaming response. |
| 85 | body = self.apply_compression(body, more_body=True) |
| 86 | |
| 87 | headers = MutableHeaders(raw=self.initial_message["headers"]) |
| 88 | headers.add_vary_header("Accept-Encoding") |
| 89 | if body != message["body"]: |