This release is a pre-release and may not be stable for production use.
parse-multipart-form-data
A small, streaming parser for HTTP multipart/form-data request bodies.
The parser consumes an iterable of byte chunks and yields a streaming event sequence for each uploaded file. It does not depend on a web framework or read from sockets itself, so callers control request-body I/O and where uploaded content is stored.
Installation
pip install parse-multipart-form-data
For local development from this checkout:
pip install -e .
Usage
from parse_multipart_form_data import (
PartBegin,
PartData,
PartEnd,
parse_multipart_form_data,
)
body_chunks = [
b"--BOUNDARY\r\n",
b'Content-Disposition: form-data; name="file"; filename="hello.txt"\r\n',
b"\r\n",
b"hello world\r\n",
b"--BOUNDARY--\r\n",
]
output = None
for event in parse_multipart_form_data(
"multipart/form-data; boundary=BOUNDARY", body_chunks):
if isinstance(event, PartBegin):
output = open(event.filename, "wb")
elif isinstance(event, PartData):
output.write(event.data)
else: # PartEnd
output.close()
The event stream is:
PartBegin(filename)at the beginning of a file part;PartData(bytes_chunk)for each file-content chunk; andPartEnd(is_final)after its delimiter has been consumed.
Only parts with a filename or filename* parameter produce events; ordinary
form fields are consumed and skipped. A valid RFC 6266 filename* (UTF-8 or
ISO-8859-1) takes precedence over filename.
Delimiter compatibility
Only exact delimiter lines are supported:
--BOUNDARY\r\n
--BOUNDARY--\r\n
MIME transport padding (spaces or tabs after a delimiter) is not supported. Supporting arbitrary transport padding requires byte-by-byte input reading, which is inefficient in Python and rare in real-world multipart form uploads.
Boundary values may be quoted or unquoted, including RFC 2046 boundary
characters such as =, :, /, ?, (, ), and ,. Preamble and
part-header lines are limited to 8192 bytes of content.
Parser states
The parser has one MultipartState vocabulary. Its transitions are:
SEEK_OPENING_BOUNDARY -> READ_HEADERS | DONE
READ_HEADERS -> MAYBE_BOUNDARY
READ_PART_BODY -> READ_PART_BODY | MAYBE_BOUNDARY
MAYBE_BOUNDARY -> MAYBE_BOUNDARY | READ_PART_BODY | READ_HEADERS | DONE
Minimal wire-format machine
For the multipart example in the module documentation, the parser's essential
wire-level transitions are (CRLF denotes the literal \r\n byte pair):
stateDiagram-v2
[*] --> SEEK_OPENING_BOUNDARY
SEEK_OPENING_BOUNDARY --> READ_HEADERS: --BOUNDARY CRLF
SEEK_OPENING_BOUNDARY --> DONE: --BOUNDARY-- CRLF
READ_HEADERS --> READ_HEADERS: header CRLF
READ_HEADERS --> MAYBE_BOUNDARY: blank CRLF / empty part check
READ_PART_BODY --> READ_PART_BODY: not *.CRLF
READ_PART_BODY --> MAYBE_BOUNDARY: *.CRLF
MAYBE_BOUNDARY --> MAYBE_BOUNDARY: non-boundary line ending CRLF
MAYBE_BOUNDARY --> READ_PART_BODY: non-boundary prefix
MAYBE_BOUNDARY --> READ_HEADERS: --BOUNDARY CRLF
MAYBE_BOUNDARY --> DONE: --BOUNDARY-- CRLF
DONE --> [*]
The single parser generator holds its state across every event. A boundary
suffix is consumed before it emits PartEnd, so the next event always starts
a well-defined next transition.
Testing
python -m unittest discover -s tests
License
MIT. See LICENSE.
Release files for parse-multipart-form-data 0.1.0a0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| parse_multipart_form_data-0.1.0a0.tar.gz | 9.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| parse_multipart_form_data-0.1.0a0-py2.py3-none-any.whl | Python 2, Python 3 | none | any | Details |
Total release size: 17.4 kB
Release files / parse_multipart_form_data-0.1.0a0.tar.gz
| Download URL | parse_multipart_form_data-0.1.0a0.tar.gz |
|---|---|
| Size | 9.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
70aca36ab031996683b6daa55bc24c707c9b8d60fb4e1373f107fb23d0bd3a83
|
|
BLAKE2b-256 checksum How to use checksums |
b0a0800cfeedf53d5f3b8a189b8ccd255aec9e423213a568f91eac5e7451637f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.7
|
Release files / parse_multipart_form_data-0.1.0a0-py2.py3-none-any.whl
| Download URL | parse_multipart_form_data-0.1.0a0-py2.py3-none-any.whl |
|---|---|
| Size | 7.8 kB |
| Tags | Python 2 Python 3 |
|
SHA-256 checksum How to use checksums |
ca63c9faae78939c65e02abe8f20500a745e60b29858ab5bc1773d49b8b1a861
|
|
BLAKE2b-256 checksum How to use checksums |
0fd909487b3cc513cbccccfd9a7c4fc635b3018d0fd7b1cc63deb3a21000b02b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.7
|