plone/plone.formwidget.namedfile — pull request #9 by lukasgraf (2013-07-11 10:00:53+00:00)
Title: Ignore contentType sent by browsers for file uploads

Currently `plone.formwidget.namedfile` [extracts the contentType](https://github.com/plone/plone.formwidget.namedfile/blob/master/plone/formwidget/namedfile/converter.py#L39)
from the file upload request sent by the browser (a `ZPublisher.HTTPRequest.FileUpload` instance), and passes that contentType to e.g. `NamedBlobFile()`.

This is a problem because the contentTypes sent by browsers are unreliable at best, and plain wrong in the worst case.

We've done some extensive tests with various browsers on different operating systems, and the results couldn't be more random. A particular version of browser X on Mac OS 10.Y can send a totally different content type than the
same browser on the same minor OS version on a different machine. It also depends on the software that is installed client-side. Certain applications register MIME types for their handled formats in the respective OS registry, causing browsers to send a different content type than they would without that application being installed.

In the end, I believe in the context of a CMS like Plone, the server side should be in control of determining the MIME type of an uploaded file:

- You want it to be consistent. Irrespective of whether it's the *right* MIME type or not, all the `.docx` NamedFiles on that Plone site should have the same content type.
- Browsers can send MIME type that is completely wrong: Wrong variant, wrong subtype, wrong major type, even malformed type ('application/' for example.)
- Sometimes browsers simply can't know the right MIME type: Unless "exotic application XY" is installed and has registered its types, the browser can't know about them, even if he's just a middleman that's supposed to upload
a file the user never intended to edit on his machine.

My suggestion would be this:
- Extract extension from the filename
- Look up the extension in the Plone MIME type registry
- If that fails, fall back to the Python MIME type registry available trough the `mimetypes` module
- If that fails, use the magic bytes of the content to guess the MIME type (for example by using python-magic)
- Only if all that failed fall back to the contentType sent by the browser.

If you want to test this behavior yourself, here's a quick & dirty browser view that presents you with the relevant information: https://gist.github.com/lukasgraf/5949331