Como o tipo MIME de um arquivo carregado é determinado pelo navegador?


87

Tenho um aplicativo da web em que o usuário precisa fazer upload de um arquivo .zip. No lado do servidor, estou verificando o tipo MIME do arquivo carregado, para ter certeza de que é application/x-zip-compressedou application/zip.

Isso funcionou bem para mim no Firefox e no IE. No entanto, quando um colega de trabalho o testou, ele falhou para ele no Firefox (o tipo MIME enviado era algo como " application/octet-stream"), mas funcionou no Internet Explorer. Nossas configurações parecem ser idênticas: IE8, FF 3.5.1 com todos os add-ons desabilitados, Win XP SP3, WinRAR instalado como manipulador de arquivo .zip nativo (não tenho certeza se isso é relevante).

Portanto, minha pergunta é: como o navegador determina que tipo de MIME enviar?

Observação: eu sei que o tipo MIME é enviado pelo navegador e, portanto, não é confiável. Estou apenas verificando como uma conveniência - principalmente para fornecer uma mensagem de erro mais amigável do que as que você recebe ao tentar abrir um arquivo não zip como um arquivo zip e para evitar o carregamento de bibliotecas de arquivo zip (presumivelmente pesadas).


application / octet-stream designa um arquivo binário. Você deve conseguir a extensão do arquivo para ver se é um arquivo zip. Só para esclarecer, isso funcionou para você no FF, mas não para seu colega de trabalho?
— Kevin Crowell

sim, funcionou para mim em ambos os navegadores
— Kip

dê uma olhada em input/@formenctypeou form/@enctypeatributos
— tuxSlayer

Respostas:


72

cromada

O Chrome (versão 38 no momento da escrita) tem 3 maneiras de determinar o tipo MIME e faz isso em uma determinada ordem. O trecho abaixo é de arquivo 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.

As listas embutidas em código vêm um pouco antes no arquivo: https://cs.chromium.org/chromium/src/net/base/mime_util.cc?l=170 ( kPrimaryMappingse kSecondaryMappings).

Um exemplo: ao fazer upload de um arquivo CSV de um sistema Windows com o Microsoft Excel instalado, o Chrome irá relatar isso como application/vnd.ms-excel. Isso ocorre porque .csvnão é especificado na primeira lista codificada, então o navegador volta para o registro do sistema. HKEY_CLASSES_ROOT\.csvtem um valor denominado Content Typedefinido como application/vnd.ms-excel.

Internet Explorer

Novamente usando o mesmo exemplo, o navegador irá relatar application/vnd.ms-excel. Acho que é razoável presumir que o Internet Explorer (versão 11 no momento da escrita) usa o registro. Possivelmente também faz uso de uma lista codificada como Chrome e Firefox, mas sua natureza de código fechado torna difícil de verificar.

Raposa de fogo

Conforme indicado no código do Chrome, o Firefox (versão 32 no momento da escrita) funciona de maneira semelhante. Snippet do arquivo uriloader\exthandler\nsExternalHelperAppService.cpp, métodonsExternalHelperAppService::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

As listas embutidas no código vêm no início do arquivo, em algum lugar perto da linha 441. Você está procurando defaultMimeEntriese extraMimeEntries.

Com meu perfil atual, o navegador reportará text/csvporque há uma entrada para ele no mimeTypes.rdf(item 2 na lista acima). Com um novo perfil, que não tem essa entrada, o navegador irá relatar application/vnd.ms-excel(item 3 da lista).

Resumo

As listas embutidas nos navegadores são bastante limitadas. Freqüentemente, o tipo MIME enviado pelo navegador será o relatado pelo sistema operacional. E é exatamente por isso, conforme declarado na pergunta, o tipo MIME relatado pelo navegador não é confiável.


1
obrigado! você tem um link para a lista codificada na fonte do Chrome?
— Kip de

@Kip sim, adicionei um link. O Firefox não parece ter um navegador de código-fonte online (oficial), tive que baixá-lo de seu servidor FTP.
— user247702

Ter o MIME como ms-excel para CSV é irritante, pergunto por que ele não está na lista codificada.
— Kris

Seria bom saber se houve algumas atualizações na detecção do tipo MIME desde 2014.
— Vitaly Isaev

1
@VitalyIsaev uma olhada rápida no código do Chrome mostra que isso não mudou desde 2014.
— user247702

12

Kip, passei algum tempo lendo RFCs, MSDN e MDN. Aqui está o que eu pude entender. Quando um navegador encontra um arquivo para upload, ele examina o primeiro buffer de dados que recebe e executa um teste nele. Esses testes tentam determinar se o arquivo é um tipo MIME conhecido ou não e, se for um tipo MIME conhecido, ele simplesmente fará um teste adicional para qual tipo MIME conhecido e tomará as medidas adequadas. Acho que o IE tenta fazer isso primeiro, em vez de apenas determinar o tipo de arquivo da extensão. Esta página explica isso para o IE http://msdn.microsoft.com/en-us/library/ms775147%28v=vs.85%29.aspx . Para o firefox, o que pude entender é que ele tenta ler as informações do arquivo do sistema de arquivos ou da entrada do diretório e, em seguida, determina o tipo de arquivo. Aqui está um link para FF https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIFile. Eu ainda gostaria de ter informações mais confiáveis ​​sobre isso.


8

Provavelmente depende do sistema operacional e do navegador, mas no Windows, o tipo MIME para uma determinada extensão de arquivo pode ser encontrado no registro em HKCR:

Por exemplo:

HKEY_CLASSES_ROOT.zip - ContentType

Para ir de MIME para extensão de arquivo, você pode olhar as chaves em

HKEY_CLASSES_ROOT \ Mime \ Database \ Content Type

Para obter a extensão padrão para um tipo MIME específico.


obrigado. infelizmente, tanto para mim quanto para meu colega de trabalho isso parece estar correto em nosso registro. Acho que é por isso que funcionou no IE para ele, mas FF está entendendo de maneira diferente de alguma forma ... bem :(
— Kip

5

Embora não seja uma resposta à sua pergunta, ela resolve o problema que você está tentando resolver. YMMV.

Como você escreveu, o tipo MIME não é confiável, pois cada navegador tem sua maneira de determiná-lo. No entanto, os navegadores enviam o nome original (incluindo a extensão) do arquivo. Portanto, a melhor maneira de lidar com o problema é inspecionar a extensão do arquivo em vez do tipo MIME.

Se você ainda precisa do tipo mime, pode usar seu próprio mime.types do apache para determiná-lo do lado do servidor.


1
Cuidado ao elaborar? Na minha experiência, os navegadores sempre enviam o nome do arquivo original correto (com extensão), enquanto os tipos MIME variam muito. Então, sim, eu diria que é muito mais confiável.
— johndodo

Corrigir. Eu quis dizer que o usuário final pode colocar qualquer ramal, independente do tipo real, por isso não deve ser confiável.
— Djizeus

Isso é verdade, mas não importa se você usa extensão ou tipo MIME - você nunca deve confiar na entrada fornecida pelo usuário. Mas OP afirmou explicitamente que está ciente desse problema, então isso não faz parte da questão. A propósito, eu agradeceria se você removesse o downvote (presumo que tenha vindo de você).
— johndodo de

Você tem razão, não prestei atenção ao não na questão, minha má. Eu posso cancelar meu voto, mas você terá que editar a resposta para isso (imposto pelo sistema) ...
— Djizeus

Sim, concordo com johndodo. Como Stijn explicou em sua resposta acima, o Chrome e o Firefox verificam a extensão primeiro. Eles estão fazendo a mesma coisa no final.
— Jenix

0

Eu concordo com o johndodo, existem tantas variáveis ​​que tornam os tipos MIME enviados de navegadores não confiáveis. Gostaria de excluir os subtipos que são recebidos e focar apenas no tipo, como 'aplicativo'. se o seu aplicativo for baseado em php, você pode fazer isso facilmente usando a função explode (). além disso, basta verificar a extensão do arquivo para ter certeza de que é .zip ou qualquer outra compactação que você esteja procurando!


0

De acordo com rfc1867 - Upload de arquivo baseado em formulário em HTML :

Cada parte deve ser rotulada com um tipo de conteúdo apropriado se o tipo de mídia for conhecido (por exemplo, inferido da extensão do arquivo ou informações de digitação do sistema operacional) ou como aplicativo / fluxo de octeto.

Então, meu entendimento é, application/octet-streamé como um blanket catch-allidentificador se o tipo não puder ser inferido .


sim, eu entendo tudo isso. a questão era como o navegador infere.
— Kip

Mas vale a pena saber, certo? Se esse application/octet-streamfor o ponto-chave, outra abordagem seria confiar no navegador, se ele foi capaz de fazer uma estimativa, e fazer seus próprios testes do lado do servidor, se você conseguir application/octet-stream.
— MikeBeaton,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.