[Python-checkins] cpython (merge 3.3 -> default): Merge #18324: set_payload now correctly handles binary input.

r.david.murray python-checkins at python.org
Thu Aug 22 03:14:31 CEST 2013


http://hg.python.org/cpython/rev/a4afcf93ef7b
changeset:   85311:a4afcf93ef7b
parent:      85309:ea4130668150
parent:      85310:64e004737837
user:        R David Murray <rdmurray at bitdance.com>
date:        Wed Aug 21 21:13:51 2013 -0400
summary:
  Merge #18324: set_payload now correctly handles binary input.

files:
  Lib/email/encoders.py             |  20 ++--------
  Lib/email/message.py              |   2 +
  Lib/test/test_email/test_email.py |  36 +++++++++++++++++++
  Misc/NEWS                         |   3 +
  4 files changed, 45 insertions(+), 16 deletions(-)


diff --git a/Lib/email/encoders.py b/Lib/email/encoders.py
--- a/Lib/email/encoders.py
+++ b/Lib/email/encoders.py
@@ -28,7 +28,7 @@
 
     Also, add an appropriate Content-Transfer-Encoding header.
     """
-    orig = msg.get_payload()
+    orig = msg.get_payload(decode=True)
     encdata = str(_bencode(orig), 'ascii')
     msg.set_payload(encdata)
     msg['Content-Transfer-Encoding'] = 'base64'
@@ -40,20 +40,16 @@
 
     Also, add an appropriate Content-Transfer-Encoding header.
     """
-    orig = msg.get_payload()
-    if isinstance(orig, str):
-        # If it is a string, the model data may have binary data encoded in via
-        # surrogateescape.  Convert back to bytes so we can CTE encode it.
-        orig = orig.encode('ascii', 'surrogateescape')
+    orig = msg.get_payload(decode=True)
     encdata = _qencode(orig)
-    msg.set_payload(encdata.decode('ascii', 'surrogateescape'))
+    msg.set_payload(encdata)
     msg['Content-Transfer-Encoding'] = 'quoted-printable'
 
 
 

 def encode_7or8bit(msg):
     """Set the Content-Transfer-Encoding header to 7bit or 8bit."""
-    orig = msg.get_payload()
+    orig = msg.get_payload(decode=True)
     if orig is None:
         # There's no payload.  For backwards compatibility we use 7bit
         msg['Content-Transfer-Encoding'] = '7bit'
@@ -75,16 +71,8 @@
             msg['Content-Transfer-Encoding'] = '8bit'
     else:
         msg['Content-Transfer-Encoding'] = '7bit'
-    if not isinstance(orig, str):
-        msg.set_payload(orig.decode('ascii', 'surrogateescape'))
 
 
 

 def encode_noop(msg):
     """Do nothing."""
-    # Well, not quite *nothing*: in Python3 we have to turn bytes into a string
-    # in our internal surrogateescaped form in order to keep the model
-    # consistent.
-    orig = msg.get_payload()
-    if not isinstance(orig, str):
-        msg.set_payload(orig.decode('ascii', 'surrogateescape'))
diff --git a/Lib/email/message.py b/Lib/email/message.py
--- a/Lib/email/message.py
+++ b/Lib/email/message.py
@@ -303,6 +303,8 @@
         Optional charset sets the message's default character set.  See
         set_charset() for details.
         """
+        if isinstance(payload, bytes):
+            payload = payload.decode('ascii', 'surrogateescape')
         self._payload = payload
         if charset is not None:
             self.set_charset(charset)
diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py
--- a/Lib/test/test_email/test_email.py
+++ b/Lib/test/test_email/test_email.py
@@ -620,6 +620,42 @@
             "attachment; filename*=utf-8''Fu%C3%9Fballer%20%5Bfilename%5D.ppt",
             msg['Content-Disposition'])
 
+    def test_binary_quopri_payload(self):
+        for charset in ('latin-1', 'ascii'):
+            msg = Message()
+            msg['content-type'] = 'text/plain; charset=%s' % charset
+            msg['content-transfer-encoding'] = 'quoted-printable'
+            msg.set_payload(b'foo=e6=96=87bar')
+            self.assertEqual(
+                msg.get_payload(decode=True),
+                b'foo\xe6\x96\x87bar',
+                'get_payload returns wrong result with charset %s.' % charset)
+
+    def test_binary_base64_payload(self):
+        for charset in ('latin-1', 'ascii'):
+            msg = Message()
+            msg['content-type'] = 'text/plain; charset=%s' % charset
+            msg['content-transfer-encoding'] = 'base64'
+            msg.set_payload(b'Zm9v5paHYmFy')
+            self.assertEqual(
+                msg.get_payload(decode=True),
+                b'foo\xe6\x96\x87bar',
+                'get_payload returns wrong result with charset %s.' % charset)
+
+    def test_binary_uuencode_payload(self):
+        for charset in ('latin-1', 'ascii'):
+            for encoding in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
+                msg = Message()
+                msg['content-type'] = 'text/plain; charset=%s' % charset
+                msg['content-transfer-encoding'] = encoding
+                msg.set_payload(b"begin 666 -\n)9F]OYI:'8F%R\n \nend\n")
+                self.assertEqual(
+                    msg.get_payload(decode=True),
+                    b'foo\xe6\x96\x87bar',
+                    str(('get_payload returns wrong result ',
+                         'with charset {0} and encoding {1}.')).\
+                        format(charset, encoding))
+
     def test_add_header_with_name_only_param(self):
         msg = Message()
         msg.add_header('Content-Disposition', 'inline', foo_bar=None)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -38,6 +38,9 @@
 Library
 -------
 
+- Issue #18324: set_payload now correctly handles binary input.  This also
+  supersedes the previous fixes for #14360, #1717, and #16564.
+
 - Issue #18794: Add a fileno() method and a closed attribute to select.devpoll
   objects.
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list