ユーザーが.Zipファイルをアップロードする必要があるWebアプリがあります。サーバー側では、アップロードされたファイルのMIMEタイプを確認して、application/x-Zip-compressed
またはapplication/Zip
。
これはFirefoxとIEでうまくいきました。ただし、同僚がそれをテストすると、Firefoxで失敗しました(送信されたMIMEタイプは「application/octet-stream
")がInternet Explorerで動作しました。セットアップは同一のようです。IE8、すべてのアドオンを無効にしたFF 3.5.1、Win XP SP3、WinRARはネイティブ.Zipファイルとしてインストールされましたハンドラー(それが関連するかどうかはわかりません)。
だから私の質問は次のとおりです。ブラウザはどのMIMEタイプを送信するかをどのように決定しますか?
注:MIMEタイプはブラウザから送信されるため、信頼性が低いことがわかっています。私はそれを便宜としてチェックしています-主に、非ZipファイルをZipファイルとして開こうとするよりもわかりやすいエラーメッセージを表示し、(おそらく重い)Zipファイルライブラリをロードしないようにします。
Chrome(執筆時点のバージョン38)には、MIMEタイプを特定する3つの方法があり、特定の順序でそうします。以下のスニペットは、ファイル_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=17 (kPrimaryMappings
およびkSecondaryMappings
)。
例:Microsoft ExcelがインストールされたWindowsシステムからCSVファイルをアップロードする場合、Chromeはこれを_application/vnd.ms-Excel
_として報告します。これは_.csv
_が最初にハードコードされたリスト、ブラウザはシステムレジストリにフォールバック_HKEY_CLASSES_ROOT\.csv
_には_Content Type
_という名前の値があり、_application/vnd.ms-Excel
_に設定されます。
再び同じ例を使用すると、ブラウザは_application/vnd.ms-Excel
_を報告します。 Internet Explorer(執筆時点のバージョン11)がレジストリを使用していると仮定するのは合理的だと思います。おそらく、Chromeおよび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
_(上のリストの項目2)にエントリがあるため、ブラウザは_mimeTypes.rdf
_を報告します。このエントリを持たない新しいプロファイルでは、ブラウザは_application/vnd.ms-Excel
_(リストの項目3)を報告します。
ブラウザのハードコードされたリストはかなり限られています。多くの場合、ブラウザによって送信されるMIMEタイプは、OSによって報告されるものです。そして、これがまさに、質問で述べたように、ブラウザによって報告されたMIMEタイプが信頼できないという理由です。
キップ、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 。これについては、さらに信頼できる情報が必要です。
これはあなたの質問に対する答えではありませんが、解決しようとしている問題を解決します。 YMMV。
あなたが書いたように、各ブラウザにはそれを決定する方法があるため、MIMEタイプは信頼できません。ただし、ブラウザはファイルの元の名前(拡張子を含む)を送信します。したがって、問題に対処する最善の方法は、MIMEタイプではなくファイルの拡張子を検査することです。
それでもMIMEタイプが必要な場合は、独自のApacheのmime.typesを使用して、サーバー側を決定できます。
これはおそらくOSであり、ブラウザに依存する可能性がありますが、Windowsでは、特定のファイル拡張子のMIMEタイプはHKCRの下のレジストリを調べることで見つけることができます。
例えば:
HKEY_CLASSES_ROOT.Zip-ContentType
MIMEからファイル拡張子に移動するには、以下のキーを見ることができます
HKEY_CLASSES_ROOT\Mime\Database\Content Type
特定のMIMEタイプのデフォルト拡張子を取得します。
rfc1867-HTMLでのフォームベースのファイルアップロード :
メディアタイプがわかっている場合(ファイル拡張子やオペレーティングシステムのタイピング情報から推測される場合)、またはアプリケーション/オクテットストリームとして、各部分に適切なコンテンツタイプのラベルを付ける必要があります。
だから私の理解は、application/octet-stream
はblanket catch-all
タイプをinferredにできない場合の識別子。
私はjohndodoに同意します。ブラウザから送信されるMIMEタイプを信頼できないものにする変数が非常に多くあります。受け取ったサブタイプを除外し、「アプリケーション」などのタイプに焦点を合わせます。アプリがphpベースの場合、explode()関数を使用して簡単にこれを行うことができます。さらに、ファイル拡張子をチェックして、それが.Zipまたは他の探している圧縮であることを確認してください!