2009-07-29 18 views
62

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.¿Cómo se determina el tipo de mimo de un archivo cargado por el navegador?

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).

Así que mi pregunta es: ¿Cómo determina el navegador qué tipo de mime enviar?

Tenga en cuenta: Sé que el tipo de mime es enviado por 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.

+0

application/octet-stream designa un archivo binario.Debería poder obtener la extensión del archivo para ver si es un archivo zip. Solo para aclarar, ¿esto funcionó para usted en FF, pero no en su compañero de trabajo? –

+0

sí, funcionó para mí en ambos navegadores – Kip

+0

eche un vistazo a los atributos 'input/@ formenctype'or' form/@ enctype' – tuxSlayer

Respuesta

43

Chrome

Chrome (versión 38 como de la escritura) tiene 3 maneras 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 no modificables llegar un poco más temprano 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, de modo que el navegador vuelve al registro del sistema. HKEY_CLASSES_ROOT\.csv tiene un valor denominado Content Type que se establece en application/vnd.ms-excel.

Internet Explorer

Otra vez usando el mismo ejemplo, el navegador informará application/vnd.ms-excel. Creo que es razonable suponer que Internet Explorer (versión 11 al momento de escribir) utiliza 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 de 32 como de la escritura) funciona de una 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 no modificables vienen anteriormente en el archivo, en algún lugar cerca de la línea 441. Usted 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á application/vnd.ms-excel (elemento 3 en la lista).

Resumen

Las listas no modificables 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.

+0

gracias! ¿Tiene un enlace a la lista codificada en la fuente Chrome? – Kip

+0

@Kip Sí, he agregado un enlace. Firefox no parece tener un buscador de código fuente en línea (oficial), tuve que descargarlo desde su servidor FTP. – Stijn

5

Esta es probablemente OS y posiblemente navegador dependiente, pero en Windows, el tipo MIME para una extensión de archivo determinado se puede encontrar buscando en el registro bajo HKCR:

Por ejemplo:

HKEY_CLASSES_ROOT. zip - ContentType

para ir de MIME para la extensión de archivo, se puede ver en las llaves bajo

HKEY_CLASSES_ROOT \ Mime \ Database \ Content Type

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

+0

gracias. desafortunadamente, tanto para mí como para mi compañero de trabajo esto parece ser correcto en nuestro registro. Supongo que es por eso que funcionó en IE para él, pero FF lo está recibiendo de una manera diferente ... oh bien :( – Kip

10

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.

4

Si bien esta no es una respuesta a su pregunta, resuelve el problema que está tratando de resolver. YMMV.

Como escribió, el tipo de mime 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 mime, puede usar los propios mime.types de su apache para determinar su lado del servidor.

+1

La extensión no es más confiable que el encabezado http ... – Djizeus

+1

¿Cuidar para elaborar? En mi experiencia los navegadores siempre envían el nombre de archivo original correcto (con extensión) mientras que los tipos MIME varían mucho. Así que sí, yo diría que es mucho más confiable. – johndodo

+0

Correcto. Quise decir que el usuario final puede poner cualquier extensión, independientemente del tipo real, por lo que debería no es de confianza. – Djizeus

0

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, simplemente verifique la extensión del archivo para asegurarse de que sea.zip o cualquier otra compresión que estés buscando!

0

Según rfc1867 - Form-based file upload in HTML:

Cada parte debe ser etiquetado con un tipo de contenido apropiado si se conoce el tipo medios de comunicación (por ejemplo, deducida de la extensión de archivo o sistema operativo información escribiendo) o como aplicación/octet-stream.

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

+0

sí, entiendo todo esto. la pregunta era ¿cómo inferir el navegador? – Kip

+0

Eso vale la pena saberlo, ¿verdad? Si 'application/octet-stream' es el catch-all, entonces otro enfoque sería confiar en el navegador si ha sido capaz de adivinar, y hacer sus propias pruebas del lado del servidor si obtiene' application/octet-stream' . –

Cuestiones relacionadas