Skip to content

Commit

Permalink
Handle StreamReader buffer overflow when reading DATA text line
Browse files Browse the repository at this point in the history
  • Loading branch information
Mortal committed Apr 4, 2017
1 parent 8924e16 commit 65f1429
Showing 1 changed file with 24 additions and 3 deletions.
27 changes: 24 additions & 3 deletions aiosmtpd/smtp.py
Original file line number Diff line number Diff line change
Expand Up @@ -583,10 +583,23 @@ def smtp_DATA(self, arg):
yield from self.push('354 End data with <CR><LF>.<CR><LF>')
data = []
num_bytes = 0
unfinished_line = []
size_exceeded = False
while True:
line = yield from self._reader.readline()
if line == b'.\r\n':
# Since eof_received cancels this coroutine,
# readuntil() can never raise asyncio.IncompleteReadError.
try:
line = yield from self._reader.readuntil()
assert line.endswith(b'\n')
except asyncio.LimitOverrunError as e:
# The line exceeds StreamReader's buffer.
# XXX Should we respond with 500 Line too long
# and set size_exceeded = True here?
# How is an SMTP implementation supposed to react?
line = yield from self._reader.read(e.consumed)
assert not line.endswith(b'\n')
# A lone dot in a line signals the end of DATA.
if not unfinished_line and line == b'.\r\n':
if data:
data[-1] = data[-1].rstrip(b'\r\n')
break
Expand All @@ -597,10 +610,18 @@ def smtp_DATA(self, arg):
size_exceeded = True
yield from self.push('552 Error: Too much mail data')
if not size_exceeded:
data.append(line)
if line.endswith(b'\n'):
data.append(EMPTYBYTES.join(unfinished_line) + line)
del unfinished_line[:]
else:
unfinished_line.append(line)
elif line.endswith(b'\n'):
del unfinished_line[:]
if size_exceeded:
self._set_post_data_state()
return
# If unfinished_line is non-empty, then the connection was closed.
assert not unfinished_line
# Remove extraneous carriage returns and de-transparency
# according to RFC 5321, Section 4.5.2.
for i in range(len(data)):
Expand Down

0 comments on commit 65f1429

Please sign in to comment.