2013-08-07 33 views
15

Cố gắng giải quyết this issue, Tôi đang cố gắng bọc đầu quanh các chức năng khác nhau trong thư viện chuẩn Python nhằm hỗ trợ RFC 2231. Mục đích chính của RFC đó là gấp ba lần: cho phép mã hóa không phải ASCII trong các tham số đầu, chú ý ngôn ngữ của một giá trị đã cho và cho phép các tham số tiêu đề trải rộng trên nhiều dòng. Các email.util library cung cấp một số chức năng để đối phó với các khía cạnh khác nhau về điều này. Theo như tôi có thể nói, họ làm việc như sau:Giải mã tiêu đề RFC 2231

decode_rfc2231 chỉ chia tách giá trị của một tham số đó vào bộ phận của nó, như thế này:

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

decode_params chăm sóc phát hiện thông số RFC2231-mã hóa. Nó thu thập các phần thuộc về nhau và cũng giải mã chuỗi được mã hóa url thành chuỗi byte. Tuy nhiên, chuỗi byte này sau đó được mã hóa thành latin1. Và tất cả các giá trị được đặt trong dấu ngoặc kép. Hơn nữa, có một số xử lý đặc biệt cho đối số đầu tiên, mà vẫn phải là một bộ gồm hai phần tử, nhưng hai thứ đó được chuyển đến kết quả mà không sửa đổi.

>>> 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 có thể được sử dụng để chuyển đổi chuỗi mã hóa, ngôn ngữ và byte này thành chuỗi unicode phù hợp. Điều gì khiến tôi bối rối, mặc dù, là một thực tế là nếu đầu vào là như vậy ba, sau đó các dấu ngoặc kép sẽ được chuyển sang đầu ra. Mặt khác, nếu đầu vào là một chuỗi được trích dẫn, thì các dấu ngoặc kép này sẽ bị xóa.

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

Vì vậy, có vẻ như để sử dụng tất cả máy móc này, tôi phải thêm một bước nữa để bỏ yếu tố thứ ba của bất kỳ bộ dữ liệu nào tôi gặp phải. Điều này có đúng không, hoặc tôi đang thiếu một số điểm ở đây? Tôi đã tìm ra rất nhiều điều trên với sự trợ giúp từ mã nguồn, vì các tài liệu hơi mơ hồ về các chi tiết. Tôi không thể tưởng tượng cái gì có thể là điểm đằng sau sự lựa chọn không được chọn lọc này. Có điểm nào không?

Tham chiếu tốt nhất về cách sử dụng các chức năng này là gì?

Điều tốt nhất tôi tìm thấy cho đến nay là email.message.Messageimplementation. Ở đó, quy trình dường như gần như được nêu ở trên, nhưng mọi trường được bỏ qua _unquotevalue sau decode_params và chỉ get_filenameget_boundary thu gọn giá trị của chúng, tất cả các trường khác sẽ trả về một bộ dữ liệu thay thế. Tôi hy vọng có cái gì đó hữu ích hơn.

+1

Không phải là câu trả lời, nhưng chúng tôi đã có một cuộc thảo luận dài về RFC 2231 có thể hữu ích cho bạn trong một câu hỏi. Đó là về các lĩnh vực hình thức, mặc dù. - http://stackoverflow.com/questions/20591599/why-arent-post-names-with-unicode-sent-correctly-when-using-multipart-form-data/20592910#20592910 –

+0

@RobStarling: Cảm ơn! RFC 2231 đã [ám ảnh tôi một thời gian] [http://stackoverflow.com/q/13514713/1468366), đặc biệt là kể từ khi [ai đó chỉ ra] (https://github.com/facebook/tornado/pull/ 869 # issuecomment-23632083) rằng [HTML5 yêu cầu * không * sử dụng nó cho tên tệp] (http://www.w3.org/html/wg/drafts/html/master/forms.html#multipart-form-data) . Nhưng HTML5 không phải là một tiêu chuẩn được nêu ra ... – MvG

+0

oh tuyệt vời. các nhân viên HTML5 đang điều chỉnh HTTP? Ugh. –

Trả lời

4

Hiện tại, các chức năng từ email.utils hiếm khi được sử dụng bên cạnh trong số email.message. Hầu hết người dùng dường như thích sử dụng trực tiếp email.message.Message. Thậm chí còn có một số cũ issue report về việc thêm các bài kiểm tra đơn vị (chắc chắn sẽ có thể sử dụng làm ví dụ) cho Python, ngay cả khi tôi không chắc chắn về cách nó liên quan đến email.util.

Ví dụ ngắn tôi tìm thấy là this blogpost, tuy nhiên, không chứa nhiều hơn một câu và một vài SLOC thông tin về phân tích cú pháp RFC2231. Tuy nhiên, tác giả lưu ý rằng nhiều MTA sử dụng RFC2047 để thay thế. Tùy thuộc vào usecase của bạn, đó cũng có thể là một vấn đề.

Đánh giá từ một vài ví dụ tôi có thể thấy rằng tôi giả sử cách phân tích cú pháp của bạn bằng cách sử dụng email.util là cách duy nhất để thực hiện, ngay cả khi hiểu danh sách dài hơi xấu xí.

Vì thiếu các ví dụ về một số khía cạnh, nên viết một trình phân tích RFC2231 mới (nếu bạn thực sự cần một codebase tốt hơn, có thể nhanh hơn hoặc đẹp hơn). Triển khai mới có thể dựa trên các triển khai hiện có như Dovecot RFC2231 parser vì lý do tương thích (bạn thậm chí có thể sử dụng Dovecot unit test. Vì mã C có vẻ khá phức tạp đối với tôi và vì tôi không thể tìm thấy bất kỳ triển khai python nào bên cạnh email.util và Python2 backports của email.util nhiệm vụ chuyển sang Python sẽ không dễ dàng (lưu ý rằng Dovecot là LGPL-licensed, có thể là một vấn đề trong dự án của bạn)

Tôi nghĩ rằng email.util RFC2231 API chưa được thiết kế để sử dụng độc lập dễ dàng nhưng hơn một đống các phương pháp tiện ích để sử dụng trong email.message.Message.

0

Câu hỏi cũ, nhưng tôi không thể tìm thấy câu trả lời hoàn chỉnh về công việc này. đây là những gì tôi đã kết thúc làm (trên 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)) 

Ví dụ:

>>> 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śšłžźżçćčñń 
Các vấn đề liên quan