Andornot Blog

Friday, November 20, 2009 10:21 AM

IE6 gzip bug solved using IIS7's URL Rewrite Module

by Ted Jardine

“IE6, that shambling wreck that clings with nightmare strength to its living death.”
Peter Tyrrell, Literary genius nonpareil

When Internet Explorer 6 was first released way back in 2001 it quickly became the predominant browser. It was much better than everything else out there. But now NINE years later, working with IE6 is truly one of the most frustrating things a Web developer has to deal with. In 2009, it has countless issues: problems with transparent PNGs, flakey caching, esoteric rendering, lack of support for modern Web standards, and the list goes on and on.

robot-jonny-ie6
Image courtesy of RobotJonny

This post is about yet another IE6 hair-puller: gzip compression. Compressing HTML, CSS, javascript, etc. allows content to be scrunched up so that it’s served up way faster while reducing bandwidth costs. It’s a great way to increase the performance of your site…except when IE6 is involved that is: IE6 does not correctly handle data that has been compressed using the gzip algorithm. This would be frustrating to deal with, but nevertheless acceptable, except for the fact that IE6 problems with compressed content only pop up sometimes, on certain machines, and intermittently. There doesn’t seem to be any rhyme or reason to it. The worst kind of bugs are the ones you cannot faithfully replicate.

With IIS6 we use Port80 Software’s excellent httpZip module to compress site content (compression is available natively in IIS6, but it’s a pain to administrate, and doesn’t work well with older browsers). One of httpZip’s big selling features is that it accurately deals with browser idiosyncrasies; therefore, until now we haven’t had to worry about IE6 and compression.

However, we have recently started transitioning more sites from being hosted on Windows Server 2003 (with IIS6) over to Windows Server 2008 (IIS7) and Windows Server 2008 R2 (IIS7.5).  With IIS7, gzip compression can be easily and correctly implemented right out of the box. But we’ve discovered that in certain scenarios with static and dynamic compression enabled, IIS7 doesn’t safely handle IE6’s idiot tendencies concerning gzip compression. The immediate solution is to turn off dynamic compression altogether, and this seems to solve the problem, but that doesn’t sit right with me: do yet another regression for IE6 users that punishes non-IE6 users.

Therefore, on to saving the world from IE6, one workaround at a time! Seb Duggan presents a solution involving ISAPI_Rewrite which essentially sniffs out whether or not IE 5 or 6 is doing the request and turns off compression for CSS and JS files if that is the case. Sounds good (although he does a sniff for pre-SP2 IE6 only, which I believe is erroneous). However, we already use IIS7’s URL Rewrite Module and I would prefer to avoid bringing another cook into the kitchen. There’s a couple of obstacles to getting this working however:

  1. The current version of the URL Rewrite Module v1.1 does not support rewriting server variables.
  2. The IIS7 URL Rewrite Module has very different syntax.

So how did I do it?

  • Download and install the URL Rewrite Module 2.0 RC (Release Candidate) or wait until the RTM is released (don’t know when). This version supports rewriting request server variables so we can fake IIS7 into thinking the requesting browser does not support gzip encoding (because for all intents and purposes, it DOESN’T – at least for CSS and javascript files that is).
  • Brute force hacking and documentation reading resulted in the following (the handy “Import Rules”, which can be used to translate Apache mod_rewrite rules, wasn’t up to the task). The important thing to remember is that each dash is replaced with an underscore and each server variable is made all caps and prefixed with “HTTP_”. Oh, and looking at the RFC specs, “0” is valid for setting the encoding to nothing (“.*” didn’t work for some reason).
    <system.webServer>
        …
    <rewrite>
            <rules>
                <rule name="IE56 Do not gzip js and css" stopProcessing="false">
                    <match url="\.(css|js)" /> <!— Match all .css and .js requests -->
                    <conditions>
                        <add input="{HTTP_USER_AGENT}" pattern="MSIE\ [56]" />
    <!— Where the User Agent includes MSIE 5 or MSIE 6 -->
                    </conditions>
                    <action type="None" />
    <!— Don’t do any redirects, rewrites, etc. -->
                    <serverVariables>
                        <set name="HTTP_ACCEPT_ENCODING" value="0" />
    <!—Make it so the request’s Accept-Encoding variable is
    set to nothing instead of gzip,decompress -->
                    </serverVariables>
                </rule>
            </rules>
        </rewrite>

    </system.webServer>
  • Explicitly allow the Accept-Encoding server variable to be overwritten by specifying the following in the applicationHost.config file (required for security reasons). If you don’t do this part, you’ll get an "HTTP/1.1 500 URL Rewrite Module Error".

    <rewrite>
        <allowedServerVariables>
            <add name="HTTP_ACCEPT_ENCODING" />
        </allowedServerVariables>
         …
    </rewrite>
  • You can implement the above on a site-by-site basis or server-wide (rules in site’s Web.config or location specific in applicationHost.config or site-wide in applicationHost.config).
  • ie6-gzip
    Fiddler showing IE6 with compression off for .js and .css files (while still compressing all other applicable files such as .htm).

    ie8-gzip
    Fiddler showing IE8 with compression on for all applicable resource types.

    The usual caveats apply to implementing the above: we don’t guarantee any of it. If it kills your cat, I know nothing. If you lose your job because of it, it’s your fault, not mine. On the other hand, if it helps you out or if you figure out a refined implementation, please let us know.

blog comments powered by Disqus

Month List