4

I'm using FindMimeFromData from urlmon.dll for sniffing uploaded files' MIME type. According to MIME Type Detection in Internet Explorer, image/tiff is one of the recognized MIME types. It works fine on my development machine (Windows 7 64bit, IE9), but doesn't work on the test env (Windows Server 2003 R2 64bit, IE8) - it returns application/octet-stream instead of image/tiff.

The above article describes the exact steps taken to determine the MIME type, but since image/tiff is one of the 26 recognized types, it should end on step 2 (sniffing the actual data), so that file extensions and registered applications (and other registry stuff) shouldn't matter.

Oh and by the way, TIFF files actually are associated with a program (Windows Picture and Fax Viewer) on the test server. It's not that any reference to TIFF is absent in Windows registry.

Any ideas why it doesn't work as expected?

EDIT: FindMimeFromData is used like this:

public class MimeUtil
{
    [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false)]
    private static extern int FindMimeFromData(
        IntPtr pBC,
        [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
        [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1, SizeParamIndex = 3)] byte[] pBuffer,
        int cbSize,
        [MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
        int dwMimeFlags,
        out IntPtr ppwzMimeOut,
        int dwReserved);

    public static string GetMimeFromData(byte[] data)
    {
        IntPtr mimetype = IntPtr.Zero;
        try
        {
            const int flags = 0x20; // FMFD_RETURNUPDATEDIMGMIMES
            int res = FindMimeFromData(IntPtr.Zero, null, data, data.Length, null, flags, out mimetype, 0);
            switch (res)
            {
                case 0:
                    string mime = Marshal.PtrToStringUni(mimetype);
                    return mime;
                // snip - error handling
                // ...
                default:
                    throw new Exception("Unexpected HRESULT " + res + " returned by FindMimeFromData (in urlmon.dll)");
            }
        }
        finally
        {
            if (mimetype != IntPtr.Zero)
                Marshal.FreeCoTaskMem(mimetype);
        }
    }
}

which is then called like this:

protected void uploader_FileUploaded(object sender, FileUploadedEventArgs e)
{
    int bsize = Math.Min(e.File.ContentLength, 256);
    byte[] buffer = new byte[bsize];
    int nbytes = e.File.InputStream.Read(buffer, 0, bsize);
    if (nbytes > 0)
        string mime = MimeUtil.GetMimeFromData(buffer);
    // ...
}
Jakub Januszkiewicz
  • 4,380
  • 2
  • 37
  • 54
  • To discard: whatIIS are using? do you have associated within the IIS MIME type? Although the .tif files are associated with a program that does not mean that the MIME type is registered in IIS – Daniel Hermosel Oct 26 '12 at 06:23
  • Do you use the `pwzUrl` or `pBuffer` parameter with `FindMimeFromData`? – Aoi Karasu Oct 26 '12 at 07:13
  • @Aoi: I use `pBuffer`. I will update the question with the actual code. – Jakub Januszkiewicz Oct 27 '12 at 11:26
  • @Daniel: IIS6 is installed on that server and MIME types for .tif and .tiff are defined (image/tiff), although I doubt that has any impact on this. This code (`urlmon.dll`) is part of IE and can be used on machines without IIS, so I can't see how IIS version or configuration could affect the results. – Jakub Januszkiewicz Oct 27 '12 at 11:30
  • Is this failing for all TIFF files or just one? Otherwise, are you sure the MIME sniffing is an enabled IE feature on the test machine (this can be disabled by IE zone also...) http://msdn.microsoft.com/en-us/library/ms537169(v=vs.85).aspx – Simon Mourier Oct 28 '12 at 17:07
  • @Simon: nice hint, but it is enabled and it works fine for all other MIME types supported by `urlmon.dll`... – Jakub Januszkiewicz Nov 01 '12 at 15:21

1 Answers1

5

I was unable to reproduce your problem, however I did some research on the subject. I believe that it is as you suspect, the problem is with step 2 of MIME Type Detection: the hard-coded tests in urlmon.dll v9 differ from those in urlmon.dll v8.

The Wikipedia article on TIFF shows how complex the format is and that is has been a problem from the very beginning:

When TIFF was introduced, its extensibility provoked compatibility problems. The flexibility in encoding gave rise to the joke that TIFF stands for Thousands of Incompatible File Formats.

The TIFF Compression Tag section clearly shows many rare compression schemes that, as I suspect, have been omitted while creating the urlmon.dll hard-coded tests in earlier versions of IE.

So, what can be done to solve this problem? I can think of three solutions, however each of them brings different kind of new problems along:

  1. Update the IE on your dev machine to version 9.
  2. Apply the latest IE 8 updates on your dev machine. It is well known that modified versions of urlmon.dll are introduced frequently (eg. KB974455). One of them may contain the updated MIME hard-coded tests.
  3. Distribute own copy of urlmon.dll with your application.

It seems that solutions 1 and 2 are the ones you should choose from. There may be a problem, however, with the production environment. As my experience shows the administrators of production env often disagree to install some updates for many reasons. It may be harder to convince an admin to update the IE to v9 and easier to install an IE8 KB update (as they are supposed to, but we all know how it is). If you're in control of the production env, I think you should go with solution 1.

The 3rd solution introduces two problems:

  • legal: It may be against the Microsoft's policies to distribute own copy of urlmon.dll
  • coding: you have to load the dll dynamically to call the FindMimeFromData function or at least customize your app's manifest file because of the Dynamic-Link Library Search Order. I assume you are aware, that it is a very bad idea just to manually copy a newer version of urlmon.dll to the system folder as other apps would most likely crash using it.

Anyway, good luck with solving your urlmon riddle.

Aoi Karasu
  • 3,730
  • 3
  • 37
  • 61
  • Thanks for doing the research and for the suggestions. This explains why I am seeing this problem. I don't need the workarounds, fortunately, as this is only a test machine which is going to be upgraded anyway, and we have full control over other servers where this application is hosted. – Jakub Januszkiewicz Nov 01 '12 at 15:23
  • By the way, just for the record - that machine is fully updated now (IE8 with all updates released as of now) and this problem still presists, so solution 2 is out. IE9 is not available for Windows Server 2003 R2, so solution 1 is also out. I will just wait for OS upgrade on that machine. – Jakub Januszkiewicz Nov 04 '12 at 09:17