Kludex / python-multipart

A streaming multipart parser for Python.

Home Page:https://kludex.github.io/python-multipart/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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".