| 184 | return container |
| 185 | |
| 186 | async def parse( |
| 187 | self, body: Body, boundary: bytes, content_length: int |
| 188 | ) -> tuple[MultiDict, MultiDict]: |
| 189 | container: IO[bytes] | list[bytes] |
| 190 | _write: Callable[[bytes], Any] |
| 191 | |
| 192 | parser = MultipartDecoder( |
| 193 | boundary, self.max_content_length, max_parts=self.max_form_parts |
| 194 | ) |
| 195 | |
| 196 | fields = [] |
| 197 | files = [] |
| 198 | |
| 199 | current_part: Field | File |
| 200 | field_size: int | None = None |
| 201 | async for data in body: |
| 202 | parser.receive_data(data) |
| 203 | event = parser.next_event() |
| 204 | while not isinstance(event, (Epilogue, NeedData)): |
| 205 | if isinstance(event, Field): |
| 206 | current_part = event |
| 207 | field_size = 0 |
| 208 | container = [] |
| 209 | _write = container.append |
| 210 | elif isinstance(event, File): |
| 211 | current_part = event |
| 212 | field_size = None |
| 213 | container = self.start_file_streaming(event, content_length) |
| 214 | _write = container.write |
| 215 | elif isinstance(event, Data): |
| 216 | if self.max_form_memory_size is not None and field_size is not None: |
| 217 | field_size += len(event.data) |
| 218 | |
| 219 | if field_size > self.max_form_memory_size: |
| 220 | raise RequestEntityTooLarge() |
| 221 | |
| 222 | _write(event.data) |
| 223 | if not event.more_data: |
| 224 | if isinstance(current_part, Field): |
| 225 | value = b"".join(container).decode( |
| 226 | self.get_part_charset(current_part.headers), "replace" |
| 227 | ) |
| 228 | fields.append((current_part.name, value)) |
| 229 | else: |
| 230 | container = cast(IO[bytes], container) |
| 231 | container.seek(0) |
| 232 | files.append( |
| 233 | ( |
| 234 | current_part.name, |
| 235 | self.file_storage_cls( |
| 236 | container, |
| 237 | current_part.filename, |
| 238 | current_part.name, |
| 239 | headers=current_part.headers, |
| 240 | ), |
| 241 | ) |
| 242 | ) |
| 243 | |