W jaki sposób typ MIME przesłanego pliku jest określany przez przeglądarkę?

87

Mam aplikację internetową, w której użytkownik musi przesłać plik .zip. Po stronie serwera sprawdzam typ MIME przesłanego pliku, aby upewnić się, że jest to application/x-zip-compressedlub application/zip.

To działało dobrze dla mnie w Firefoksie i IE. Jednak gdy współpracownik go przetestował, nie udało mu się to w Firefoksie (wysłany typ MIME to coś w rodzaju „ application/octet-stream”), ale działał w przeglądarce Internet Explorer. Nasze konfiguracje wydają się identyczne: IE8, FF 3.5.1 z wyłączonymi wszystkimi dodatkami, Win XP SP3, WinRAR zainstalowany jako natywny program obsługi plików .zip (nie jestem pewien, czy to istotne).

Więc moje pytanie brzmi: jaki sposób przeglądarka określa, jaki typ MIME wysłać?

Uwaga: wiem, że typ MIME jest wysyłany przez przeglądarkę i dlatego jest zawodny. Sprawdzam to tylko dla wygody - głównie po to, aby dać bardziej przyjazny komunikat o błędzie niż te, które otrzymujesz, próbując otworzyć plik niezip jako plik zip, i aby uniknąć ładowania (prawdopodobnie ciężkich) bibliotek plików zip.

Wyrko
źródło
application / octet-stream wyznacza plik binarny. Powinieneś być w stanie uzyskać rozszerzenie pliku, aby sprawdzić, czy jest to plik zip. Dla wyjaśnienia, czy to zadziałało dla ciebie na FF, ale nie dla twojego współpracownika?
Kevin Crowell
tak, działało u mnie w obu przeglądarkach
Kip
spójrz na input/@formenctypelub form/@enctypeatrybuty
tuxSlayer

Odpowiedzi:

72

Chrom

Chrome (wersja 38 w chwili pisania) ma 3 sposoby określenia typu MIME i robi to w określonej kolejności. Poniższy fragment pochodzi z pliku src/net/base/mime_util.cc, metoda 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.

Zakodowane listy pojawiają się nieco wcześniej w pliku: https://cs.chromium.org/chromium/src/net/base/mime_util.cc?l=170 ( kPrimaryMappingsi kSecondaryMappings).

Przykład: podczas przesyłania pliku CSV z systemu Windows z zainstalowanym programem Microsoft Excel Chrome zgłosi to jako application/vnd.ms-excel. Dzieje się tak, ponieważ .csvnie jest określony na pierwszej zakodowanej liście, więc przeglądarka powraca do rejestru systemu. HKEY_CLASSES_ROOT\.csvma wartość o nazwie, Content Typektóra jest ustawiona na application/vnd.ms-excel.

Internet Explorer

Ponownie korzystając z tego samego przykładu, przeglądarka zgłosi application/vnd.ms-excel. Myślę, że rozsądne jest założenie, że Internet Explorer (wersja 11 w chwili pisania) korzysta z rejestru. Możliwe, że korzysta również z zakodowanej listy, takiej jak Chrome i Firefox, ale jej zamknięty charakter źródłowy utrudnia weryfikację.

Firefox

Jak wskazano w kodzie Chrome, Firefox (wersja 32 w chwili pisania) działa w podobny sposób. Fragment z pliku uriloader\exthandler\nsExternalHelperAppService.cpp, metodansExternalHelperAppService::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

Listy zakodowane na stałe znajdują się wcześniej w pliku, gdzieś w pobliżu linii 441. Szukasz defaultMimeEntriesi extraMimeEntries.

W przypadku mojego obecnego profilu przeglądarka zgłosi raport, text/csvponieważ jest dla niego wpis mimeTypes.rdf(pozycja 2 na powyższej liście). Przy nowym profilu, który nie ma tego wpisu, przeglądarka zgłosi application/vnd.ms-excel(pozycja 3 na liście).

Podsumowanie

Zakodowane na stałe listy w przeglądarkach są dość ograniczone. Często typ MIME wysłany przez przeglądarkę będzie taki, jaki jest zgłaszany przez system operacyjny. I właśnie dlatego, jak stwierdzono w pytaniu, typ MIME zgłaszany przez przeglądarkę jest niewiarygodny.

user247702
źródło
1
dzięki! czy masz link do listy zakodowanej na stałe w źródle chrome?
Kip
@Kip tak, dodałem link. Wydaje się, że Firefox nie ma (oficjalnej) przeglądarki kodu źródłowego online, musiałem ją pobrać z ich serwera FTP.
user247702
Posiadanie MIME jako ms-excel dla CSV jest denerwujące, zastanawiam się, dlaczego nie ma go na zakodowanej liście.
Kris
Byłoby miło wiedzieć, czy od 2014 roku pojawiły się aktualizacje w wykrywaniu typu mime.
Vitaly Isaev
1
@VitalyIsaev pobieżne spojrzenie na kod Chrome pokazuje, że nie zmieniło się to od 2014 roku.
user247702
12

Kip, spędziłem trochę czasu na czytaniu RFC, MSDN i MDN. Oto, co mogłem zrozumieć. Gdy przeglądarka napotyka plik do przesłania, sprawdza pierwszy bufor danych, które otrzymuje, a następnie przeprowadza na nim test. Te testy próbują określić, czy plik jest znanym typem MIME, czy nie, a jeśli jest znany typ MIME, po prostu dalej go przetestuje, dla którego znanego typu MIME, i podejmie odpowiednie działania. Myślę, że IE próbuje to zrobić najpierw, a nie tylko określa typ pliku na podstawie rozszerzenia. Ta strona wyjaśnia to dla IE http://msdn.microsoft.com/en-us/library/ms775147%28v=vs.85%29.aspx . W przypadku Firefoksa mogłem zrozumieć, że próbuje odczytać informacje o pliku z systemu plików lub wpisu katalogu, a następnie określa typ pliku. Oto link do FF https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIFile. Nadal chciałbym mieć więcej wiarygodnych informacji na ten temat.

Kumar
źródło
8

Jest to prawdopodobnie zależne od systemu operacyjnego i prawdopodobnie przeglądarki, ale w systemie Windows typ MIME dla danego rozszerzenia pliku można znaleźć w rejestrze pod HKCR:

Na przykład:

HKEY_CLASSES_ROOT.zip - ContentType

Aby przejść z MIME do rozszerzenia pliku, możesz spojrzeć na klawisze poniżej

HKEY_CLASSES_ROOT \ Mime \ Database \ Content Type

Aby uzyskać domyślne rozszerzenie dla określonego typu MIME.

Michael A. McCloskey
źródło
dzięki. niestety, zarówno dla mnie, jak i dla mojego współpracownika, wydaje się to być poprawne w naszym rejestrze. myślę, że dlatego zadziałało dla niego w IE, ale FF robi to jakoś inaczej ... no cóż :(
Kip
5

Chociaż nie jest to odpowiedź na Twoje pytanie, rozwiązuje problem, który próbujesz rozwiązać. YMMV.

Jak napisałeś, typ MIME nie jest wiarygodny, ponieważ każda przeglądarka ma swój sposób określania go. Jednak przeglądarki wysyłają oryginalną nazwę (łącznie z rozszerzeniem) pliku. Dlatego najlepszym sposobem rozwiązania problemu jest sprawdzenie rozszerzenia pliku zamiast typu MIME.

Jeśli nadal potrzebujesz typu mime, możesz użyć własnego typu mime.types Apache, aby określić go po stronie serwera.

johndodo
źródło
1
Możesz rozwinąć temat? Z mojego doświadczenia wynika, że ​​przeglądarki zawsze wysyłają poprawną oryginalną nazwę pliku (z rozszerzeniem), podczas gdy typy MIME znacznie się różnią. Więc tak, powiedziałbym, że jest znacznie bardziej niezawodny.
johndodo
Poprawny. Chciałem powiedzieć, że użytkownik końcowy może umieścić dowolne rozszerzenie, niezależnie od rzeczywistego typu, więc nie należy mu ufać.
Djizeus
To prawda, ale nie ma znaczenia, czy używasz rozszerzenia, czy typu MIME - nigdy nie powinieneś ufać danym wprowadzonym przez użytkownika. Ale OP wyraźnie stwierdził, że jest świadomy tego problemu, więc nie jest to część tego pytania. Przy okazji, byłbym wdzięczny, gdybyś usunął głos przeciwny (zakładam, że pochodzi od ciebie).
johndodo
Masz rację, nie zwracałem uwagi na nie w pytaniu, mój błąd. Mogę anulować swój głos, ale będziesz musiał zmienić odpowiedź (wymuszoną przez system) ...
Djizeus
Tak, zgadzam się z johndodo. Jak wyjaśnił Stijn w swojej odpowiedzi powyżej, Chrome i Firefox najpierw sprawdzają rozszerzenie. W końcu robią to samo.
Jenix,
0

Zgadzam się z johndodo, jest tak wiele zmiennych, które powodują, że typy MIME wysyłane z przeglądarek są niewiarygodne. Wykluczyłbym otrzymane podtypy i skupiłbym się tylko na typie „aplikacja”. jeśli Twoja aplikacja jest oparta na PHP, możesz to łatwo zrobić za pomocą funkcji explode (). ponadto po prostu sprawdź rozszerzenie pliku, aby upewnić się, że jest to .zip lub inna kompresja, której szukasz!

Seul Shahkee
źródło
0

Zgodnie z rfc1867 - przesyłanie plików w formacie HTML na podstawie formularza :

Każda część powinna być oznaczona odpowiednim typem treści, jeśli typ nośnika jest znany (np. Wywnioskowany z rozszerzenia pliku lub informacji o typie systemu operacyjnego) lub jako aplikacja / strumień oktetu.

Rozumiem więc, że jest application/octet-streamto rodzaj blanket catch-allidentyfikatora, jeśli nie można wywnioskować typu .

smwikipedia
źródło
tak, rozumiem to wszystko. pytanie brzmiało, jak przeglądarka wnioskuje.
Kip
Warto jednak wiedzieć, prawda? Jeśli application/octet-streamchodzi o wszystko, innym podejściem byłoby zaufanie przeglądarce, jeśli byłaby w stanie zgadnąć, i wykonanie własnych testów po stronie serwera, jeśli tak się stanie application/octet-stream.
MikeBeaton,