MultipartParseError when parsing empty message
connection-reset opened this issue · comments
Parsing an empty message, i.e. a message with only the final boundary, raises MultipartParseError in MultipartParser._internal_write
:
Traceback (most recent call last):
File "/tmp/repro.py", line 5, in <module>
parser.write(b"--" + boundary + b"--\r\n")
File "/tmp/python-multipart/multipart/multipart.py", line 1076, in write
l = self._internal_write(data, data_len)
File "/tmp/python-multipart/multipart/multipart.py", line 1154, in _internal_write
raise e
multipart.exceptions.MultipartParseError: Did not find CR at end of boundary (3)
How to reproduce (ed8c47a):
import multipart
boundary = b"-"
parser = multipart.MultipartParser(boundary)
parser.write(b"--" + boundary + b"--\r\n")
Firefox and Chrome produce empty messages like this, e.g. when POSTing a HTML form with only a unchecked checkbox.
Confirming it. Reproduced during parsing of form with all optional fields (useful for PATCH
).
Is this behaviour expected?
I'm getting this same error from a starlette-admin webapp: jowilf/starlette-admin#262
Sample code:
class ArticleView(ModelView):
actions = ['test', 'delete']
@action(
name='test',
text='Test',
confirmation='Are you sure?',
form="""
<form>
<input type="checkbox" id="check" name="check">
<label for="check">Breaks unless you check it</label>
</form>
""",
)
async def make_published_action(self, request: Request, pks: List[Any]) -> str:
data: FormData = await request.form()
print(data)
When the form
has an <input>
with no value, it throws: MultipartParseError: Did not find CR at end of boundary
.
This also happens with type="radio"
when submitted with options unselected.
I finally found a workaround: include a hidden
value in the form.
<form>
<input type="checkbox" id="check" name="check">
<label for="check">Doesn't break, thanks to hidden value!</label>
<input type="hidden" name="_" value="">
</form>
Works even when value is ""
, as above.
I'm assuming it's something about parsing a completely empty form, since check
is only passed if it is "on"
.