Troubleshooting HTTP Compression in IIS6
Enabling HTTP Compression for your IIS6 web applications is one way of increasing site performance. One of the more common problems I see when helping customers with compression is that their IIS servers are not set up for compression correctly. Unfortunately the IIS6 admin GUI doesn't expose many of the compression properties needed to fully administer it...in fact the GUI really only lets you turn it on or off. So it is important to note that to configure http compression to its full extent you'll need to edit the metabase using a tool other than the IIS Manager. The most common tool we use is adsutil.vbs, which is included in the IIS installation.
Determining if compression is working
In my opinion, the only valid way of determining whether the IIS server sent a compressed response is by analyzing a network trace of the client request/server response. The request from the client needs to contain the following HTTP Request Header:
HTTP: Accept-Encoding =gzip, deflate
This tells the server that the client supports compression and will accept a compressed response. In return, a compressed response from the server will contain the following HTTP Response header and a value:
HTTP: Content-Encoding = gzip
Troubleshooting why compression isn't happening
The following troubleshooting topics assume the that client sent its request with a valid "HTTP: Accept-Encoding" header and value(s).
1) Compression is not turned on in the metabase at the right locations.
There are three metabase locations for Compression configuration:
Configuring at the /parameters location is *mandatory*. Then, you need to configure at either /gzip *or* /deflate, *or* both. This means that configuring at just /gzip will not work, at just /deflate will not work, and just /parameters will not work. But, configuring at /parameters and /gzip will enable the Gzip compression scheme. And, configuring /parameters and /deflate will enable the Deflate compression scheme. Finally, configuring at all three will enable both GZip compression and Deflate compression.
2) Either Dynamic or Static compression is turned off
At each of the three configuration locations (/parameters, /gzip, and /deflate), you have the option of enabling Static and/or Dynamic compression. For static files like txt and html to be compressed, you need to set the HcDoStaticCompression key to 1 (or TRUE). To enable Dynamic compression (for things like asp, aspx, asmx, exe) you need to have HcDoDynamicCompression set to 1 (or TRUE).
For example, to set dynamic compression at the /parameters node using adsutil, run this command:
cscript.exe adsutil.vbs SET w3svc/filters/compression/parameters/HcDoDynamicCompression TRUE
The output to that command looks like this:
HcDoDynamicCompression : (BOOLEAN) True
3) The file type you want to compress is not listed in the appropriate File Extensions sections at the /gzip and /deflate nodes.
Once you turn on compression with the HcDoDynamicCompression and/or HcDoStaticCompression keys, you have to make sure to tell IIS which file types to actually compress. By default, we compress htm, html, and txt for STATIC compression, and asp, dll, and exe for DYNAMIC compression. If you want different file types compressed, for example aspx, you need to add it to the appropriate file extension section in the /gzip and-or /deflate nodes, depending on the type of compression you're using. For static file compression (like html, txt, and xml), you add the file extensions to the HcFileExtensions property. For dynamic compression (like asp, aspx, asmx) you add it to the HcScriptFileExtension property.
adsutil.vbs get w3svc/filters/compression/gzip/HcFileExtensions
This command will output:
HcFileExtensions : (LIST) (3 Items)
NOTE: In some IIS application environments you may have a static file type, such as .html, mapped to a dynamic handler, such as asp.dll or aspnet_isapi. In this scenario, if you want the .html response to be compressed you need to add the html extension to HcScriptFileExtensions.
4) The HcFileExtensions or HcScriptFileExtensions properties are misconfigured
Configuring the HcFileExtensions or HcScriptFileExtensions properties needs to be done with the exact right syntax. Any trailing spaces or unnecessary quotes/carriage returns will cause the property to be misconfigured. Unfortunately adsutil.vbs does not throw an error if you add an extra space, so you need to be very careful. Also, copy/pasting the values into a command prompt or into the metabase.xml file (metabase direct-edit) is a bad idea....always type it manually!
It is extremely tricky to catch an extra space or other mistake in the Extensions sections, so if all else fails try manually re-entering the desired extensions using adsutil, by first typing:
adsutil.vbs set w3svc/filters/compression/gzip/HcScriptFileExtensions
...And then appending that with a space, then open quotation, then the file extension, then a close quote, then a space, then a open quote, then the next file extension, then close quote, etc. There should be NO COMMAS when setting this. Here is an example:
adsutil.vbs SET w3svc/filters/compression/gzip/HcScriptFileExtensions "asp" "dll" "exe" "aspx"
5) Compression is set at the master level, but it getting overridden by a setting at a child level
As dicussed above, we turn on Compression at the w3svc/filters/compression level. Most of the time, this is enough, and it is a global setting. However, you *can* configure compression at individual application levels too, using the DoStaticCompression or DoDynamicCompression properties (instead of HcDoDynamicCompression and HcDoStaticCompression). Therefore if you have HcDoDynamicCompression set to TRUE, and for the default web site have DoDynamicCompression set to FALSE, dynamic compression will NOT occur for responses to requests for the Default Web Site.
6) An anti-virus program has scanned the directory where the compressed files get stored. For information on this problem, see the following article:
7) The URL being requested contains a slash as part of the parameters passed to the executing DLL file.
8) The application pool identity (or the IIS_WPG group in general) does not have Read and Write access to the metabase key W3SVC/Filters. In this scenario, a failure condition of COMPRESSION_DISABLED will be logged in an Enterprise Tracing for Windows (ETW) trace.
9) An ISAPI is doing the send operation and is not sending the complete set of HTTP headers along with the entity to HTTP_COMPRESSION::DoDynamicCompression. Since DoDynamicCompression doesn't receive all the data it should from the ISAPI, we cannot compress the response. Third party and/or non-Microsoft ISAPIs have been seen to do this by putting the headers in the function meant for the entity body or the entity body in the function meant for the HTTP headers, or by not providing any headers whatsoever. When this happens, things like the ISAPI filter SF_NOTIFY_SEND_RESPONSE, or AddResponseHeaders, or dynamic compression will fail. The ISAPI needs to put the headers and the entity in the right locations, respectively.
10) The initial Client request contains a Range header and value, and the IIS server's metabase setting for HcNoCompressionForRange is set to false. The HcNoCompressionForRange property specifies how IIS handles HTTP Range requests. The HTTP 1.1 Request for Comment, RFC 2068, is ambiguous about whether Range requests apply to the compressed or uncompressed version of a file. Some browsers could be unprepared for compressed Range responses. As a result, IIS, by default, does not send compressed responses to Range requests, to avoid problems with browser misbehavior.
11) The response status code is something other than 200. In IIS 6, only responses with an HTTP 200 status will get compressed.
12) The client request contains a Via: header. The Via headers indicates that the request is coming to IIS via a Proxy. Many proxies don't handle the compression header correctly and give compressed data to clients when they aren't supposed to, so by default we don't allow compressed responses when the request has a Via header. You can override this by setting the HcNoCompressionForProxies metabase key to True.
13) The request is for a static page, and the response contains a document footer. Document footers will cause static compression to fail.