diff options
author | R David Murray <rdmurray@bitdance.com> | 2014-06-11 15:18:08 (GMT) |
---|---|---|
committer | R David Murray <rdmurray@bitdance.com> | 2014-06-11 15:18:08 (GMT) |
commit | 554bcbf1b925399ef06dd9fd6b87a20f5d028c1e (patch) | |
tree | fa7bc0ec474895b0051422d855065960eb68c3ca /Lib/smtpd.py | |
parent | 38ee9afb34d8eb3fc7d080c447f245ab8369934d (diff) | |
download | cpython-554bcbf1b925399ef06dd9fd6b87a20f5d028c1e.zip cpython-554bcbf1b925399ef06dd9fd6b87a20f5d028c1e.tar.gz cpython-554bcbf1b925399ef06dd9fd6b87a20f5d028c1e.tar.bz2 |
#19662: add decode_data to smtpd so you can get at DATA in bytes form.
Otherwise smtpd is restricted to 7bit clean data, since even if the
incoming data is actually utf-8, it will often break things to decode
it before parsing the message.
Patch by Maciej Szulik, with some adjustments (mostly the warning
support).
Diffstat (limited to 'Lib/smtpd.py')
-rwxr-xr-x | Lib/smtpd.py | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/Lib/smtpd.py b/Lib/smtpd.py index 1fa157a..569b42e 100755 --- a/Lib/smtpd.py +++ b/Lib/smtpd.py @@ -98,7 +98,6 @@ class Devnull: DEBUGSTREAM = Devnull() NEWLINE = '\n' -EMPTYSTRING = '' COMMASPACE = ', ' DATA_SIZE_DEFAULT = 33554432 @@ -122,12 +121,28 @@ class SMTPChannel(asynchat.async_chat): max_command_size_limit = max(command_size_limits.values()) def __init__(self, server, conn, addr, data_size_limit=DATA_SIZE_DEFAULT, - map=None): + map=None, decode_data=None): asynchat.async_chat.__init__(self, conn, map=map) self.smtp_server = server self.conn = conn self.addr = addr self.data_size_limit = data_size_limit + if decode_data is None: + warn("The decode_data default of True will change to False in 3.6;" + " specify an explicit value for this keyword", + DeprecationWarning, 2) + decode_data = True + self._decode_data = decode_data + if decode_data: + self._emptystring = '' + self._linesep = '\r\n' + self._dotsep = '.' + self._newline = NEWLINE + else: + self._emptystring = b'' + self._linesep = b'\r\n' + self._dotsep = b'.' + self._newline = b'\n' self.received_lines = [] self.smtp_state = self.COMMAND self.seen_greeting = '' @@ -287,11 +302,14 @@ class SMTPChannel(asynchat.async_chat): return elif limit: self.num_bytes += len(data) - self.received_lines.append(str(data, "utf-8")) + if self._decode_data: + self.received_lines.append(str(data, 'utf-8')) + else: + self.received_lines.append(data) # Implementation of base class abstract method def found_terminator(self): - line = EMPTYSTRING.join(self.received_lines) + line = self._emptystring.join(self.received_lines) print('Data:', repr(line), file=DEBUGSTREAM) self.received_lines = [] if self.smtp_state == self.COMMAND: @@ -300,6 +318,8 @@ class SMTPChannel(asynchat.async_chat): self.push('500 Error: bad syntax') return method = None + if not self._decode_data: + line = str(line, 'utf-8') i = line.find(' ') if i < 0: command = line.upper() @@ -330,12 +350,12 @@ class SMTPChannel(asynchat.async_chat): # Remove extraneous carriage returns and de-transparency according # to RFC 5321, Section 4.5.2. data = [] - for text in line.split('\r\n'): - if text and text[0] == '.': + for text in line.split(self._linesep): + if text and text[0] == self._dotsep: data.append(text[1:]) else: data.append(text) - self.received_data = NEWLINE.join(data) + self.received_data = self._newline.join(data) status = self.smtp_server.process_message(self.peer, self.mailfrom, self.rcpttos, @@ -577,10 +597,17 @@ class SMTPServer(asyncore.dispatcher): channel_class = SMTPChannel def __init__(self, localaddr, remoteaddr, - data_size_limit=DATA_SIZE_DEFAULT, map=None): + data_size_limit=DATA_SIZE_DEFAULT, map=None, + decode_data=None): self._localaddr = localaddr self._remoteaddr = remoteaddr self.data_size_limit = data_size_limit + if decode_data is None: + warn("The decode_data default of True will change to False in 3.6;" + " specify an explicit value for this keyword", + DeprecationWarning, 2) + decode_data = True + self._decode_data = decode_data asyncore.dispatcher.__init__(self, map=map) try: self.create_socket(socket.AF_INET, socket.SOCK_STREAM) @@ -599,7 +626,7 @@ class SMTPServer(asyncore.dispatcher): def handle_accepted(self, conn, addr): print('Incoming connection from %s' % repr(addr), file=DEBUGSTREAM) channel = self.channel_class(self, conn, addr, self.data_size_limit, - self._map) + self._map, self._decode_data) # API for "doing something useful with the message" def process_message(self, peer, mailfrom, rcpttos, data): |