From: Marcelo Trylesinski Date: Tue, 24 May 2022 05:31:57 +0000 (+0200) Subject: Raise `MultiPartException` when missing "name" field on `Content-Disposition` header... X-Git-Tag: 0.20.1~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7b9fcaf31d4d23f91ca96181188f5440c3f63201;p=thirdparty%2Fstarlette.git Raise `MultiPartException` when missing "name" field on `Content-Disposition` header (#1643) --- diff --git a/setup.cfg b/setup.cfg index 734fa818..8dad329c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,6 +30,7 @@ filterwarnings= error ignore: run_until_first_complete is deprecated and will be removed in a future version.:DeprecationWarning ignore: starlette\.middleware\.wsgi is deprecated and will be removed in a future release\.*:DeprecationWarning + ignore: Async generator 'starlette\.requests\.Request\.stream' was garbage collected before it had been exhausted.*:ResourceWarning [coverage:run] source_pkgs = starlette, tests diff --git a/starlette/formparsers.py b/starlette/formparsers.py index 4cde71b6..53538c81 100644 --- a/starlette/formparsers.py +++ b/starlette/formparsers.py @@ -220,7 +220,13 @@ class MultiPartParser: header_value = b"" elif message_type == MultiPartMessage.HEADERS_FINISHED: disposition, options = parse_options_header(content_disposition) - field_name = _user_safe_decode(options[b"name"], charset) + try: + field_name = _user_safe_decode(options[b"name"], charset) + except KeyError: + raise MultiPartException( + 'The Content-Disposition header field "name" must be ' + "provided." + ) if b"filename" in options: filename = _user_safe_decode(options[b"filename"], charset) file = UploadFile( diff --git a/tests/test_formparsers.py b/tests/test_formparsers.py index 67105952..7418595c 100644 --- a/tests/test_formparsers.py +++ b/tests/test_formparsers.py @@ -418,3 +418,35 @@ def test_missing_boundary_parameter( ) assert res.status_code == 400 assert res.text == "Missing boundary in multipart." + + +@pytest.mark.parametrize( + "app,expectation", + [ + (app, pytest.raises(MultiPartException)), + (Starlette(routes=[Mount("/", app=app)]), does_not_raise()), + ], +) +def test_missing_name_parameter_on_content_disposition( + app, expectation, test_client_factory: typing.Callable[..., TestClient] +): + client = test_client_factory(app) + with expectation: + res = client.post( + "/", + data=( + # data + b"--a7f7ac8d4e2e437c877bb7b8d7cc549c\r\n" + b'Content-Disposition: form-data; ="field0"\r\n\r\n' + b"value0\r\n" + ), + headers={ + "Content-Type": ( + "multipart/form-data; boundary=a7f7ac8d4e2e437c877bb7b8d7cc549c" + ) + }, + ) + assert res.status_code == 400 + assert ( + res.text == 'The Content-Disposition header field "name" must be provided.' + )