I have been working with one of my customers to fix some static compression issues on IIS 8.5. During our work I have been asked that if IIS is not respecting the minFileSizeForComp settings and if it is compressing the static files that are smaller than the limit configured in the IIS settings.
Before proceeding with the situation and the solution, I would like to explain what that minFileSizeForComp setting is used for first:
Specifies the minimum number of
kilobytesbytes a file must contain in order to use on-demand compression.
As explained, if the file size is smaller than the limit configured, then the static file compression will not happen. Note that the default limit is 2700 bytes for IIS 7.5 and the never versions. This means that, a static file (for example a CSS file) will not be compressed if it is smaller than 2700 bytes with the default configuration.
Another note is that this setting will be ignored for the dynamic compression as a by-design behavior.
This configuration is quite useful because compressing the small files may produce larger files so it may cause more bandwidth usage. For example, if you compress a CSS file which is 7 bytes, then you may have a compressed one which is 130 bytes as a result, which is larger than the uncompressed version of the same file. Obviously this will waste the CPU time on the server and will consume more bandwidth.
As I explained in the beginning of this article, my customer asked if this setting is ignored for static files and if the small static files are compressed as an unexpected behavior.
When I searched the internet for the minFileSizeForComp setting, I have found that several discussions have been made around the same topic and the same behavior is reported with no solution or workaround. For example the following forum thread shows the same discussion:
IIS7 Compression not honoring minfilesizeforcomp setting
To understand if IIS really ignores this setting I decided to set up a repro with the following configuration on my test machine:
- I set up a web site on my IIS 8.5 machine.
- I created the web site with two CSS files referenced:
- /Content/Site.css: a css file which is 7 bytes
- /Content/Bootstrap.css: a css which is 117 KB (120.502 bytes)
- I enabled both Dynamic Compression and Static Compression for my site since I would like to have both dynamic and static files to be compressed:
Below is the compression settings for my web site:
Please note the followings:
- minFileSizeForComp is 2700 bytes, which is the default value.
- I changed the staticCompressionIgnoreHitFrequency to true so static compression will happen for every requests (please see https://www.iis.net/configreference/system.webserver/httpcompression for the details).
When I request my site with this configuration I end up with both CSS files are compressed. Please see the Fiddler log below:
As seen in the screenshot above, the 7 bytes /Content/Site.css file is served as 130 bytes after compressed with gzip, although I have minFileSizeForComp is set 2700 bytes. Expectation was to serve it uncompressed.
TROUBLESHOOTING THIS BEHAVIOR
IIS comes with a great built-in troubleshooting tool called Failed Request Tracing (a.k.a. FREB). FREB can provide a lot of useful information about what happens in the IIS pipeline, either within the Integrated or Classic pipeline.
I set up a FREB rule in my web site for /Content/* path for troubleshooting:
Since I am interested in only successful responses from IIS, I set up the rule for HTTP 200 status code. This makes sure to generate FREB logs for every requests made for a file under /Content/ path for HTTP 200 response:
I am only interested in seeing compression related data in the IIS pipeline so I select only the WWW Server Providers and choose the Compression property. This will log only the compression related processing from IIS pipeline and it creates the minimum data for analyzing:
After reproducing the same behavior FREB logs will be created in the FREB logging directory.
REVIEWING THE DATA
When I open the FREB log for Site.css request, I confirm that IIS is actually respecting the minFileSizeForComp setting and the static compression does not happen for that request. The reason is shown as FILE_TOO_SMALL:
This proves that IIS respects the minFileSizeForComp setting. But why is the small CSS file compressed then? As seen in the same FREB results above, the CSS file is compressed because of Dynamic Compression and it also shows that the original size is 7 bytes and the result is 130 bytes! Well, obviously this is an undesirable behavior.
So the small file is not compressed because of static compression, instead it is compressed because of dynamic compression settings. Note that as I expressed at the beginning of this article minFileSizeForComp is ignored for dynamic compression which is a by-design behavior. That is why dynamic compression did not check if the file is smaller than the minFileSizeForComp value.
There should be some questions arising here:
- If a file is compressed by static compression, then is the same file compressed by dynamic compression again?
- How to avoid dynamic compression for this particular file?
The answer for the first question is NO, if a file is compressed by static compression then it will not be compressed by dynamic compression. Remember that I had another CSS file which was 117 KB (bootstrap.css) and it was larger than the 2700 bytes limit so it should have been compressed by static compression. If I check the FREB log for that file I can confirm that the static compression happened but dynamic compression did not:
As seen in the FREB log results above, the static compression is successful so IIS does not try to compress the same file with the dynamic compression and the ALREADY_CONTENT_ENCODING information is logged.
For the answer to the second question, let's please welcome the solution below.
If you do not need dynamic compression then you can just disable it. This will avoid dynamic compression to happen at all. Please note that the dynamic compression should be used carefully since it may cause higher CPU usage on the server since it will not create the compressed version on the temporary folder on the disk (by default the folder is C:\inetpub\temp\IIS Temporary Compressed Files), meaning that the dynamic compression will happen for each request for the same file by default. This causes the CPU work for every request for the same file.
However, if you need Dynamic Compression, then you can tell IIS to not compress a certain file type with dynamic compression. You can do that at the site level with IIS Configuration Editor easily. To do so please follow the steps below:
1) Select your web site and choose IIS Configuration Editor under Management section and then choose system.webServer/httpCompression. Then click ... to open the Dynamic Types settings:
2) Then add the “text/css” as mimeType and set enabled=False, as seen in the screenshot below:
3) Do not forget to click Apply after closing the window above. It will make the necessary changes in the web.config file for your web site.
Now you can test it again and this time you should be able to see the small static file is not compressed. You can see a sample Fiddler output in the screenshot below. Note that the /Content/Bootstrap.css file is compressed because it is a larger file than the minFileSizeForComp value while the /Content/Site.css is served as uncompressed since the file size is 7 bytes and it is smaller than the minFileSizeForComp value:
SOME WORDS ABOUT BEST PRACTICES
I was discussing this issue with my friend and my colleauge Paul Cociuba who works as an Escalation Engineer in Microsoft IIS Support Team. We agreed that it is a best practice not to serve several small CSS or JS files separately. Instead, using the Bundling and Minification techniques will improve the request times. The following article is a good read for those techniques:
Bundling and Minification
HTTP Compression <httpCompression>
Troubleshooting Failed Requests Using Tracing in IIS 7
Editing Collections with Configuration Editor
IIS 7.x and newer versions.