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.


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.


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.


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.


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.


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!


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 .


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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.