snoyman.com-content/posts/ie-mimetype-png
2014-10-19 13:49:53 +03:00

76 lines
3.3 KiB
Text

I've been a bit torn about what exactly to put on this blog. Short comments go
to Google+. Anything Haskell related goes to the [Yesod blog](http://www.yesodweb.com/blog).
So what goes here?
For now, I've decided to start a series on dysfunctional programming. In other
words, horror stories from the non-Haskell world.
Today's tale begins with a strange bug report. One of our clients says that all
of the CSS changes we put on their server have suddenly disappeared. Which is
especially strange, because I don't have any write access to their production
server. There were two aspects to this report: bullets were missing, and the
title image didn't display in IE. By the way, there's a separate title image,
provided by the client, for each publication.
Forget about the bullets for now, that one wasn't interesting. The title image
was truly a conundrum. I started off by loading the output in Chrome. No
problem. Internet Explorer? Red X. At first I thought it was a URL mangling
issue. But when I tried moving the title image to a simple path on the system
and loading it up, it *still* displayed as a red X.
I started a local Warp server and accessed the site from there. No problem.
So... the file itself is correct, and the name of the file isn't the problem.
What's the issue? I spent a good 30 minutes looking for PNG bugs in IE.
Unfortunately, with IE's sordid history of PNG bugs, it was like looking for a
needle in a haystack. However, I saw one off-hand comment:
> Try right-clicking the image, choosing properties, and look at the type.
I tried it and, sure enough, the type was "Unknown," not "PNG". So it turns out
that when served from a web server, IE was delivered the correct mimetype via a
response header. But when opening from the local filesystem, it needs to detect
the mimetype automatically.
Looking at a file extension is too simple. IE needs to outsmart us. The
solution?
[FindMimeFromData](http://msdn.microsoft.com/en-us/library/ie/ms775147%28v=vs.85%29.aspx).
This wonderfully constructed function inspects the contents of the file in
question and determines the mimetype. For example, this nifty little program
will print the mimetype of the title.png file:
#include <urlmon.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
char buff[256];
LPWSTR out;
FILE *in = fopen("title.png", "rb");
fread(buff, 1, 256, in);
FindMimeFromData(NULL, NULL, buff, 256, NULL, FMFD_DEFAULT, &out, 0);
printf("%ls\n", out);
return 0;
}
The result? `image/pjpeg` of course! Never mind that that's an invalid mimetype, but the Win32 function is giving the __wrong mimetype for a PNG file__!!! I'm not quite certain how Microsoft screwed this up so royally. There's a very explicit set of bytes at the beginning of the file indicating that it's a PNG, and [imagesize-conduit](http://hackage.haskell.org/package/imagesize-conduit) detects it just fine:
import Data.Conduit
import Data.Conduit.Binary
import Data.Conduit.ImageSize
main :: IO ()
main = do
f <- runResourceT $ sourceFile "title.png" $$ sinkImageInfo
print f
In other words: Internet Explorer, since version 4, can't even display some
simple images.
I had to tell the client that we have no workaround, and they need to either
"fix" their perfectly valid PNG or always serve their content from a webserver.