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

Kip
fonte
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.

user247702
fonte
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.

Kumar
fonte
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.

Michael A. McCloskey
fonte
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.

johndodo
fonte
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!

Seul Shahkee
fonte
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 .

smwikipedia
fonte
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,