]> granicus.if.org Git - python/commitdiff
#1078919: make add_header automatically do RFC2231 encoding when needed.
authorR. David Murray <rdmurray@bitdance.com>
Mon, 13 Dec 2010 23:51:19 +0000 (23:51 +0000)
committerR. David Murray <rdmurray@bitdance.com>
Mon, 13 Dec 2010 23:51:19 +0000 (23:51 +0000)
Also document the use of three-tuples if control of the charset
and language is desired.

Doc/library/email.message.rst
Lib/email/message.py
Lib/email/test/test_email.py
Misc/NEWS

index 47c1fcde0379cc7a2922df836efbfbeaa6e04ab7..386e11d3015df816eb1a87961dfb0887cd288eda 100644 (file)
@@ -270,7 +270,15 @@ Here are the methods of the :class:`Message` class:
       taken as the parameter name, with underscores converted to dashes (since
       dashes are illegal in Python identifiers).  Normally, the parameter will
       be added as ``key="value"`` unless the value is ``None``, in which case
-      only the key will be added.
+      only the key will be added.  If the value contains non-ASCII characters,
+      it can be specified as a three tuple in the format
+      ``(CHARSET, LANGUAGE, VALUE)``, where ``CHARSET`` is a string naming the
+      charset to be used to encode the value, ``LANGUAGE`` can usually be set
+      to ``None`` or the empty string (see :RFC:`2231` for other possibilities),
+      and ``VALUE`` is the string value containing non-ASCII code points.  If
+      a three tuple is not passed and the value contains non-ASCII characters,
+      it is automatically encoded in :RFC`2231` format using a ``CHARSET``
+      of ``utf-8`` and a ``LANGUAGE`` of ``None``.
 
       Here's an example::
 
@@ -280,6 +288,15 @@ Here are the methods of the :class:`Message` class:
 
          Content-Disposition: attachment; filename="bud.gif"
 
+      An example with with non-ASCII characters::
+
+         msg.add_header('Content-Disposition', 'attachment',
+                        filename=('iso-8859-1', '', 'Fußballer.ppt'))
+
+      Which produces ::
+
+         Content-Disposition: attachment; filename*="iso-8859-1''Fu%DFballer.ppt"
+
 
    .. method:: replace_header(_name, _value)
 
@@ -369,7 +386,7 @@ Here are the methods of the :class:`Message` class:
       :rfc:`2231`, you can collapse the parameter value by calling
       :func:`email.utils.collapse_rfc2231_value`, passing in the return value
       from :meth:`get_param`.  This will return a suitably decoded Unicode
-      string whn the value is a tuple, or the original string unquoted if it
+      string when the value is a tuple, or the original string unquoted if it
       isn't.  For example::
 
          rawparam = msg.get_param('foo')
index a835ce2e69bd2749fa3550f77f2fef408b4d63df..8d68c093cc95f608bc269d67a8f9ba313e6ffcff 100644 (file)
@@ -57,7 +57,11 @@ def _splitparam(param):
 def _formatparam(param, value=None, quote=True):
     """Convenience function to format and return a key=value pair.
 
-    This will quote the value if needed or if quote is true.
+    This will quote the value if needed or if quote is true.  If value is a
+    three tuple (charset, language, value), it will be encoded according
+    to RFC2231 rules.  If it contains non-ascii characters it will likewise
+    be encoded according to RFC2231 rules, using the utf-8 charset and
+    a null language.
     """
     if value is not None and len(value) > 0:
         # A tuple is used for RFC 2231 encoded parameter values where items
@@ -67,6 +71,12 @@ def _formatparam(param, value=None, quote=True):
             # Encode as per RFC 2231
             param += '*'
             value = utils.encode_rfc2231(value[2], value[0], value[1])
+        else:
+            try:
+                value.encode('ascii')
+            except UnicodeEncodeError:
+                param += '*'
+                value = utils.encode_rfc2231(value, 'utf-8', '')
         # BAW: Please check this.  I think that if quote is set it should
         # force quoting even if not necessary.
         if quote or tspecials.search(value):
@@ -438,11 +448,19 @@ class Message:
         name is the header field to add.  keyword arguments can be used to set
         additional parameters for the header field, with underscores converted
         to dashes.  Normally the parameter will be added as key="value" unless
-        value is None, in which case only the key will be added.
+        value is None, in which case only the key will be added.  If a
+        parameter value contains non-ASCII characters it can be specified as a
+        three-tuple of (charset, language, value), in which case it will be
+        encoded according to RFC2231 rules.  Otherwise it will be encoded using
+        the utf-8 charset and a language of ''.
 
-        Example:
+        Examples:
 
         msg.add_header('content-disposition', 'attachment', filename='bud.gif')
+        msg.add_header('content-disposition', 'attachment',
+                       filename=('utf-8', '', Fußballer.ppt'))
+        msg.add_header('content-disposition', 'attachment',
+                       filename='Fußballer.ppt'))
         """
         parts = []
         for k, v in _params.items():
index 79934869e6d5009a9e4411221cd71abb82f1153a..78fb9616152e2fbad01090121bba12acdd1893a4 100644 (file)
@@ -510,6 +510,29 @@ class TestMessageAPI(TestEmailBase):
         self.assertEqual(msg.get_payload(decode=True),
                          bytes(x, 'raw-unicode-escape'))
 
+    # Issue 1078919
+    def test_ascii_add_header(self):
+        msg = Message()
+        msg.add_header('Content-Disposition', 'attachment',
+                       filename='bud.gif')
+        self.assertEqual('attachment; filename="bud.gif"',
+            msg['Content-Disposition'])
+
+    def test_noascii_add_header(self):
+        msg = Message()
+        msg.add_header('Content-Disposition', 'attachment',
+            filename="Fußballer.ppt")
+        self.assertEqual(
+            'attachment; filename*="utf-8\'\'Fu%C3%9Fballer.ppt"',
+            msg['Content-Disposition'])
+
+    def test_nonascii_add_header_via_triple(self):
+        msg = Message()
+        msg.add_header('Content-Disposition', 'attachment',
+            filename=('iso-8859-1', '', 'Fußballer.ppt'))
+        self.assertEqual(
+            'attachment; filename*="iso-8859-1\'\'Fu%DFballer.ppt"',
+            msg['Content-Disposition'])
 
 
 # Test the email.encoders module
index 88805a6234bf3c11b16a36b5996eb9959ac4b249..6ca5fc8f1a922326ef7198965b158dfdb2cad749 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -11,6 +11,9 @@ What's New in Python 3.2 Beta 2?
 Library
 -------
 
+- Issue #1078919: add_header now automatically RFC2231 encodes parameters
+  that contain non-ascii values.
+
 - Issue #10188 (partial resolution): tempfile.TemporaryDirectory emits
   a warning on sys.stderr rather than throwing a misleading exception
   if cleanup fails due to nulling out of modules during shutdown.