The :class:`FileStorage` class is a thin wrapper over incoming files. It is used by the request object to represent uploaded files. All the attributes of the wrapper stream are proxied by the file storage so it's possible to do ``storage.read()`` instead of the long form ``storage.s
| 14 | |
| 15 | |
| 16 | class FileStorage: |
| 17 | """The :class:`FileStorage` class is a thin wrapper over incoming files. |
| 18 | It is used by the request object to represent uploaded files. All the |
| 19 | attributes of the wrapper stream are proxied by the file storage so |
| 20 | it's possible to do ``storage.read()`` instead of the long form |
| 21 | ``storage.stream.read()``. |
| 22 | """ |
| 23 | |
| 24 | def __init__( |
| 25 | self, |
| 26 | stream: t.IO[bytes] | None = None, |
| 27 | filename: str | None = None, |
| 28 | name: str | None = None, |
| 29 | content_type: str | None = None, |
| 30 | content_length: int | None = None, |
| 31 | headers: Headers | None = None, |
| 32 | ): |
| 33 | self.name = name |
| 34 | self.stream = stream or BytesIO() |
| 35 | |
| 36 | # If no filename is provided, attempt to get the filename from |
| 37 | # the stream object. Python names special streams like |
| 38 | # ``<stderr>`` with angular brackets, skip these streams. |
| 39 | if filename is None: |
| 40 | filename = getattr(stream, "name", None) |
| 41 | |
| 42 | if filename is not None: |
| 43 | filename = fsdecode(filename) |
| 44 | |
| 45 | if filename and filename[0] == "<" and filename[-1] == ">": |
| 46 | filename = None |
| 47 | else: |
| 48 | filename = fsdecode(filename) |
| 49 | |
| 50 | self.filename = filename |
| 51 | |
| 52 | if headers is None: |
| 53 | headers = Headers() |
| 54 | self.headers = headers |
| 55 | if content_type is not None: |
| 56 | headers["Content-Type"] = content_type |
| 57 | if content_length is not None: |
| 58 | headers["Content-Length"] = str(content_length) |
| 59 | |
| 60 | def _parse_content_type(self) -> None: |
| 61 | if not hasattr(self, "_parsed_content_type"): |
| 62 | self._parsed_content_type = http.parse_options_header(self.content_type) |
| 63 | |
| 64 | @property |
| 65 | def content_type(self) -> str | None: |
| 66 | """The content-type sent in the header. Usually not available""" |
| 67 | return self.headers.get("content-type") |
| 68 | |
| 69 | @property |
| 70 | def content_length(self) -> int: |
| 71 | """The content-length sent in the header. Usually not available""" |
| 72 | if "content-length" in self.headers: |
| 73 | try: |
no outgoing calls