Deencoding de encabezados RFC 2231

Tratando de abordar este problema , estoy tratando de comprender las diversas funciones de la biblioteca estándar de Python que apunta a ser compatible con RFC 2231 . El objective principal de ese RFC parece ser triple: permitir la encoding no ASCII en los parámetros del encabezado, observar el idioma de un valor determinado y permitir que los parámetros del encabezado abarquen varias líneas. La biblioteca email.util proporciona varias funciones para tratar varios aspectos de esto. Por lo que puedo decir, funcionan de la siguiente manera:

decode_rfc2231 solo divide el valor de dicho parámetro en sus partes, como esto:

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

decode_params se encarga de detectar los parámetros codificados en RFC2231. Recostack partes que pertenecen juntas y también decodifica la cadena codificada en url a una secuencia de bytes. Esta secuencia de bytes, sin embargo, luego se codifica como latin1. Y todos los valores están entre comillas. Además, hay un manejo especial para el primer argumento, que todavía tiene que ser una tupla de dos elementos, pero esos dos pasan al resultado sin modificaciones.

 >>> 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 se puede usar para convertir este triple de encoding, idioma y secuencia de bytes en una cadena Unicode adecuada. Sin embargo, lo que me ha confundido es el hecho de que si la entrada era tan triple, entonces las comillas se trasladarán a la salida. Si, por otro lado, la entrada era una sola cadena entre comillas, entonces estas comillas serán eliminadas.

 >>> [(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"')] 

Así que parece que para usar toda esta maquinaria, tendría que agregar otro paso para anular el tercer elemento de cualquier tupla con la que me encontraría. ¿Es esto cierto, o me estoy perdiendo algún punto aquí? Tuve que resolver mucho de lo anterior con la ayuda del código fuente, ya que los documentos son un poco vagos en los detalles. No puedo imaginar lo que podría ser el punto detrás de esta cita selectiva. ¿Hay algún punto al respecto?

¿Cuál es la mejor referencia sobre cómo usar estas funciones?

Lo mejor que encontré hasta ahora es la implementación del email.message.Message . email.message.Message . Allí, el proceso parece ser aproximadamente el descrito anteriormente, pero todos los campos no se _unquotevalue través de _unquotevalue después de decode_params , y solo get_filename y get_boundary colapsan sus valores, todos los demás devuelven una tupla. Espero que haya algo más útil.

Actualmente, las funciones de email.utils rara vez se utilizan, además de dentro de email.message . La mayoría de los usuarios parecen preferir el uso de email.message.Message directamente. Incluso hay un informe un tanto antiguo sobre la adición de pruebas unitarias (que ciertamente se podrían usar como ejemplos) a Python, incluso si no estoy seguro de cómo se relaciona con email.util .

Un pequeño ejemplo que encontré es este blogpost que, sin embargo, no contiene más de una oración y algunos SLOC de información sobre el análisis RFC2231. El autor señala, sin embargo, que muchos MTA utilizan RFC2047 en su lugar. Dependiendo de su caso de uso, eso también podría ser un problema.

A juzgar por los pocos ejemplos que pude encontrar, asumo que tu forma de analizar usando email.util es la única, aunque la comprensión de la lista larga sea algo fea.

Debido a la falta de ejemplos en algunos aspectos, podría ser conveniente escribir un nuevo analizador RFC2231 (si realmente necesita un código base mejor, tal vez más rápido o más hermoso). Una nueva implementación podría basarse en implementaciones existentes como el analizador Dovecot RFC2231 por razones de compatibilidad (incluso podría usar la prueba unitaria de Dovecot . Como el código C me parece bastante complejo y, como no puedo encontrar ninguna implementación de python, además de email.util y los backports de email.util de email.util la tarea de portar a Python no será fácil (tenga en cuenta que Dovecot tiene licencia LGPL , lo que podría ser un problema en su proyecto)

Creo que la API de email.util RFC2231 no se ha diseñado para un uso autónomo fácil, sino más bien como una stack de métodos de utilidad para usar en email.message.Message .

Pregunta antigua, pero no pude encontrar una respuesta completa que funcione en esto. Así que esto es lo que terminé haciendo (en 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)) 

Por ejemplo:

 >>> 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śšłžźżçćčñń