Как браузер определяет MIME-тип загруженного файла?

StackOverflow https://stackoverflow.com/questions/1201945

Вопрос

У меня есть веб-приложение, в которое пользователю необходимо загрузить ZIP-файл.На стороне сервера я проверяю тип MIME загруженного файла, чтобы убедиться, что он application/x-zip-compressed или application/zip.

У меня это отлично работало в Firefox и IE.Однако, когда коллега проверил это, у него это не получилось в Firefox (тип отправленного mime был примерно таким: «application/octet-stream"), но работал в Internet Explorer.Наши настройки кажутся идентичными:IE8, FF 3.5.1 со всеми отключенными надстройками, Win XP SP3, WinRAR, установленный как собственный обработчик файлов .zip (не уверен, актуально ли это).

Итак, мой вопрос: Как браузер определяет, какой тип MIME отправлять?

Пожалуйста, обрати внимание:Я знаю, что тип mime отправляется браузером и, следовательно, ненадежен.Я проверяю это просто для удобства - в основном для того, чтобы выдать более понятное сообщение об ошибке, чем то, которое вы получаете при попытке открыть не-zip-файл как zip-файл, и чтобы избежать загрузки (предположительно тяжелых) библиотек zip-файлов.

Это было полезно?

Решение

Chrome

Chrome (версия 38 на момент написания) имеет 3 способа определения типа MIME и делает это в определенном порядке. Ниже приведен фрагмент файла src / net / base / mime_util.cc , метод MimeUtil :: GetMimeTypeFromExtensionHelper .

// We implement the same algorithm as Mozilla for mapping a file extension to
// a mime type.  That is, we first check a hard-coded list (that cannot be
// overridden), and then if not found there, we defer to the system registry.
// Finally, we scan a secondary hard-coded list to catch types that we can
// deduce but that we also want to allow the OS to override.

Жестко закодированные списки находятся в файле немного раньше: https://cs.chromium.org/chromium/src/net/base/mime_util.cc?l=170 ( kPrimaryMappings и kSecondaryMappings ).

Пример: при загрузке файла CSV из системы Windows с установленным Microsoft Excel Chrome сообщит об этом как application / vnd.ms-excel . Это связано с тем, что .csv не указан в первом жестко закодированном списке, поэтому браузер возвращается к системному реестру. HKEY_CLASSES_ROOT \ .csv имеет значение с именем Тип содержимого , для которого установлено значение application / vnd.ms-excel .

Internet Explorer

Снова, используя тот же пример, браузер сообщит application / vnd.ms-excel . Я думаю, что разумно предположить, что Internet Explorer (версия 11 на момент написания) использует реестр. Возможно, он также использует жестко закодированный список, такой как Chrome и Firefox, но его закрытый исходный код затрудняет проверку.

Firefox

Как указано в коде Chrome, Firefox (версия 32 на момент написания) работает аналогичным образом. Фрагмент из файла uriloader \ exthandler \ nsExternalHelperAppService.cpp , метод nsExternalHelperAppService :: GetTypeFromExtension

// OK. We want to try the following sources of mimetype information, in this order:
// 1. defaultMimeEntries array
// 2. User-set preferences (managed by the handler service)
// 3. OS-provided information
// 4. our "extras" array
// 5. Information from plugins
// 6. The "ext-to-type-mapping" category

Жестко закодированные списки находятся в начале файла, где-то рядом со строкой 441. Вы ищете defaultMimeEntries и extraMimeEntries .

С моим текущим профилем браузер сообщит о text / csv , поскольку для него есть запись в mimeTypes.rdf (пункт 2 в списке выше). Со свежим профилем, который не имеет этой записи, браузер сообщит application / vnd.ms-excel (пункт 3 в списке).

Резюме

Жестко закодированные списки в браузерах довольно ограничены. Часто тип MIME, отправляемый браузером, будет сообщаться операционной системой. И именно поэтому, как указано в вопросе, тип MIME, сообщаемый браузером, ненадежен.

Другие советы

Кип, я потратил некоторое время на чтение RFC, MSDN и MDN. Вот что я мог понять. Когда браузер обнаруживает файл для загрузки, он просматривает первый буфер данных, который он получает, а затем запускает тест для него. Эти тесты пытаются определить, является ли файл известным типом mime или нет, и если известный тип mime, он просто дополнительно проверит его на наличие известного типа mime и примет соответствующие меры. Я думаю, что IE пытается сделать это в первую очередь, а не просто определить тип файла по расширению. Эта страница объясняет это для IE http: // msdn .microsoft.com / EN-US / библиотека / ms775147% 28В = vs.85% 29.aspx . Что касается firefox, то я понял, что он пытается прочитать информацию о файле из файловой системы или записи каталога, а затем определяет тип файла. Вот ссылка для FF https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIFile. Я все еще хотел бы иметь более авторитетную информацию по этому вопросу.

Вероятно, это зависит от ОС и, возможно, браузера, но в Windows тип MIME для данного расширения файла можно найти, просмотрев реестр в разделе HKCR:

Например:

HKEY_CLASSES_ROOT.ZIP - ContentType

Чтобы перейти от MIME к расширению файла, вы можете посмотреть ключи под

HKEY_CLASSES_ROOT\Mime\Database\Тип контента

Чтобы получить расширение по умолчанию для определенного типа MIME.

Хотя это не ответ на ваш вопрос, он решает проблему, которую вы пытаетесь решить. YMMV.

Как вы писали, MIME-тип не является надежным, так как у каждого браузера есть свой способ его определения. Однако браузеры отправляют оригинальное имя (включая расширение) файла. Поэтому лучший способ справиться с этой проблемой - проверить расширение файла вместо типа MIME.

Если вам все еще нужен тип mime, вы можете использовать собственный apime-файл mime.types, чтобы определить его на стороне сервера.

Я согласен с johndodo, что существует так много переменных, которые делают MIME-типы, отправляемые из браузеров, ненадежными. Я бы исключил полученные подтипы и сосредоточился только на типе «приложение». если ваше приложение основано на php, вы можете легко сделать это с помощью функции explode (). Кроме того, просто проверьте расширение файла, чтобы убедиться, что это .zip или любое другое сжатие, которое вы ищете!

Согласно rfc1867 - загрузка файлов на основе форм в HTML :

  

Каждая часть должна быть помечена соответствующим типом содержимого, если   тип носителя известен (например, выводится из расширения файла или   информация о наборе операционной системы) или как application / octet-stream.

Насколько я понимаю, application / octet-stream является своего рода идентификатором blanket catch-all , если тип не может быть выведен .

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top