Как браузер определяет MIME-тип загруженного файла?
-
05-07-2019 - |
Вопрос
У меня есть веб-приложение, в которое пользователю необходимо загрузить 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
, если тип не может быть выведен . р>