Skip to content

Commit cbc0c86

Browse files
Revert #3492 (#8300)
#3492 was never backported and nobody seems to have reported the missing feature after 5 years which suggests there is little demand for it. Furthermore, there is a risk that this may introduce HTTP request smuggling vulnerabilities. Therefore, we should revert this for now. If there is desire to re-add the feature, the specs will need to referenced and evaluated to ensure this doesn't present a security issue.
1 parent 4d72dca commit cbc0c86

File tree

3 files changed

+214
-475
lines changed

3 files changed

+214
-475
lines changed

CHANGES/2302.feature

-1
This file was deleted.

aiohttp/multipart.py

+10-38
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,9 @@ def __init__(
260260
boundary: bytes,
261261
headers: "CIMultiDictProxy[str]",
262262
content: StreamReader,
263-
*,
264-
_newline: bytes = b"\r\n",
265263
) -> None:
266264
self.headers = headers
267265
self._boundary = boundary
268-
self._newline = _newline
269266
self._content = content
270267
self._at_eof = False
271268
length = self.headers.get(CONTENT_LENGTH, None)
@@ -348,9 +345,9 @@ async def read_chunk(self, size: int = chunk_size) -> bytes:
348345
if self._read_bytes == self._length:
349346
self._at_eof = True
350347
if self._at_eof:
351-
newline = await self._content.readline()
348+
clrf = await self._content.readline()
352349
assert (
353-
newline == self._newline
350+
b"\r\n" == clrf
354351
), "reader did not read all the data or it is malformed"
355352
return chunk
356353

@@ -377,15 +374,11 @@ async def _read_chunk_from_stream(self, size: int) -> bytes:
377374
assert self._content_eof < 3, "Reading after EOF"
378375
assert self._prev_chunk is not None
379376
window = self._prev_chunk + chunk
380-
381-
intermeditate_boundary = self._newline + self._boundary
382-
377+
sub = b"\r\n" + self._boundary
383378
if first_chunk:
384-
pos = 0
379+
idx = window.find(sub)
385380
else:
386-
pos = max(0, len(self._prev_chunk) - len(intermeditate_boundary))
387-
388-
idx = window.find(intermeditate_boundary, pos)
381+
idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub)))
389382
if idx >= 0:
390383
# pushing boundary back to content
391384
with warnings.catch_warnings():
@@ -396,7 +389,6 @@ async def _read_chunk_from_stream(self, size: int) -> bytes:
396389
chunk = window[len(self._prev_chunk) : idx]
397390
if not chunk:
398391
self._at_eof = True
399-
400392
result = self._prev_chunk
401393
self._prev_chunk = chunk
402394
return result
@@ -425,8 +417,7 @@ async def readline(self) -> bytes:
425417
else:
426418
next_line = await self._content.readline()
427419
if next_line.startswith(self._boundary):
428-
# strip newline but only once
429-
line = line[: -len(self._newline)]
420+
line = line[:-2] # strip CRLF but only once
430421
self._unread.append(next_line)
431422

432423
return line
@@ -578,12 +569,9 @@ def __init__(
578569
self,
579570
headers: Mapping[str, str],
580571
content: StreamReader,
581-
*,
582-
_newline: bytes = b"\r\n",
583572
) -> None:
584573
self.headers = headers
585574
self._boundary = ("--" + self._get_boundary()).encode()
586-
self._newline = _newline
587575
self._content = content
588576
self._last_part: Optional[Union["MultipartReader", BodyPartReader]] = None
589577
self._at_eof = False
@@ -670,13 +658,9 @@ def _get_part_reader(
670658
if mimetype.type == "multipart":
671659
if self.multipart_reader_cls is None:
672660
return type(self)(headers, self._content)
673-
return self.multipart_reader_cls(
674-
headers, self._content, _newline=self._newline
675-
)
661+
return self.multipart_reader_cls(headers, self._content)
676662
else:
677-
return self.part_reader_cls(
678-
self._boundary, headers, self._content, _newline=self._newline
679-
)
663+
return self.part_reader_cls(self._boundary, headers, self._content)
680664

681665
def _get_boundary(self) -> str:
682666
mimetype = parse_mimetype(self.headers[CONTENT_TYPE])
@@ -703,23 +687,11 @@ async def _read_until_first_boundary(self) -> None:
703687
while True:
704688
chunk = await self._readline()
705689
if chunk == b"":
706-
raise ValueError(
707-
"Could not find starting boundary %r" % (self._boundary)
708-
)
709-
newline = None
710-
end_boundary = self._boundary + b"--"
711-
if chunk.startswith(end_boundary):
712-
_, newline = chunk.split(end_boundary, 1)
713-
elif chunk.startswith(self._boundary):
714-
_, newline = chunk.split(self._boundary, 1)
715-
if newline is not None:
716-
assert newline in (b"\r\n", b"\n"), (newline, chunk, self._boundary)
717-
self._newline = newline
718-
690+
raise ValueError(f"Could not find starting boundary {self._boundary!r}")
719691
chunk = chunk.rstrip()
720692
if chunk == self._boundary:
721693
return
722-
elif chunk == end_boundary:
694+
elif chunk == self._boundary + b"--":
723695
self._at_eof = True
724696
return
725697

0 commit comments

Comments
 (0)