【问题标题】:Decoding RFC 2231 headers解码 RFC 2231 标头
【发布时间】:2013-08-08 07:03:04
【问题描述】:

试图解决this issue,我试图围绕Python标准库中旨在支持RFC 2231的各种函数。该 RFC 的主要目的似乎有三个方面:允许在标头参数中使用非 ASCII 编码,注意给定值的语言,以及允许标头参数跨越多行。 email.util library 提供了几个函数来处理这方面的各个方面。据我所知,它们的工作方式如下:

decode_rfc2231 仅将此类参数的值拆分为其部分,如下所示:

>>> email.utils.decode_rfc2231("utf-8''T%C3%A4st.txt")
['utf-8', '', 'T%C3%A4st.txt']

decode_params 负责检测 RFC2231 编码的参数。它收集属于一起的部分,并将 url 编码的字符串解码为字节序列。然而,这个字节序列随后被编码为 latin1。并且所有值都用引号引起来。此外,对第一个参数有一些特殊处理,它仍然必须是两个元素的元组,但是这两个元素会直接传递给结果。

>>> email.utils.decode_params([
...   (1,2),
...   ("foo","bar"),
...   ("name*","utf-8''T%C3%A4st.txt"),
...   ("baz*0","two"),("baz*1","-part")])
[(1, 2), ('foo', '"bar"'), ('baz', '"two-part"'), ('name', ('utf-8', '', '"Täst.txt"'))]

collapse_rfc2231_value 可用于将这三重编码、语言和字节序列转换为适当的 unicode 字符串。然而,让我感到困惑的是,如果输入是这样一个三元组,那么引号将被转移到输出中。另一方面,如果输入是单引号字符串,则这些引号将被删除。

>>> [(k, email.utils.collapse_rfc2231_value(v)) for k, v in
...  email.utils.decode_params([
...   (1,2),
...   ("foo","bar"),
...   ("name*","utf-8''T%C3%A4st.txt"),
...   ("baz*0","two"),("baz*1","-part")])[1:]]
[('foo', 'bar'), ('baz', 'two-part'), ('name', '"Täst.txt"')]

所以看来,为了使用所有这些机制,我必须再添加一个步骤来取消引用我遇到的任何元组的第三个元素。这是真的,还是我在这里遗漏了一些观点?我不得不在源代码的帮助下弄清楚上面的很多内容,因为文档对细节有点模糊。我无法想象这种选择性取消引用背后的意义是什么。有道理吗?

关于如何使用这些功能的最佳参考资料是什么?

到目前为止我发现的最好的是email.message.Messageimplementation。在那里,该过程似乎与上面概述的大致相同,但每个字段在decode_params 之后通过_unquotevalue 被取消引用,并且只有get_filenameget_boundary 折叠它们的值,所有其他字段都返回一个元组。我希望有更有用的东西。

【问题讨论】:

标签: python http mime multipartform-data


【解决方案1】:

目前email.utils 中的函数除了在email.message 中之外很少使用。大多数用户似乎更喜欢直接使用email.message.Message。即使我不确定它与 email.util 的关系如何,在向 Python 添加单元测试(这肯定可以用作示例)时,甚至还有一个有点老的 issue report

我发现一个简短的例子是this blogpost,但是,它不包含一个以上的句子和一些关于 RFC2231 解析的信息的 SLOC。然而,作者指出,许多 MTA 使用 RFC2047 代替。根据您的用例,这也可能是一个问题。

从我能找到的几个例子来看,我假设你使用 email.util 解析的方式是唯一的方法,即使长列表理解有点难看。

由于在某些方面缺乏示例,编写一个新的 RFC2231 解析器可能是明智之举(如果您真的需要更好、可能更快或更漂亮的代码库)。出于兼容性原因,新的实现可以基于现有的实现,例如Dovecot RFC2231 parser(您甚至可以使用Dovecot unit test。因为C 代码对我来说似乎很复杂,而且除了email.util 之外我找不到任何python 实现和email.util 的 Python2 反向移植,移植到 Python 的任务并不容易(注意 Dovecot 是 LGPL-licensed,这可能是您项目中的一个问题)

我认为email.util RFC2231 API 的设计并不是为了方便独立使用,而是作为一堆实用方法用于email.message.Message

【讨论】:

    【解决方案2】:

    老问题,但我找不到适用于此的完整答案。所以这就是我最终做的事情(在 Python 2.7 上):

    def decode_rfc2231_header(header):
        """Decode a RFC 2231 header"""
        # Remove any quotes
        header = email.utils.unquote(header)
        encoding, language, value = email.utils.decode_rfc2231(header)
        value = urllib.unquote(value)
        return email.utils.collapse_rfc2231_value((encoding, language, value))
    

    例如:

    >>> name = u'èéêëēėęûüùúūàáâäæãåāāîïíīįì test ôöòóœøōõssśšłžźżçćčñń'
    >>> encoded_header = email.utils.encode_rfc2231(name.encode("utf8"), 'utf8', 'en')
    >>> print encoded_header 
    utf8'en'%C3%A8%C3%A9%C3%AA%C3%AB%C4%93%C4%97%C4%99%C3%BB%C3%BC%C3%B9%C3%BA%C5%AB%C3%A0%C3%A1%C3%A2%C3%A4%C3%A6%C3%A3%C3%A5%C4%81%C4%81%C3%AE%C3%AF%C3%AD%C4%AB%C4%AF%C3%AC%20test%20%C3%B4%C3%B6%C3%B2%C3%B3%C5%93%C3%B8%C5%8D%C3%B5ss%C5%9B%C5%A1%C5%82%C5%BE%C5%BA%C5%BC%C3%A7%C4%87%C4%8D%C3%B1%C5%84
    >>> print decode_rfc2231_header(encoded_header)
    èéêëēėęûüùúūàáâäæãåāāîïíīįì test ôöòóœøōõssśšłžźżçćčñń
    

    【讨论】:

      猜你喜欢
      • 2013-01-11
      • 2011-06-25
      • 2011-11-21
      • 2012-01-26
      • 2011-09-30
      • 2013-03-05
      • 2013-06-15
      • 2020-04-26
      • 2010-09-24
      相关资源
      最近更新 更多