5. Поле заголовка Content-Transfer-Encoding
Многие типы среды, которые могут передаваться посредством электронной почты, представляются в своем естественном формате, таком как 8-битовые символы или двоичные данные. Такие данные не могут быть переданы посредством некоторых транспортных протоколов. Например, RFC 821 (SMTP) ограничивает почтовые сообщения 7-битовым символьным набором ASCII со строками короче 1000 символов, включая строчные разделители CRLF.
Таким образом, необходимо определить стандартный механизм кодировки таких данных в 7-битный формат с короткими строками. В MIME для этой цели используется поле заголовка "Content-Transfer-Encoding". Это поле не было определено каким-либо прежним стандартом.
5.1. Синтаксис Content-Transfer-Encoding
Значения полей Content-Transfer-Encoding представляют собой лексему, характеризующую тип кодирования, как это описано ниже.
encoding | := | "Content-Transfer-Encoding" ":" mechanism |
mechanism | := | "7bit" / "8bit" / "binary" / "quoted-printable" / "base64" / ietf-token / x-token |
Эти значения не чувствительны к регистру, в котором напечатаны. - Base64, BASE64 и bAsE64 эквивалентны. Тип кодировки 7BIT требует, чтобы тело уже имело 7-битовое представление, пригодное для передачи. Это значение по умолчанию, означает, что в отсутствии поля Transfer-Encoding предполагается "Content-Transfer-Encoding: 7BIT".
5.2. Семантика Content-Transfer-Encodings
Лексема Content-Transfer-Encoding предоставляет два вида информации. Она специфицирует, какому виду кодового преобразования подвергнуто тело сообщения и, следовательно, какая процедура декодирования должна использоваться при восстановлении исходного вида сообщения.
Преобразовательная часть любого Content-Transfer-Encodings специфицирует явно или неявно алгоритм декодирования, который либо восстановит исходный вид последовательности или обнаружит ошибку. Преобразования Content-Transfer-Encodings для нормальной работы никогда не требует какой-либо дополнительной внешней информации.
Преобразование заданной последовательности октетов в другую эквивалентную кодовую последовательность совершенно легально.
В настоящее время определены три преобразования: тождественное (никакого преобразования), преобразование в последовательность печатных символов и в последовательность кодов "base64".
Значения Content-Transfer-Encoding "7bit", "8bit" и "binary" означают, что никакого преобразования не произведено. Они указывают на тип тела сообщения, и позволяют предполагать, какое кодирование может потребоваться при передаче данных.
Кодирование в последовательность печатных символов или в кодовую последовательность base64 предполагает преобразование из произвольного исходного формата в представление "7bit", что позволяет передачу через любые транспортные среды.
Всегда должна использоваться корректная метка Content-Transfer-Encoding. Пометка данных, преобразованных программой UUENCODE и содержащих 8-битовые символы, как "7bit" не допустима, такие данные должны помечаться только как "binary".
При прочих равных условиях предпочтительным представлением является последовательность печатных символов или кодов base64.
Передача почтовых сообщений закодированных программой uuencode описана в документе RFC 1652. Но следует иметь в виду, что ни при каких обстоятельствах Content-Transfer-Encoding "binary" нельзя считать приемлемым для e-mail. Однако когда используется MIME, двоичное тело сообщение может быть помечено как таковое.
5.3. Новое значение Content-Transfer-Encodings
Программисты могут, если необходимо, определить частные значения Content-Transfer-Encoding. При этом должны использоваться x-лексемы, которые представляют собой имена с префиксом "X-", что указывает на нестандартный статус, например, "Content-Transfer- Encoding: x-my-new-encoding". Дополнительные стандартизованные значения Content-Transfer-Encoding должны быть специфицированы в официальных документах RFC.
В отличие от типов среды и субтипов, формирование новых значений Content- Transfer-Encoding категорически не рекомендуется, так как может привести к полному выходу из строя системы.
4. Реализация и применение
Если поле заголовка Content-Transfer-Encoding появляется как часть заголовка сообщения, оно относится ко всему телу сообщения. Если поле заголовка Content-Transfer-Encoding появляется в качестве части заголовка объекта, то зоной его действия будет тело этого объекта. Если объект имеет тип "multipart", то Content-Transfer-Encoding не может иметь значение "7bit", "8bit" или "binary". Следует заметить, что большинство типов среды определены в терминах октетов, а не бит, поэтому описываемые механизмы относятся к кодировке произвольных потоков октетов, а не бит. Если необходимо закодировать битовую последовательность, она должна быть преобразована в последовательность октетов с сетевой последовательностью бит ("big-endian"), в которой более ранние биты становятся старшими битами октетов. Битовые потоки, длина которых не кратна 8, должны быть дополнены нулями.
Механизмы кодировки, определенные здесь, осуществляют преобразование любых данных в ASCII. Таким образом, предположим, например, что объект имеет следующие поля заголовка:
Content-Type: text/plain; charset=ISO-8859-1
Content-transfer-encoding: base64
Это должно интерпретироваться так, что тело имеет кодировку base64, а исходные данные имели представление в ISO-8859-1.
Определенные значения Content-Transfer-Encoding могут использоваться только с определенными типами среды. В частности, категорически запрещено использовать любую кодировку отличную от "7bit", "8bit" или "binary" с любым составным типом среды, т.e. включающим и другие поля Content-Type. В настоящее время допустимы составные типы среды "multipart" и "message". Все кодировки, допустимые для тел типа multipart или message должны использоваться на самом внутреннем уровне.
Следует также заметить, что по определению, если составной объект имеет значение transfer-encoding равное "7bit", но один из составляющих объектов имеет менее регламентирующее значение, например, "8bit", тогда либо внешняя метка "7bit" является ошибкой, или внутренняя метка "8bit" устанавливает слишком высокое требование к транспортной системе (следовало проставить 7bit).
Хотя запрет использования content-transfer-encodings для составного тела может показаться чрезмерно регламентирующим, следует избегать вложенных кодирований, в которых данные подвергаются последовательно обработке несколькими алгоритмами. Вложенные кодирования заметно повышают сложность агентов пользователя. Помимо очевидных проблем эффективности при множественном кодировании они могут затемнить базовую структуру сообщения. В частности они могут подразумевать, что необходимо несколько операций декодирования, чтобы определить, какие типы тел содержит сообщение. Запрет вложенных кодировок может осложнить работу некоторых почтовых шлюзов, но это представляется меньшей бедой, чем осложнение жизни агентов пользователя при вложенном кодировании.
Любой объект с нераспознанным значением Content-Transfer-Encoding должен рассматриваться, как если бы он имел код Content-type "application/octet-stream", вне зависимости оттого, что утверждается полем заголовка Content-Type.
Может показаться, что Content-Transfer-Encoding может быть выяснено из характеристик среды, для которой нужно осуществить кодирование или, по крайней мере, что определенное Content-Transfer-Encodings может быть предназначено для использования с определенными типами среды. Есть несколько причин, почему это не так. Во-первых, существующие различные типы транспорта, используемые для почты, некоторые кодирования могут годиться для определенных комбинаций типов среды и транспорта, но быть непригодными для других. Например, при 8-битовой передаче, при определенном символьном наборе для текста не потребуется никакого кодирования, в то время как такое кодирование очевидно необходимо для 7-битового SMTP.
Во-вторых, определенные типы среды могут требовать различного транспортного кодирования при разных обстоятельствах. Например, многие PostScript-тела могут целиком состоять из коротких строк 7-битовых кодов, и, следовательно, совсем не требуют кодирования. Другие тела PostScript (в особенности те, что используют механизм двоичного кодирования уровня 2 PostScript) могут быть представлены с использованием двоичного транспортного кодирования. Наконец, так как поле Content-Type ориентировано на то, чтобы предоставлять открытые механизмы спецификации, строгие ассоциации типов среды и кодирования эффективно соединяют спецификацию прикладного протокола с определенным транспортом нижнего уровня. Это нежелательно, так как разработчики типа среды не должны заботиться обо всех видах транспорта и их особенностях.
5.5. Транслирующее кодирование
Кодирование с использованием закавыченных строк печатных символов и кодов base64 устроено так, чтобы позволить взаимные преобразования. Единственная проблема, которая здесь возникает, это обработка принудительных разрывов строк для закавыченных последовательностей печатных символов. При преобразовании закавыченных строк в коды base64 принудительные разрывы строк отображаются последовательностями CRLF. Аналогично, последовательность CRLF в канонической форме данных, полученной после декодирования из base64, должна преобразоваться в принудительный разрыв строки в случае представления текста в виде закавыченной строки печатных символов. Каноническая модель кодирования представлена в документе RFC 2049.
5.6. Транспортное кодирование содержимого Quoted-Printable
Кодирование Quoted-Printable имеет целью представление данных, состоящих по большей части из октетов, которые соответствуют печатным символам ASCII-набора. Оно преобразует данные таким образом, что результирующие октеты не будут видоизменены при транспортировке почты. Если преобразуемые данные представляют собой ASCII-текст, то после кодирования они сохранят читабельность. Тело, которое целиком состоит из ASCII-кодов, может быть также представлено в виде закавыченной строки печатных символов.
При этом сохраняется целостность текста в процессе прохождении через шлюз, который осуществляет трансляцию символов и/или обработку разрывов строк. При этом кодировании октеты должны определяться согласно изложенным ниже правилам:
(1) | 8-битовое представление. Любой октет, за исключением CR или LF, которые являются частью последовательности разрыва строки CRLF, канонического (стандартного) формата данных может быть представлен с помощью символом "=", за которым следуют две шестнадцатеричные цифры, характеризующие значение октета. Для этих целей используются цифры шестнадцатеричного алфавита "0123456789ABCDEF". Должны использоваться прописные буквы; использование строчных букв недопустимо. Так, например, десятичное значение 12 (ASCII FF) может быть представлено как "=0C", а десятичное значение 61 (ASCII символ знака равенства) представляется с помощью "=3D". Это правило должно выполняться всегда за исключением случаев, когда правила допускают альтернативное кодирование. |
(2) | Литеральное представление. Октеты с десятичными кодами в интервале 33 - 60 включительно, и 62 - 126, включительно, могут представляться ASCII-символами, которые соответствуют этим октетам (с ! до < и с > до ~ соответственно). |
(3) | Пробелы. Октеты со значениями кодов 9 и 32 могут отображаться с помощью ASCII-символов TAB (HT) и пробел, соответственно, но не должны использоваться в конце строки. За любым символом TAB (HT) или пробел в кодируемой строке должен следовать печатный символ. В частности, символ "=" в конце каждой кодируемой строки, обозначающий "мягкий" разрыв строки (смотри правило #5), может следовать за одним или более символами TAB (HT) или SP. Отсюда следует, что октет, равный 9 или 32 появляющийся в конце кодируемой строки должен быть представлен в форме, указанной правилом #1. Это правило необходимо, так как некоторые MTA (Message Transport Agents, программы, которые передают сообщения от одного пользователя другому) дополняют строки пробелами, а другие удаляют пробелы (HT или SP) в конце строки. Следовательно, при декодировании тела, представленного в форме закавыченных печатных последовательностей, любые HT или SP должны быть удалены. |
(4) |
Разрывы строк. Разрыв строки в теле текста, представленный последовательностью CRLF в канонической форме, для закавыченной печатной строки отмечается CRLF. Последовательности типа "=0D", "=0A", "=0A=0D" и "=0D=0A" появляются в нетекстовых данных, представленных в виде закавыченных строк печатных символов. Заметим, что многие реализации могут выбрать для кодирования непосредственно локальное представление различных типов содержимого, а не преобразование в каноническую форму, кодирование и только затем преобразование в локальное представление. В частности, такая техника может быть применена к простому тексту в системах, которые используют для межстрочных разрывов последовательности, отличные от CRLF. Такая оптимизация конкретной программной реализации вполне допустима, но только когда комбинированный шаг канонизация-кодирование эквивалентен выполнению всех трех шагов отдельно. |
(5) | Мягкие разрывы строки. Кодирование с помощью закавыченных строк печатных символов требует, чтобы строки содержали не более 76 символов. Если нужно закодировать более длинные строки вводятся “мягкие” разрывы строк. Символ равенства в конце строки как раз и обозначает такой разрыв. |
(1) | Символ "=", за которым следует две шестнадцатеричные цифры, одна или обе из которых являются строчными символами (abcdef). Надежные реализации могут распознавать их как прописные буквы. |
(2) | Символ "=", за которым следует символ, не являющийся ни шестнадцатеричной цифрой (включая abcdef), ни CR из комбинации CRLF. Это не может стать частью ASCII-текста, включенного в сообщение, без преобразования в закавыченную последовательность печатных кодов. Разумным решением для надежной реализации может быть включение символа "=" и следующих за ним кодов в декодированную последовательность, без какого-либо преобразования и, если возможно, дать и сигнал агенту пользователя, что декодирование в этом месте оказалось невозможным. |
(3) | Символ "=" не может быть последним или завершающим символом в кодируемом объекте. Решением проблемы можно считать способ, предложенный в пункте (2). |
(4) | Управляющие символы, отличные от TAB, CR и LF (в качестве части CRLF) не должны присутствовать. То же справедливо для октетов с десятичными значениями больше чем 126. Если такие коды обнаруживаются в приходящих закавыченных последовательностях печатных символов, корректная реализация может исключить из декодированных данных и предупредить пользователя о том, что обнаружен нелегальный символ. |
(5) | Закодированные строки не должны быть длиннее 76 символов, не считая завершающие CRLF. Если во входном потоке обнаружены более длинные строки, надежная реализация может их декодировать, но должна предупредить пользователя об ошибке. |
quoted-printable | := | qp-line *(CRLF qp-line) | |
qp-line | := | *(qp-segment transport-padding CRLF) qp-part transport-padding | |
qp-part | := | qp-section | ; Максимальна длина 76 символов |
qp-segment | := | qp-section *(SPACE / TAB) "=" | ; Максимальна длина 76 символов |
qp-section | := | [*(ptext / SPACE / TAB) ptext] | |
ptext | := | hex-octet / safe-char | |
safe-char | := | ; Символы, не включенные в список "mail-safe" RFC 2049, не рекомендуются к применению. | |
hex-octet | := | "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F") | ; Октет должен использоваться для символов с кодами > 127, =, SP или TAB в конце строк, и рекомендуются для любого символа не указанного в списке "mail-safe" документа RFC 2049. |
transport-padding | := | *LWSP-char | ; Составители не должны генерировать заполнители ненулевой длины, но получатели должны быть способны обрабатывать заполнители, добавленные при транспортировке. |