¿Cómo es el tipo de mime de un archivo cargado determinado por el navegador?

Tengo una aplicación web donde el usuario necesita cargar un archivo .zip. En el lado del servidor, estoy verificando el tipo de mime del archivo cargado, para asegurarme de que sea application/x-zip-compressed o application/zip .

Esto funcionó bien para mí en Firefox y IE. Sin embargo, cuando un compañero de trabajo lo probó, falló para él en Firefox (el tipo de mime enviado era algo así como ” application/octet-stream “) pero funcionaba en Internet Explorer. Nuestras configuraciones parecen ser idénticas: IE8, FF 3.5.1 con todos los complementos deshabilitados, Win XP SP3, WinRAR instalado como controlador de archivo nativo .zip (no estoy seguro si eso es relevante).

Entonces mi pregunta es: ¿cómo determina el navegador qué tipo de mimo enviar?

Tenga en cuenta: Sé que el tipo de mime lo envía el navegador y, por lo tanto, no es confiable. Solo lo estoy verificando como una conveniencia, principalmente para dar un mensaje de error más amigable que los que se obtienen al tratar de abrir un archivo no zip como un archivo zip, y para evitar cargar las (presumiblemente pesadas) librerías de archivos zip.

Cromo

Chrome (versión 38 desde el momento de la escritura) tiene 3 formas de determinar el tipo MIME y lo hace en un orden determinado. El siguiente fragmento es del archivo src/net/base/mime_util.cc , método 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. 

Las listas codificadas vienen un poco antes en el archivo: https://cs.chromium.org/chromium/src/net/base/mime_util.cc?l=170 ( kPrimaryMappings y kSecondaryMappings ).

Un ejemplo: al cargar un archivo CSV desde un sistema Windows con Microsoft Excel instalado, Chrome informará esto como application/vnd.ms-excel . Esto se debe a que .csv no está especificado en la primera lista codificada, por lo que el navegador vuelve al registro del sistema. HKEY_CLASSES_ROOT\.csv tiene un valor llamado Content Type que se establece en application/vnd.ms-excel .

explorador de Internet

Usando de nuevo el mismo ejemplo, el navegador informará la application/vnd.ms-excel . Creo que es razonable suponer que Internet Explorer (versión 11 al momento de escribir) usa el registro. Posiblemente también haga uso de una lista codificada como Chrome y Firefox, pero su naturaleza de código cerrado dificulta su verificación.

Firefox

Como se indica en el código de Chrome, Firefox (versión 32 al momento de la escritura) funciona de manera similar. Fragmento del archivo uriloader\exthandler\nsExternalHelperAppService.cpp , método 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 

Las listas codificadas vienen antes en el archivo, en algún lugar cerca de la línea 441. Está buscando defaultMimeEntries y extraMimeEntries .

Con mi perfil actual, el navegador informará text/csv porque hay una entrada para él en mimeTypes.rdf (elemento 2 en la lista anterior). Con un perfil nuevo, que no tiene esta entrada, el navegador informará la application/vnd.ms-excel (elemento 3 en la lista).

Resumen

Las listas codificadas en los navegadores son bastante limitadas. A menudo, el tipo de MIME enviado por el navegador será el informado por el sistema operativo. Y esta es exactamente la razón por la cual, como se afirma en la pregunta, el tipo MIME informado por el navegador no es confiable.

Kip, pasé un tiempo leyendo RFC, MSDN y MDN. Esto es lo que podría entender. Cuando un navegador encuentra un archivo para cargar, mira el primer buffer de datos que recibe y luego ejecuta una prueba en él. Estas pruebas intentan determinar si el archivo es un tipo de mimo conocido o no, y si se conoce el tipo de mimo simplemente lo probará más para el tipo de mimo conocido y actuará en consecuencia. Creo que IE intenta hacer esto primero en lugar de simplemente determinar el tipo de archivo desde la extensión. Esta página explica esto para IE http://msdn.microsoft.com/en-us/library/ms775147%28v=vs.85%29.aspx . Para Firefox, lo que pude entender es que intenta leer la información del archivo del sistema de archivos o la entrada del directorio y luego determina el tipo de archivo. Aquí hay un enlace para FF https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIFile . Me gustaría tener más información fidedigna sobre esto.

Probablemente este sea el sistema operativo y, posiblemente, el navegador, pero en Windows, el tipo MIME para una extensión de archivo dada se puede encontrar buscando en el registro en HKCR:

Por ejemplo:

HKEY_CLASSES_ROOT.zip – ContentType

Para ir de MIME a la extensión de archivo, puede mirar las teclas debajo

HKEY_CLASSES_ROOT \ Mime \ Database \ Content Type

Para obtener la extensión predeterminada para un tipo MIME en particular.

Si bien esta no es una respuesta a tu pregunta, sí resuelve el problema que intentas resolver. YMMV.

Como escribió, el tipo de mimo no es confiable ya que cada navegador tiene su manera de determinarlo. Sin embargo, los navegadores envían el nombre original (incluida la extensión) del archivo. Entonces, la mejor forma de lidiar con el problema es inspeccionar la extensión del archivo en lugar del tipo MIME.

Si aún necesita el tipo de mimo, puede usar los mime.types de su propio apache para determinarlo en el servidor.

Estoy de acuerdo con johndodo, hay tantas variables que hacen que los tipos de mime que se envían desde navegadores no sean confiables. Excluiría los subtipos que se reciben y solo me enfocaré en el tipo como ‘aplicación’. si su aplicación está basada en php, puede hacer esto fácilmente mediante el uso de la función de explosión (). Además, solo revisa la extensión del archivo para asegurarte de que sea .zip o cualquier otra compresión que estés buscando.

De acuerdo con rfc1867 – Carga de archivos basada en formularios en HTML :

Cada parte debe etiquetarse con un tipo de contenido apropiado si el tipo de medio es conocido (por ejemplo, inferido de la extensión de archivo o de la información de tipeo del sistema operativo) o como application / octet-stream.

Así que mi entendimiento es que application/octet-stream es como un identificador blanket catch-all si el tipo no puede ser inferido .