О MIME
2016-03-21
Есть такой милый стандарт MIME. Если верить Википедии, произносится это как «майм». Но я почему-то всегда произносил это неправильно как «миме». Это — Multipurpose Internet Mail Extensions. Не путать с мимами — странными молчаливыми ребятами с чрезвычайно бледными лицами.
И вы постоянно сталкиваетесь с этими MIME сообщениями.
Ибо это обычная электропочта,
то самое,
что посылается через
SMTP,
принимается через IMAP
и ещё кучу протоколов
и, в конце концов,
отображается в вашей любимой почтовой программе.
А ещё может быть сохранено в виде .eml
или .msg
файлов.
Но на самом деле MIME встречается ещё чаще,
ибо в
HTTP
что запрос,
что ответ,
по сути
(за исключением первой строки с типом запроса и статусом ответа)
являются MIME сообщениями.
MIME сообщения восходят ещё к тем временам, когда не было XML и JSON, и в Интернете правили текстовые протоколы. В MIME сообщении имеются заголовки, где название заголовка отделяется от значения двоеточием, пустая строка-разделитель, и тело сообщения.
Самым важным заголовком MIME является Content-Type
.
Content-Type: text/plain
Значение этого заголовка — это тип содержимого сообщения. И здесь мы встречаемся с величайшим вкладом этого стандарта в Порядок во Вселенной: MIME type или MIME тип.
MIME тип состоит из двух слов,
разделённых слэшем.
Первое слово — тип содержимого.
Текст — text
.
Изображение — image
.
Музыка — audio
.
Видосик — video
.
Это содержимое предназначено для обработки конкретной программой — application
.
Содержимое состоит из нескольких частей — multipart
.
Второе слово — подтип содержимого.
Просто текст без форматирования — text/plain
,
текст
в HTML разметке — text/html
.
Изображение
в JPEG — image/jpeg
,
в PNG — image/png
.
Аудио
в MP3 — audio/mp3
,
в Ogg Vorbis, или Opus, или Speex — audio/ogg
.
Видео
в MP4 — video/mp4
,
в Matroska — video/x-matroska
.
Текст в формате OpenDocument,
подразумевается,
что открываться должен в соответствующих программах, — application/vnd.oasis.opendocument.text
.
PDF документ,
должен открываться
в программах для просмотра PDF, — application/pdf
.
Типы MIME,
по-хорошему,
положено регистрировать
в IANA.
Часто при этом,
если за данным форматом данных стоит конкретная организация,
подтип начинается с vnd.
,
например: application/vnd.ms-excel
.
Но,
по устаревшим спецификациям,
можно было не регистрировать подтипы,
начинающиеся с x-
.
Они вроде как были экспериментальными,
но некоторые так здорово прижились,
что мы до сих пор имеем дело с ужастиками
вроде application/x-www-form-urlencoded
.
Этот тип,
кстати,
обозначает один из способов
отправки данных из HTML формы.
Вообще, когда у нас есть какой-то кусок байт, хорошо, если файл, то мы можем определить его содержимое несколькими способами. Можно попытаться открыть это во всех имеющихся программах, авось какая-то и переварит. Очевидно, это не очень эффективно. Если у нас есть имя файла, то значит у этого имени есть расширение (по факту — буквы после последней точки), а расширение часто даёт понять, что это за файл. Так до сих пор поступают нынешние ОС, у них записано, файлы с каким расширением в какой программе открывать. Но здесь нужно имя файла, а его может не быть, если байты пришли по Сети или вообще хранятся где-то в базе данных.
Если же у нас есть MIME тип, то мы прекрасно знаем, что это за данные. А современные ОС ещё и знают, какой программой данный MIME тип открывать. Получается, что ОС хранят соответствие между программой и расширениями имени файлов, а также между программой и связанными с нею MIME типами.
В серверостроении возникает
немного другая проблема.
У нас есть файл,
и его надо передать по Сети (по HTTP).
Чтобы сделать это правильно,
нам нужно выдать MIME тип пересылаемых данных.
К сожалению,
ОС,
как правило,
не предоставляет механизма узнать
MIME тип конкретного файла.
Это банально нигде не хранится.
Поэтому серверам приходится
выводить тип из расширения имени файла,
для этого есть даже специальные
файлики-БД.
Либо применять специальную магию.
Очень часто тип файла можно узнать
по нескольким первым байтам самого файла.
Например,
все изображения PNG начинаются с байт 89 50 4E 47
,
последние три байта — это буквы PNG
в ASCII.
Вот MIME тип и определяется по началу файла.
Мораль такова. MIME тип всегда передаётся по сети. MIME тип однозначно даёт знать, что это за данные, и что с ними можно сделать. А значит, если вы сохраняете байтики в базу данных, или ещё куда-нибудь, не потеряйте MIME тип, сохраните его рядышком. Потом это может очень пригодиться.
А если вы создаёте свой формат данных, который может быть полезен за пределами данного запроса-ответа, который может быть стоит куда-то сохранить, придумайте для него свой MIME тип.
Особняком стоит тип multipart
.
С его помощью можно засовывать в одно сообщение
несколько различных содержимых.
Именно так создаются письма с вложениями.
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=part
--part
Content-Type: text/plain
This is a text message with PNG attachment.
--part
Content-Type: image/png
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=stackoverflow.png
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCElEQVQ4y7XRLUtEQRjF8Z/ulgG9
BrNpqy/NZhKDi/gFBIMoaJFpCmLSYvIWQQ0WNRj9CgbDCqIGwWw3TLlBRMsNC3tXr4gHhgnPM4f/
OUMNpRjG+s0G1dNlimH1LwZr2E8xtGobpBhWUwzzkOXFC/ZKkkZdgmecpBgOUgyNLC+O8Iad7qWB
H8obxTmGsIR3PGAxy4sONCsetbCL0ywvbtFOMWzhDsvYwAI6lQQphhGslMV94BgXmMQl5spOakWY
wTrauMZhlheP3TtVEW7wiqfybGOzxO9RVYSpEnccE+U9jPssL2b74p6dX31+9xsphumqvaoIn9/U
0kPcY5DlxYBfqFk3xr/pC6p9USZurgviAAAAAElFTkSuQmCC
--part--
Распаковать это безобразие можно,
например,
с помощью программы munpack
.
Для типа multipart
обязательно задаётся ещё и параметр boundary
—
разделитель частей сообщения.
Заголовок Content-Transfer-Encoding
указывает на то,
как закодировано содержимое.
Бинарные файлы в электропочте
как правило кодируются
в Base64,
чтобы ограничиться при передаче
исключительно ASCII символами.
Что приводит
к распуханию бинарных файлов в письме на треть.
А вот в HTTP принято пересылать бинарные данные как есть.
Заголовок Content-Disposition
указывает,
как поступить с содержимым.
Если attachment
,
значит,
это отдельный файл,
имя которого может быть задано тут же.
В случае HTTP attachment
означает,
что браузер должен скачать файл,
а не отобразить его в своём окне.
multipart
сообщения
(с разными boundary
)
могут быть вложены друг в друга.
Получается целое дерево вложенных
документов.
Таким образом можно даже закодировать целый HTML
со всеми сопутствующими картинками и стилями.
Помните о MIME. Даже стандарты, которым уже больше тридцати лет, вполне себе существуют и работают где-то рядом. А MIME тип — это вообще штука, которая встречается на каждом шагу.