2013-08-07 11 views
15

Próbuję adresować this issue, staram się owijać głowę wokół różnych funkcji w standardowej bibliotece Pythona mających na celu wspieranie RFC 2231. Główny cel tego RFC wydaje się być trzykrotny: zezwalanie na kodowanie inne niż ASCII w parametrach nagłówka, zwracanie uwagi na język danej wartości i pozwalanie parametrom nagłówka na rozciąganie wielu linii. Model email.util library udostępnia kilka funkcji umożliwiających radzenie sobie z różnymi aspektami. O ile mogę powiedzieć, że działa w następujący sposób:Dekodowanie nagłówków RFC 2231

decode_rfc2231 dzieli tylko wartość takiego parametru w jego części, podobnie jak to:

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

decode_params dba wykrywania parametrów RFC2231 kodowane. Gromadzi części, które należą do siebie, a także dekoduje łańcuch zakodowany w url do sekwencji bajtów. Ta sekwencja bajtów jest jednak kodowana jako łacińska1. Wszystkie wartości są ujęte w cudzysłowy. Co więcej, istnieje pewien specjalny sposób postępowania z pierwszym argumentem, który wciąż musi być krotką dwóch elementów, ale te dwie są przekazywane do wyniku bez modyfikacji.

>>> 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 może być użyty do konwersji to trójka, języka i kodowania sekwencji bajtów w odpowiednie ciąg Unicode. Tym, co mnie wprawiło w zakłopotanie, jest fakt, że jeśli dane wejściowe były tak potrójne, wówczas cytaty zostaną przeniesione na wyjście. Jeśli, z drugiej strony, dane wejściowe były pojedynczym cudzysłowem, wówczas te cytaty zostaną usunięte.

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

Wydaje się więc, że aby wykorzystać cały ten sprzęt, to muszę dodać kolejny krok do cytatu trzeci element każdej krotki bym spotkać. Czy to prawda, czy też brakuje mi tutaj jakiegoś punktu? Musiałem dowiedzieć się wielu powyższych z pomocą kodu źródłowego, ponieważ dokumenty są nieco niejasne na temat szczegółów. Nie mogę sobie wyobrazić, co może być przyczyną tego selektywnego niedopasowania. Czy to ma sens?

Jakie jest najlepsze odniesienie do korzystania z tych funkcji?

Najlepsze, co dotąd znalazłem to email.message.Messageimplementation. Tam proces wydaje się być mniej więcej opisany powyżej, ale każde pole jest niecytowane przez _unquotevalue po decode_params, a tylko get_filename i get_boundary zwinąć ich wartości, wszystkie inne zwracają zamiast tego krotkę. Mam nadzieję, że jest coś bardziej użytecznego.

+1

nie jest odpowiedź, ale mieliśmy długą dyskusję na temat RFC 2231, która może być przydatna w innym pytanie. Chodziło o pola formularzy. - http://stackoverflow.com/questions/20591599/why-arent-post-names-with-unicode-sent-orrectly-when-using-multipart-forma-data/20592910#20592910 –

+0

@RobStarling: Dzięki! RFC 2231 już od pewnego czasu [nawiedza mnie] (http://stackoverflow.com/q/13514713/1468366), zwłaszcza, że ​​[ktoś zauważył] (https://github.com/facebook/tornado/pull/ 869 # issuecomment-23632083), że [HTML5 wymaga * nie * używania go dla nazw plików] (http://www.w3.org/html/wg/drafts/html/master/forms.html#multipart-form-data) . Ale HTML5 nie jest jeszcze standardem ... – MvG

+0

o super. ludzie HTML5 modyfikują HTTP? Ugh. –

Odpowiedz

4

Obecnie funkcje z email.utils są rzadko używane poza email.message. Większość użytkowników woli bezpośrednio używać numeru email.message.Message. Istnieje nawet trochę stary issue report o dodawaniu testów jednostkowych (które z pewnością można wykorzystać jako przykłady) do Pythona, nawet jeśli nie jestem pewien jak to się ma do email.util.

Krótki przykład, który znalazłem to this blogpost, który jednak nie zawiera więcej niż jednego zdania i kilka SLOC informacji o analizie RFC2231. Autor zauważa jednak, że wiele MTA używa zamiast tego RFC2047. W zależności od Twojego zastosowania może to również stanowić problem.

Sądząc po kilku przykładach, które mogłem znaleźć, zakładam, że twój sposób analizowania przy użyciu email.util jest jedynym sposobem, aby przejść, nawet jeśli zrozumienie długiej listy jest nieco brzydkie.

Z powodu braku przykładów pod pewnym względem warto napisać nowy parser RFC2231 (jeśli naprawdę potrzebujesz lepszego, może szybszego lub piękniejszego kodu). Nowa implementacja może być oparta na istniejących implementacjach, takich jak Dovecot RFC2231 parser ze względu na kompatybilność (można nawet użyć Dovecot unit test.Kod kodu C wydaje mi się dość skomplikowany i ponieważ nie mogę znaleźć żadnej implementacji Pythona oprócz email.util i Python2 backports z email.util zadaniem przeniesieniem do Pythona nie będzie łatwe (zauważ, że Dovecot jest LGPL-licensed, co może być problemem w projekcie)

myślę API email.util RFC2231 nie został zaprojektowany dla łatwego użycia autonomicznego ale bardziej jako stos metody użytkowe do użycia w email.message.Message.

0

Stare pytanie, ale nie mogłem znaleźć pełnej odpowiedzi, która nad tym pracuje. to jest to, co skończyło się robi (na 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)) 

Na przykład:

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