Skip to content

Commit bc1319e

Browse files
Replace asserts with exceptions (#11897) (#11914)
(cherry picked from commit d5bf65f) Co-authored-by: J. Nick Koston <nick@home-assistant.io>
1 parent dc3170b commit bc1319e

File tree

4 files changed

+41
-13
lines changed

4 files changed

+41
-13
lines changed

aiohttp/multipart.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -361,11 +361,8 @@ async def read_chunk(self, size: int = chunk_size) -> bytes:
361361
self._read_bytes += len(chunk)
362362
if self._read_bytes == self._length:
363363
self._at_eof = True
364-
if self._at_eof:
365-
clrf = await self._content.readline()
366-
assert (
367-
b"\r\n" == clrf
368-
), "reader did not read all the data or it is malformed"
364+
if self._at_eof and await self._content.readline() != b"\r\n":
365+
raise ValueError("Reader did not read all the data or it is malformed")
369366
return chunk
370367

371368
async def _read_chunk_from_length(self, size: int) -> bytes:
@@ -395,7 +392,8 @@ async def _read_chunk_from_stream(self, size: int) -> bytes:
395392
while len(chunk) < self._boundary_len:
396393
chunk += await self._content.read(size)
397394
self._content_eof += int(self._content.at_eof())
398-
assert self._content_eof < 3, "Reading after EOF"
395+
if self._content_eof > 2:
396+
raise ValueError("Reading after EOF")
399397
if self._content_eof:
400398
break
401399
if len(chunk) > size:

aiohttp/web_request.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -722,12 +722,12 @@ async def post(self) -> "MultiDictProxy[Union[str, bytes, FileField]]":
722722
max_size = self._client_max_size
723723

724724
size = 0
725-
field = await multipart.next()
726-
while field is not None:
725+
while (field := await multipart.next()) is not None:
727726
field_ct = field.headers.get(hdrs.CONTENT_TYPE)
728727

729728
if isinstance(field, BodyPartReader):
730-
assert field.name is not None
729+
if field.name is None:
730+
raise ValueError("Multipart field missing name.")
731731

732732
# Note that according to RFC 7578, the Content-Type header
733733
# is optional, even for files, so we can't assume it's
@@ -779,8 +779,6 @@ async def post(self) -> "MultiDictProxy[Union[str, bytes, FileField]]":
779779
raise ValueError(
780780
"To decode nested multipart you need to use custom reader",
781781
)
782-
783-
field = await multipart.next()
784782
else:
785783
data = await self.read()
786784
if data:

tests/test_multipart.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,21 @@ async def test_read_incomplete_body_chunked(self) -> None:
221221
with Stream(data) as stream:
222222
obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)
223223
result = b""
224-
with pytest.raises(AssertionError):
224+
with pytest.raises(ValueError):
225225
for _ in range(4):
226226
result += await obj.read_chunk(7)
227227
assert data == result
228228

229+
async def test_read_with_content_length_malformed_crlf(self) -> None:
230+
# Content-Length is correct but data after content is not \r\n
231+
content = b"Hello"
232+
h = CIMultiDictProxy(CIMultiDict({"CONTENT-LENGTH": str(len(content))}))
233+
# Malformed: "XX" instead of "\r\n" after content
234+
with Stream(content + b"XX--:--") as stream:
235+
obj = aiohttp.BodyPartReader(BOUNDARY, h, stream)
236+
with pytest.raises(ValueError, match="malformed"):
237+
await obj.read()
238+
229239
async def test_read_boundary_with_incomplete_chunk(self) -> None:
230240
with Stream(b"") as stream:
231241

tests/test_web_request.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from yarl import URL
1313

1414
from aiohttp import HttpVersion
15+
from aiohttp.base_protocol import BaseProtocol
1516
from aiohttp.http_parser import RawRequestMessage
1617
from aiohttp.streams import StreamReader
1718
from aiohttp.test_utils import make_mocked_request
@@ -845,7 +846,28 @@ async def test_multipart_formdata(protocol) -> None:
845846
assert dict(result) == {"a": "b", "c": "d"}
846847

847848

848-
async def test_multipart_formdata_file(protocol) -> None:
849+
async def test_multipart_formdata_field_missing_name(protocol: BaseProtocol) -> None:
850+
# Ensure ValueError is raised when Content-Disposition has no name
851+
payload = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())
852+
payload.feed_data(
853+
b"-----------------------------326931944431359\r\n"
854+
b"Content-Disposition: form-data\r\n" # Missing name!
855+
b"\r\n"
856+
b"value\r\n"
857+
b"-----------------------------326931944431359--\r\n"
858+
)
859+
content_type = (
860+
"multipart/form-data; boundary=---------------------------326931944431359"
861+
)
862+
payload.feed_eof()
863+
req = make_mocked_request(
864+
"POST", "/", headers={"CONTENT-TYPE": content_type}, payload=payload
865+
)
866+
with pytest.raises(ValueError, match="Multipart field missing name"):
867+
await req.post()
868+
869+
870+
async def test_multipart_formdata_file(protocol: BaseProtocol) -> None:
849871
# Make sure file uploads work, even without a content type
850872
payload = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())
851873
payload.feed_data(

0 commit comments

Comments
 (0)