We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Bug: `FileResponse` doesn't set `content-encoding` headers on gzip/brotli compressed files
### Description

When using `StaticFilesConfig` to serve compressed files (think `styles.css.gz`), Litestar will happily serve the file and even properly infer the mimetype, but won't set the correct `content-encoding` header required by the browser.

I will provide a PR with a test.

### URL to code causing the issue

_No response_

### MCVE

_No response_

### Steps to reproduce

_No response_

### Screenshots

```bash
"![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"
```


### Logs

_No response_

### Litestar Version

1.51.10

### Platform

- [X] Linux
- [ ] Mac
- [ ] Windows
- [ ] Other (Please specify in the description above)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `litestar/response/file.py`
Content:
```
1 from __future__ import annotations
2 
3 from email.utils import formatdate
4 from inspect import iscoroutine
5 from mimetypes import guess_type
6 from typing import TYPE_CHECKING, Any, AsyncGenerator, Coroutine, Literal, cast
7 from urllib.parse import quote
8 from zlib import adler32
9 
10 from litestar.constants import ONE_MEGABYTE
11 from litestar.exceptions import ImproperlyConfiguredException
12 from litestar.file_system import BaseLocalFileSystem, FileSystemAdapter
13 from litestar.response.streaming import StreamingResponse
14 from litestar.status_codes import HTTP_200_OK
15 
16 __all__ = ("FileResponse", "async_file_iterator", "create_etag_for_file")
17 
18 
19 if TYPE_CHECKING:
20     from os import PathLike
21     from os import stat_result as stat_result_type
22 
23     from anyio import Path
24 
25     from litestar.background_tasks import BackgroundTask, BackgroundTasks
26     from litestar.datastructures.headers import ETag
27     from litestar.enums import MediaType
28     from litestar.types import HTTPResponseBodyEvent, PathType, Receive, ResponseCookies, Send
29     from litestar.types.file_types import FileInfo, FileSystemProtocol
30 
31 
32 async def async_file_iterator(
33     file_path: PathType, chunk_size: int, adapter: FileSystemAdapter
34 ) -> AsyncGenerator[bytes, None]:
35     """Return an async that asynchronously reads a file and yields its chunks.
36 
37     Args:
38         file_path: A path to a file.
39         chunk_size: The chunk file to use.
40         adapter: File system adapter class.
41         adapter: File system adapter class.
42 
43     Returns:
44         An async generator.
45     """
46     async with await adapter.open(file_path) as file:
47         while chunk := await file.read(chunk_size):
48             yield chunk
49 
50 
51 def create_etag_for_file(path: PathType, modified_time: float, file_size: int) -> str:
52     """Create an etag.
53 
54     Notes:
55         - Function is derived from flask.
56 
57     Returns:
58         An etag.
59     """
60     check = adler32(str(path).encode("utf-8")) & 0xFFFFFFFF
61     return f'"{modified_time}-{file_size}-{check}"'
62 
63 
64 class FileResponse(StreamingResponse):
65     """A response, streaming a file as response body."""
66 
67     __slots__ = (
68         "chunk_size",
69         "content_disposition_type",
70         "etag",
71         "file_path",
72         "filename",
73         "adapter",
74         "file_info",
75     )
76 
77     def __init__(
78         self,
79         path: str | PathLike | Path,
80         *,
81         background: BackgroundTask | BackgroundTasks | None = None,
82         chunk_size: int = ONE_MEGABYTE,
83         content_disposition_type: Literal["attachment", "inline"] = "attachment",
84         cookies: ResponseCookies | None = None,
85         encoding: str = "utf-8",
86         etag: ETag | None = None,
87         file_system: FileSystemProtocol | None = None,
88         filename: str | None = None,
89         file_info: FileInfo | None = None,
90         headers: dict[str, Any] | None = None,
91         is_head_response: bool = False,
92         media_type: Literal[MediaType.TEXT] | str | None = None,
93         stat_result: stat_result_type | None = None,
94         status_code: int = HTTP_200_OK,
95     ) -> None:
96         """Initialize ``FileResponse``
97 
98         Notes:
99             - This class extends the :class:`StreamingResponse <.response.StreamingResponse>` class.
100 
101         Args:
102             path: A file path in one of the supported formats.
103             status_code: An HTTP status code.
104             media_type: A value for the response ``Content-Type`` header. If not provided, the value will be either
105                 derived from the filename if provided and supported by the stdlib, or will default to
106                 ``application/octet-stream``.
107             background: A :class:`BackgroundTask <.background_tasks.BackgroundTask>` instance or
108                 :class:`BackgroundTasks <.background_tasks.BackgroundTasks>` to execute after the response is finished.
109                 Defaults to None.
110             headers: A string keyed dictionary of response headers. Header keys are insensitive.
111             cookies: A list of :class:`Cookie <.datastructures.Cookie>` instances to be set under the response
112                 ``Set-Cookie`` header.
113             encoding: The encoding to be used for the response headers.
114             is_head_response: Whether the response should send only the headers ("head" request) or also the content.
115             filename: An optional filename to set in the header.
116             stat_result: An optional result of calling :func:os.stat:. If not provided, this will be done by the
117                 response constructor.
118             chunk_size: The chunk sizes to use when streaming the file. Defaults to 1MB.
119             content_disposition_type: The type of the ``Content-Disposition``. Either ``inline`` or ``attachment``.
120             etag: An optional :class:`ETag <.datastructures.ETag>` instance. If not provided, an etag will be
121                 generated.
122             file_system: An implementation of the :class:`FileSystemProtocol <.types.FileSystemProtocol>`. If provided
123                 it will be used to load the file.
124             file_info: The output of calling :meth:`file_system.info <types.FileSystemProtocol.info>`, equivalent to
125                 providing an :class:`os.stat_result`.
126         """
127         if not media_type:
128             mimetype, _ = guess_type(filename) if filename else (None, None)
129             media_type = mimetype or "application/octet-stream"
130 
131         self.chunk_size = chunk_size
132         self.content_disposition_type = content_disposition_type
133         self.etag = etag
134         self.file_path = path
135         self.filename = filename or ""
136         self.adapter = FileSystemAdapter(file_system or BaseLocalFileSystem())
137 
138         super().__init__(
139             content=async_file_iterator(file_path=path, chunk_size=chunk_size, adapter=self.adapter),
140             status_code=status_code,
141             media_type=media_type,
142             background=background,
143             headers=headers,
144             cookies=cookies,
145             encoding=encoding,
146             is_head_response=is_head_response,
147         )
148 
149         if file_info:
150             self.file_info: FileInfo | Coroutine[Any, Any, FileInfo] = file_info
151         elif stat_result:
152             self.file_info = self.adapter.parse_stat_result(result=stat_result, path=path)
153         else:
154             self.file_info = self.adapter.info(self.file_path)
155 
156     @property
157     def content_disposition(self) -> str:
158         """Content disposition.
159 
160         Returns:
161             A value for the ``Content-Disposition`` header.
162         """
163         quoted_filename = quote(self.filename)
164         is_utf8 = quoted_filename == self.filename
165         if is_utf8:
166             return f'{self.content_disposition_type}; filename="{self.filename}"'
167         return f"{self.content_disposition_type}; filename*=utf-8''{quoted_filename}"
168 
169     @property
170     def content_length(self) -> int:
171         """Content length of the response if applicable.
172 
173         Returns:
174             Returns the value of :attr:`stat_result.st_size <os.stat_result.st_size>` to populate the ``Content-Length``
175                 header.
176         """
177         if isinstance(self.file_info, dict):
178             return self.file_info["size"]
179         return 0
180 
181     async def send_body(self, send: Send, receive: Receive) -> None:
182         """Emit a stream of events correlating with the response body.
183 
184         Args:
185             send: The ASGI send function.
186             receive: The ASGI receive function.
187 
188         Returns:
189             None
190         """
191         if self.chunk_size < self.content_length:
192             await super().send_body(send=send, receive=receive)
193             return
194 
195         async with await self.adapter.open(self.file_path) as file:
196             body_event: HTTPResponseBodyEvent = {
197                 "type": "http.response.body",
198                 "body": await file.read(),
199                 "more_body": False,
200             }
201             await send(body_event)
202 
203     async def start_response(self, send: Send) -> None:
204         """Emit the start event of the response. This event includes the headers and status codes.
205 
206         Args:
207             send: The ASGI send function.
208 
209         Returns:
210             None
211         """
212         try:
213             fs_info = self.file_info = cast(
214                 "FileInfo", (await self.file_info if iscoroutine(self.file_info) else self.file_info)
215             )
216         except FileNotFoundError as e:
217             raise ImproperlyConfiguredException(f"{self.file_path} does not exist") from e
218 
219         if fs_info["type"] != "file":
220             raise ImproperlyConfiguredException(f"{self.file_path} is not a file")
221 
222         self.set_header("last-modified", formatdate(fs_info["mtime"], usegmt=True))
223         self.set_header("content-disposition", self.content_disposition)
224         self.set_etag(
225             self.etag
226             or create_etag_for_file(path=self.file_path, modified_time=fs_info["mtime"], file_size=fs_info["size"])
227         )
228 
229         await super().start_response(send=send)
230
```
--- 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/litestar/response/file.py b/litestar/response/file.py
--- a/litestar/response/file.py
+++ b/litestar/response/file.py
@@ -2,7 +2,7 @@
 
 from email.utils import formatdate
 from inspect import iscoroutine
-from mimetypes import guess_type
+from mimetypes import encodings_map, guess_type
 from typing import TYPE_CHECKING, Any, AsyncGenerator, Coroutine, Literal, cast
 from urllib.parse import quote
 from zlib import adler32
@@ -28,6 +28,9 @@
     from litestar.types import HTTPResponseBodyEvent, PathType, Receive, ResponseCookies, Send
     from litestar.types.file_types import FileInfo, FileSystemProtocol
 
+# brotli not supported in 'mimetypes.encodings_map' until py 3.9.
+encodings_map[".br"] = "br"
+
 
 async def async_file_iterator(
     file_path: PathType, chunk_size: int, adapter: FileSystemAdapter
@@ -125,8 +128,11 @@
                 providing an :class:`os.stat_result`.
         """
         if not media_type:
-            mimetype, _ = guess_type(filename) if filename else (None, None)
+            mimetype, content_encoding = guess_type(filename) if filename else (None, None)
             media_type = mimetype or "application/octet-stream"
+            if content_encoding is not None:
+                headers = headers or {}
+                headers.update({"content-encoding": content_encoding})
 
         self.chunk_size = chunk_size
         self.content_disposition_type = content_disposition_type

{"golden_diff": "diff --git a/litestar/response/file.py b/litestar/response/file.py\n--- a/litestar/response/file.py\n+++ b/litestar/response/file.py\n@@ -2,7 +2,7 @@\n \n from email.utils import formatdate\n from inspect import iscoroutine\n-from mimetypes import guess_type\n+from mimetypes import encodings_map, guess_type\n from typing import TYPE_CHECKING, Any, AsyncGenerator, Coroutine, Literal, cast\n from urllib.parse import quote\n from zlib import adler32\n@@ -28,6 +28,9 @@\n     from litestar.types import HTTPResponseBodyEvent, PathType, Receive, ResponseCookies, Send\n     from litestar.types.file_types import FileInfo, FileSystemProtocol\n \n+# brotli not supported in 'mimetypes.encodings_map' until py 3.9.\n+encodings_map[\".br\"] = \"br\"\n+\n \n async def async_file_iterator(\n     file_path: PathType, chunk_size: int, adapter: FileSystemAdapter\n@@ -125,8 +128,11 @@\n                 providing an :class:`os.stat_result`.\n         \"\"\"\n         if not media_type:\n-            mimetype, _ = guess_type(filename) if filename else (None, None)\n+            mimetype, content_encoding = guess_type(filename) if filename else (None, None)\n             media_type = mimetype or \"application/octet-stream\"\n+            if content_encoding is not None:\n+                headers = headers or {}\n+                headers.update({\"content-encoding\": content_encoding})\n \n         self.chunk_size = chunk_size\n         self.content_disposition_type = content_disposition_type\n", "issue": "Bug: `FileResponse` doesn't set `content-encoding` headers on gzip/brotli compressed files\n### Description\n\nWhen using `StaticFilesConfig` to serve compressed files (think `styles.css.gz`), Litestar will happily serve the file and even properly infer the mimetype, but won't set the correct `content-encoding` header required by the browser.\r\n\r\nI will provide a PR with a test.\n\n### URL to code causing the issue\n\n_No response_\n\n### MCVE\n\n_No response_\n\n### Steps to reproduce\n\n_No response_\n\n### Screenshots\n\n```bash\n\"![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)\"\n```\n\n\n### Logs\n\n_No response_\n\n### Litestar Version\n\n1.51.10\n\n### Platform\n\n- [X] Linux\n- [ ] Mac\n- [ ] Windows\n- [ ] Other (Please specify in the description above)\n", "before_files": [{"content": "from __future__ import annotations\n\nfrom email.utils import formatdate\nfrom inspect import iscoroutine\nfrom mimetypes import guess_type\nfrom typing import TYPE_CHECKING, Any, AsyncGenerator, Coroutine, Literal, cast\nfrom urllib.parse import quote\nfrom zlib import adler32\n\nfrom litestar.constants import ONE_MEGABYTE\nfrom litestar.exceptions import ImproperlyConfiguredException\nfrom litestar.file_system import BaseLocalFileSystem, FileSystemAdapter\nfrom litestar.response.streaming import StreamingResponse\nfrom litestar.status_codes import HTTP_200_OK\n\n__all__ = (\"FileResponse\", \"async_file_iterator\", \"create_etag_for_file\")\n\n\nif TYPE_CHECKING:\n    from os import PathLike\n    from os import stat_result as stat_result_type\n\n    from anyio import Path\n\n    from litestar.background_tasks import BackgroundTask, BackgroundTasks\n    from litestar.datastructures.headers import ETag\n    from litestar.enums import MediaType\n    from litestar.types import HTTPResponseBodyEvent, PathType, Receive, ResponseCookies, Send\n    from litestar.types.file_types import FileInfo, FileSystemProtocol\n\n\nasync def async_file_iterator(\n    file_path: PathType, chunk_size: int, adapter: FileSystemAdapter\n) -> AsyncGenerator[bytes, None]:\n    \"\"\"Return an async that asynchronously reads a file and yields its chunks.\n\n    Args:\n        file_path: A path to a file.\n        chunk_size: The chunk file to use.\n        adapter: File system adapter class.\n        adapter: File system adapter class.\n\n    Returns:\n        An async generator.\n    \"\"\"\n    async with await adapter.open(file_path) as file:\n        while chunk := await file.read(chunk_size):\n            yield chunk\n\n\ndef create_etag_for_file(path: PathType, modified_time: float, file_size: int) -> str:\n    \"\"\"Create an etag.\n\n    Notes:\n        - Function is derived from flask.\n\n    Returns:\n        An etag.\n    \"\"\"\n    check = adler32(str(path).encode(\"utf-8\")) & 0xFFFFFFFF\n    return f'\"{modified_time}-{file_size}-{check}\"'\n\n\nclass FileResponse(StreamingResponse):\n    \"\"\"A response, streaming a file as response body.\"\"\"\n\n    __slots__ = (\n        \"chunk_size\",\n        \"content_disposition_type\",\n        \"etag\",\n        \"file_path\",\n        \"filename\",\n        \"adapter\",\n        \"file_info\",\n    )\n\n    def __init__(\n        self,\n        path: str | PathLike | Path,\n        *,\n        background: BackgroundTask | BackgroundTasks | None = None,\n        chunk_size: int = ONE_MEGABYTE,\n        content_disposition_type: Literal[\"attachment\", \"inline\"] = \"attachment\",\n        cookies: ResponseCookies | None = None,\n        encoding: str = \"utf-8\",\n        etag: ETag | None = None,\n        file_system: FileSystemProtocol | None = None,\n        filename: str | None = None,\n        file_info: FileInfo | None = None,\n        headers: dict[str, Any] | None = None,\n        is_head_response: bool = False,\n        media_type: Literal[MediaType.TEXT] | str | None = None,\n        stat_result: stat_result_type | None = None,\n        status_code: int = HTTP_200_OK,\n    ) -> None:\n        \"\"\"Initialize ``FileResponse``\n\n        Notes:\n            - This class extends the :class:`StreamingResponse <.response.StreamingResponse>` class.\n\n        Args:\n            path: A file path in one of the supported formats.\n            status_code: An HTTP status code.\n            media_type: A value for the response ``Content-Type`` header. If not provided, the value will be either\n                derived from the filename if provided and supported by the stdlib, or will default to\n                ``application/octet-stream``.\n            background: A :class:`BackgroundTask <.background_tasks.BackgroundTask>` instance or\n                :class:`BackgroundTasks <.background_tasks.BackgroundTasks>` to execute after the response is finished.\n                Defaults to None.\n            headers: A string keyed dictionary of response headers. Header keys are insensitive.\n            cookies: A list of :class:`Cookie <.datastructures.Cookie>` instances to be set under the response\n                ``Set-Cookie`` header.\n            encoding: The encoding to be used for the response headers.\n            is_head_response: Whether the response should send only the headers (\"head\" request) or also the content.\n            filename: An optional filename to set in the header.\n            stat_result: An optional result of calling :func:os.stat:. If not provided, this will be done by the\n                response constructor.\n            chunk_size: The chunk sizes to use when streaming the file. Defaults to 1MB.\n            content_disposition_type: The type of the ``Content-Disposition``. Either ``inline`` or ``attachment``.\n            etag: An optional :class:`ETag <.datastructures.ETag>` instance. If not provided, an etag will be\n                generated.\n            file_system: An implementation of the :class:`FileSystemProtocol <.types.FileSystemProtocol>`. If provided\n                it will be used to load the file.\n            file_info: The output of calling :meth:`file_system.info <types.FileSystemProtocol.info>`, equivalent to\n                providing an :class:`os.stat_result`.\n        \"\"\"\n        if not media_type:\n            mimetype, _ = guess_type(filename) if filename else (None, None)\n            media_type = mimetype or \"application/octet-stream\"\n\n        self.chunk_size = chunk_size\n        self.content_disposition_type = content_disposition_type\n        self.etag = etag\n        self.file_path = path\n        self.filename = filename or \"\"\n        self.adapter = FileSystemAdapter(file_system or BaseLocalFileSystem())\n\n        super().__init__(\n            content=async_file_iterator(file_path=path, chunk_size=chunk_size, adapter=self.adapter),\n            status_code=status_code,\n            media_type=media_type,\n            background=background,\n            headers=headers,\n            cookies=cookies,\n            encoding=encoding,\n            is_head_response=is_head_response,\n        )\n\n        if file_info:\n            self.file_info: FileInfo | Coroutine[Any, Any, FileInfo] = file_info\n        elif stat_result:\n            self.file_info = self.adapter.parse_stat_result(result=stat_result, path=path)\n        else:\n            self.file_info = self.adapter.info(self.file_path)\n\n    @property\n    def content_disposition(self) -> str:\n        \"\"\"Content disposition.\n\n        Returns:\n            A value for the ``Content-Disposition`` header.\n        \"\"\"\n        quoted_filename = quote(self.filename)\n        is_utf8 = quoted_filename == self.filename\n        if is_utf8:\n            return f'{self.content_disposition_type}; filename=\"{self.filename}\"'\n        return f\"{self.content_disposition_type}; filename*=utf-8''{quoted_filename}\"\n\n    @property\n    def content_length(self) -> int:\n        \"\"\"Content length of the response if applicable.\n\n        Returns:\n            Returns the value of :attr:`stat_result.st_size <os.stat_result.st_size>` to populate the ``Content-Length``\n                header.\n        \"\"\"\n        if isinstance(self.file_info, dict):\n            return self.file_info[\"size\"]\n        return 0\n\n    async def send_body(self, send: Send, receive: Receive) -> None:\n        \"\"\"Emit a stream of events correlating with the response body.\n\n        Args:\n            send: The ASGI send function.\n            receive: The ASGI receive function.\n\n        Returns:\n            None\n        \"\"\"\n        if self.chunk_size < self.content_length:\n            await super().send_body(send=send, receive=receive)\n            return\n\n        async with await self.adapter.open(self.file_path) as file:\n            body_event: HTTPResponseBodyEvent = {\n                \"type\": \"http.response.body\",\n                \"body\": await file.read(),\n                \"more_body\": False,\n            }\n            await send(body_event)\n\n    async def start_response(self, send: Send) -> None:\n        \"\"\"Emit the start event of the response. This event includes the headers and status codes.\n\n        Args:\n            send: The ASGI send function.\n\n        Returns:\n            None\n        \"\"\"\n        try:\n            fs_info = self.file_info = cast(\n                \"FileInfo\", (await self.file_info if iscoroutine(self.file_info) else self.file_info)\n            )\n        except FileNotFoundError as e:\n            raise ImproperlyConfiguredException(f\"{self.file_path} does not exist\") from e\n\n        if fs_info[\"type\"] != \"file\":\n            raise ImproperlyConfiguredException(f\"{self.file_path} is not a file\")\n\n        self.set_header(\"last-modified\", formatdate(fs_info[\"mtime\"], usegmt=True))\n        self.set_header(\"content-disposition\", self.content_disposition)\n        self.set_etag(\n            self.etag\n            or create_etag_for_file(path=self.file_path, modified_time=fs_info[\"mtime\"], file_size=fs_info[\"size\"])\n        )\n\n        await super().start_response(send=send)\n", "path": "litestar/response/file.py"}], "after_files": [{"content": "from __future__ import annotations\n\nfrom email.utils import formatdate\nfrom inspect import iscoroutine\nfrom mimetypes import encodings_map, guess_type\nfrom typing import TYPE_CHECKING, Any, AsyncGenerator, Coroutine, Literal, cast\nfrom urllib.parse import quote\nfrom zlib import adler32\n\nfrom litestar.constants import ONE_MEGABYTE\nfrom litestar.exceptions import ImproperlyConfiguredException\nfrom litestar.file_system import BaseLocalFileSystem, FileSystemAdapter\nfrom litestar.response.streaming import StreamingResponse\nfrom litestar.status_codes import HTTP_200_OK\n\n__all__ = (\"FileResponse\", \"async_file_iterator\", \"create_etag_for_file\")\n\n\nif TYPE_CHECKING:\n    from os import PathLike\n    from os import stat_result as stat_result_type\n\n    from anyio import Path\n\n    from litestar.background_tasks import BackgroundTask, BackgroundTasks\n    from litestar.datastructures.headers import ETag\n    from litestar.enums import MediaType\n    from litestar.types import HTTPResponseBodyEvent, PathType, Receive, ResponseCookies, Send\n    from litestar.types.file_types import FileInfo, FileSystemProtocol\n\n# brotli not supported in 'mimetypes.encodings_map' until py 3.9.\nencodings_map[\".br\"] = \"br\"\n\n\nasync def async_file_iterator(\n    file_path: PathType, chunk_size: int, adapter: FileSystemAdapter\n) -> AsyncGenerator[bytes, None]:\n    \"\"\"Return an async that asynchronously reads a file and yields its chunks.\n\n    Args:\n        file_path: A path to a file.\n        chunk_size: The chunk file to use.\n        adapter: File system adapter class.\n        adapter: File system adapter class.\n\n    Returns:\n        An async generator.\n    \"\"\"\n    async with await adapter.open(file_path) as file:\n        while chunk := await file.read(chunk_size):\n            yield chunk\n\n\ndef create_etag_for_file(path: PathType, modified_time: float, file_size: int) -> str:\n    \"\"\"Create an etag.\n\n    Notes:\n        - Function is derived from flask.\n\n    Returns:\n        An etag.\n    \"\"\"\n    check = adler32(str(path).encode(\"utf-8\")) & 0xFFFFFFFF\n    return f'\"{modified_time}-{file_size}-{check}\"'\n\n\nclass FileResponse(StreamingResponse):\n    \"\"\"A response, streaming a file as response body.\"\"\"\n\n    __slots__ = (\n        \"chunk_size\",\n        \"content_disposition_type\",\n        \"etag\",\n        \"file_path\",\n        \"filename\",\n        \"adapter\",\n        \"file_info\",\n    )\n\n    def __init__(\n        self,\n        path: str | PathLike | Path,\n        *,\n        background: BackgroundTask | BackgroundTasks | None = None,\n        chunk_size: int = ONE_MEGABYTE,\n        content_disposition_type: Literal[\"attachment\", \"inline\"] = \"attachment\",\n        cookies: ResponseCookies | None = None,\n        encoding: str = \"utf-8\",\n        etag: ETag | None = None,\n        file_system: FileSystemProtocol | None = None,\n        filename: str | None = None,\n        file_info: FileInfo | None = None,\n        headers: dict[str, Any] | None = None,\n        is_head_response: bool = False,\n        media_type: Literal[MediaType.TEXT] | str | None = None,\n        stat_result: stat_result_type | None = None,\n        status_code: int = HTTP_200_OK,\n    ) -> None:\n        \"\"\"Initialize ``FileResponse``\n\n        Notes:\n            - This class extends the :class:`StreamingResponse <.response.StreamingResponse>` class.\n\n        Args:\n            path: A file path in one of the supported formats.\n            status_code: An HTTP status code.\n            media_type: A value for the response ``Content-Type`` header. If not provided, the value will be either\n                derived from the filename if provided and supported by the stdlib, or will default to\n                ``application/octet-stream``.\n            background: A :class:`BackgroundTask <.background_tasks.BackgroundTask>` instance or\n                :class:`BackgroundTasks <.background_tasks.BackgroundTasks>` to execute after the response is finished.\n                Defaults to None.\n            headers: A string keyed dictionary of response headers. Header keys are insensitive.\n            cookies: A list of :class:`Cookie <.datastructures.Cookie>` instances to be set under the response\n                ``Set-Cookie`` header.\n            encoding: The encoding to be used for the response headers.\n            is_head_response: Whether the response should send only the headers (\"head\" request) or also the content.\n            filename: An optional filename to set in the header.\n            stat_result: An optional result of calling :func:os.stat:. If not provided, this will be done by the\n                response constructor.\n            chunk_size: The chunk sizes to use when streaming the file. Defaults to 1MB.\n            content_disposition_type: The type of the ``Content-Disposition``. Either ``inline`` or ``attachment``.\n            etag: An optional :class:`ETag <.datastructures.ETag>` instance. If not provided, an etag will be\n                generated.\n            file_system: An implementation of the :class:`FileSystemProtocol <.types.FileSystemProtocol>`. If provided\n                it will be used to load the file.\n            file_info: The output of calling :meth:`file_system.info <types.FileSystemProtocol.info>`, equivalent to\n                providing an :class:`os.stat_result`.\n        \"\"\"\n        if not media_type:\n            mimetype, content_encoding = guess_type(filename) if filename else (None, None)\n            media_type = mimetype or \"application/octet-stream\"\n            if content_encoding is not None:\n                headers = headers or {}\n                headers.update({\"content-encoding\": content_encoding})\n\n        self.chunk_size = chunk_size\n        self.content_disposition_type = content_disposition_type\n        self.etag = etag\n        self.file_path = path\n        self.filename = filename or \"\"\n        self.adapter = FileSystemAdapter(file_system or BaseLocalFileSystem())\n\n        super().__init__(\n            content=async_file_iterator(file_path=path, chunk_size=chunk_size, adapter=self.adapter),\n            status_code=status_code,\n            media_type=media_type,\n            background=background,\n            headers=headers,\n            cookies=cookies,\n            encoding=encoding,\n            is_head_response=is_head_response,\n        )\n\n        if file_info:\n            self.file_info: FileInfo | Coroutine[Any, Any, FileInfo] = file_info\n        elif stat_result:\n            self.file_info = self.adapter.parse_stat_result(result=stat_result, path=path)\n        else:\n            self.file_info = self.adapter.info(self.file_path)\n\n    @property\n    def content_disposition(self) -> str:\n        \"\"\"Content disposition.\n\n        Returns:\n            A value for the ``Content-Disposition`` header.\n        \"\"\"\n        quoted_filename = quote(self.filename)\n        is_utf8 = quoted_filename == self.filename\n        if is_utf8:\n            return f'{self.content_disposition_type}; filename=\"{self.filename}\"'\n        return f\"{self.content_disposition_type}; filename*=utf-8''{quoted_filename}\"\n\n    @property\n    def content_length(self) -> int:\n        \"\"\"Content length of the response if applicable.\n\n        Returns:\n            Returns the value of :attr:`stat_result.st_size <os.stat_result.st_size>` to populate the ``Content-Length``\n                header.\n        \"\"\"\n        if isinstance(self.file_info, dict):\n            return self.file_info[\"size\"]\n        return 0\n\n    async def send_body(self, send: Send, receive: Receive) -> None:\n        \"\"\"Emit a stream of events correlating with the response body.\n\n        Args:\n            send: The ASGI send function.\n            receive: The ASGI receive function.\n\n        Returns:\n            None\n        \"\"\"\n        if self.chunk_size < self.content_length:\n            await super().send_body(send=send, receive=receive)\n            return\n\n        async with await self.adapter.open(self.file_path) as file:\n            body_event: HTTPResponseBodyEvent = {\n                \"type\": \"http.response.body\",\n                \"body\": await file.read(),\n                \"more_body\": False,\n            }\n            await send(body_event)\n\n    async def start_response(self, send: Send) -> None:\n        \"\"\"Emit the start event of the response. This event includes the headers and status codes.\n\n        Args:\n            send: The ASGI send function.\n\n        Returns:\n            None\n        \"\"\"\n        try:\n            fs_info = self.file_info = cast(\n                \"FileInfo\", (await self.file_info if iscoroutine(self.file_info) else self.file_info)\n            )\n        except FileNotFoundError as e:\n            raise ImproperlyConfiguredException(f\"{self.file_path} does not exist\") from e\n\n        if fs_info[\"type\"] != \"file\":\n            raise ImproperlyConfiguredException(f\"{self.file_path} is not a file\")\n\n        self.set_header(\"last-modified\", formatdate(fs_info[\"mtime\"], usegmt=True))\n        self.set_header(\"content-disposition\", self.content_disposition)\n        self.set_etag(\n            self.etag\n            or create_etag_for_file(path=self.file_path, modified_time=fs_info[\"mtime\"], file_size=fs_info[\"size\"])\n        )\n\n        await super().start_response(send=send)\n", "path": "litestar/response/file.py"}]}