2009-07-29 3 views
62

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

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

Так что мой вопрос: Как браузер определяет тип mime для отправки?

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

+0

application/octet-stream обозначает двоичный файл.Вы должны иметь возможность получить расширение файла, чтобы узнать, является ли он zip-файлом. Просто, чтобы уточнить, это работало для вас в FF, но не для вашего коллеги? –

+0

да, это сработало для меня в обоих браузерах – Kip

+0

взглянуть на атрибуты 'input/@ formenctype'или' form/@ enctype' – tuxSlayer

ответ

43

Хром

Хром (версия 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 имеет значение Content Type, которое установлено на 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, о котором сообщает браузер, ненадежен.

+0

спасибо! у вас есть ссылка на жесткий список в хромовом источнике? – Kip

+0

@ Kip да, я добавил ссылку. У Firefox, похоже, нет (официального) онлайн-браузера исходного кода, я должен был загрузить его с их FTP-сервера. – Stijn

5

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

Например:

HKEY_CLASSES_ROOT. застежка-молния - ContentType

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

HKEY_CLASSES_ROOT \ Мим \ Database \ Content Type

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

+0

спасибо. к сожалению, для меня и моего коллеги это, кажется, правильно в нашем реестре. я думаю, именно поэтому он работал в IE для него, но FF получает его по-другому как-то ... oh well :( – Kip

10

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

4

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

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

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

+1

Расширение не более надежное, чем HTTP-заголовок ... – Djizeus

+1

Уход за разработкой? В моем опыте браузеры всегда отправляют правильное исходное имя файла (с расширением), в то время как типы MIME сильно различаются. Поэтому да, я бы сказал, что он намного надежнее. – johndodo

+0

Правильно. Я хотел сказать, что конечный пользователь может разместить любое расширение, независимо от фактического типа, поэтому он должен не следует доверять. – Djizeus

0

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

0

По rfc1867 - Form-based file upload in HTML:

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

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

+0

да, я понимаю все это. вопрос был в том, как делает вывод браузер. – Kip

+0

Это стоит знать, правда? Если 'application/octet-stream' является catch-all, тогда другой подход состоял бы в том, чтобы доверять браузеру, если он был в состоянии сделать предположение, и выполнять собственные проверки на стороне сервера, если вы получаете' application/octet-stream' , –

Смежные вопросы