IIS Static Compression does not Gzip, or cache files - iis

I have an ASP.NET website that I'm trying to enable Static Compression for. My website has the following compression configuration.
<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files" staticCompressionEnableCpuUsage="0" staticCompressionDisableCpuUsage="100" staticCompressionIgnoreHitFrequency="true">
<clear/>
<scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" staticCompressionLevel="10" dynamicCompressionLevel="3" />
<scheme name="deflate" dll="%Windir%\system32\inetsrv\gzip.dll" staticCompressionLevel="10" dynamicCompressionLevel="3" />
<staticTypes>
<clear/>
<add mimeType="text/*" enabled="true" />
<add mimeType="message/*" enabled="true" />
<add mimeType="application/x-javascript" enabled="true" />
<add mimeType="application/javascript" enabled="true" />
<add mimeType="*/*" enabled="false" />
</staticTypes>
</httpCompression>
<urlCompression doStaticCompression="true" doDynamicCompression="false" dynamicCompressionBeforeCache="false" />
I do not want to enable dynamic compression. According to Microsoft documentation,
Unlike static compression, IIS 7 performs dynamic compression each time a client requests the content, but the compressed version is not cached to disk.
My web server is fairly heavily loaded with processes, so this would be an unwanted burden. By Static Compression is appealing because the compressed files are cached on disk.
However, even after continuous refreshing of the localhost page (Ctrl+F5), and waiting 15+minutes on watching the compression directory, nothing is being cached.
Also, none of the relevant files (css/js/html) are being returned with an gzip compression header.
Both dynamic and static compression are installed. Dynamic is turned off. If I turn on dynamic compression, I start seeing the gzip HTTP response headers come back.
What am I missing? Why does Static Compression refuse to work?
IIS 10

I had this problem and tracked it down to a bad URL Rewrite rule. The static assets were living in C:\inetpub\wwwroot\MyProject\wwwroot and the rewrite rule was changing ^assets/(.*) to ./{R:1}, so IIS was looking at the top of MyProject and not finding the file. But then when it handed the request off to the .Net app, the app would see the file and serve it. So the two symptoms were:
gzip worked only when dynamic compression was enabled (because the .Net app was serving the files).
turning off runAllManagedModulesForAllRequests (on the modules element) caused our static files to become 404 errors---basically surfacing the problem of IIS not seeing the file.
To fix it I changed the rewrite rule from ./{R:1} to ./wwwroot/{R:1}.

Have you looked at this: https://blogs.msdn.microsoft.com/friis/2017/09/05/iis-dynamic-compression-and-new-dynamic-compression-features-in-iis-10/
Theres not much context to see from your question ... but for me this worked.
Cached by asp.net mvc, because it's a bundle of multiple js files. I guess the IIS can see it's not a static file on disk on thats the reason it's dynamic.
There also help to see what id actually does with your js file to find out why it's not doing compression in the link I posted.
I also saw a line in the link you posted:
Unlike static compression, IIS 7 performs dynamic compression each time a client requests the content, but the compressed version is not cached to disk. This change is made because of the primary difference between static and dynamic content. Static content does not change. However, dynamic content is typically content that is created by an application and therefore changes often, such as Active Server Pages (ASP) or ASP.NET content. Since dynamic content should change often, IIS 7 does not cache it.
Also try to read this post: https://forums.iis.net/t/1071156.aspx

Related

meaning of same types for static and dynamic content in iis http compression

I am looking at the ApplicationHost.config file in IIS server to understand the configurations of Http Compression.
I see the following code:
<httpCompression
directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
<scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" />
<dynamicTypes>
<add mimeType="text/*" enabled="true" />
<add mimeType="message/*" enabled="true" />
<add mimeType="application/javascript" enabled="true" />
<add mimeType="*/*" enabled="false" />
</dynamicTypes>
<staticTypes>
<add mimeType="text/*" enabled="true" />
<add mimeType="message/*" enabled="true" />
<add mimeType="application/javascript" enabled="true" />
<add mimeType="*/*" enabled="false" />
</staticTypes>
</httpCompression>
(taken from: https://learn.microsoft.com/en-us/iis/configuration/system.webserver/httpcompression/)
And my question for you is:
What does it mean to have the same mimeType in both dynamic and static types?
For example from the code I gave we see application/javascript in both sections. now lets say both dynamic and static content compression are enabled, what will happen when we serve an Http Response with Content-Type application/javascript?
Content served by IIS is either static or dynamic. For the most part, if your content is served by a handler such as ASP.NET or Classic ASP, then it falls under the dynamic bucket, if it is a file read straight off the disk, it a static. The example you give obviously doesn't matter because if application/javascript is served, and is enabled by both, then it is eligible for compression. A better example is to say that if the javascript is served thru the static file handler (i.e. the javascript file is from a .js file on the disk) then it will change the static file handler to see if compression is enabled and may compress it. If the javascript comes from some call to script.axd or some other "dynamic" handler, then it will check the dynamicTypes.
So you might ask why two sections? The reason is simply that static files can be compressed and then cached because the files are, well, static. Therefore, we can be much more liberal with our static caching rules because the file can be compressed for the first person who requests it and then cache that compressed copy. Future requests to that same file can be served directly out of the cache. Of course the system handles any modifications that may happen to the file an updates the cache.
With dynamic content, well, that file may be different for every request, every user, etc. As result, IIS doesn't make attempts to cache the compressed copy and simply compresses it each time.
Hopefully that's enough info to get you started. Side note, with static compression it doesn't actually compress for the first user (generally) and it needs a couple people requesting before it goes thru the effort of compressing the content.

How to prevent azure cdn from serving dynamic content?

How do I prevent azure cdn from serving dynamic content? I only want it to serve static files: images, scripts and css but when I choose my web app as origin it serves also the root url (/), that is a dynamic page. Can I create restrictions based on file extension?
Not at this time. Any request to the CDN edge node is going to hit the origin for the asset and cache it, whether it's dynamic or static content. The solution, then, is to ensure that your application doesn't link to any dynamic content via the CDN.
If your static content is located in specific folders (images/, css/, etc), you can prevent the CDN from reaching content outside of those folders.
In order to prevent search engines from indexing our site via the CDN domain we
have disabled site browsing on the CDN domain (except for a specific set of folders that serve resources) by adding the following urlRewrite rule to web.config:
<rule name="Deny site browsing on CDN domain" stopProcessing="true">
<match url="^(storage/|ui/)(.*)" negate="true" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_X_HOST}" pattern="\.azureedge.net$" />
</conditions>
<action type="CustomResponse" statusCode="404" statusReason="Not found" statusDescription="Not found" />
</rule>
Using web server as CDN origin is a "lazy" way to setup CDN. After you set it up, in your website instead of using:
/mypic.jpg
replace all the relative url with
xxx.azureedge.net/mypic.jpg
You don't really need to care about CDN is serving the dynamic content or not, you just need to pick the content you want. CDN just blindly serve the content from origin you specified.

How do I prevent default IIS compression on a response that is already compressed?

TLDR
I have an IHttpHandler that performs compression. It works fine on its own. But then I added an IHttpModule that performs a completely unrelated task on those (and all other) responses, and now IIS is re-compressing the already-compressed responses. How can I prevent this?
The Whole Story
I have an IHttpHandler implementation that performs combination and compression (among other things) for CSS and JS files. Everything in the IHttpHandler works exactly like I want it to.
But then I added an IHttpModule implementation that removes unnecessary response headers (Server, X-AspNet-Version, etc.) from all responses (including the dynamic responses that are generated by the IHttpHandler) during the PreSendRequestHeaders event.
However, it seems that simply registering an IHttpModule, regardless of what it actually does, causes IIS to apply compression to the response, even if the response is already compressed.
So, my IHttpHandler explicitly compresses the response and sets the Content-Encoding header, then (if and only if) the IHttpModule is also registered, IIS re-compresses the response (so there's a doubly-compressed response that browsers can't read).
I don't want to disable all default compression. I still want HTML from views to be compressed (and I want any CSS and JS that doesn't go through the IHttpHandler to also be default-compressed).
I'm guessing there's no easy solution to my problem because it seems like a bug in IIS. IIS should not compress a response that is already compressed.
I tried adding the following to my web.config, but it had no effect:
<httpCompression>
<dynamicTypes>
<add mimeType="text/css" enabled="false" />
<add mimeType="application/javascript" enabled="false" />
</dynamicTypes>
</httpCompression>
(From my interpretation of the documentation, that should disable compression for dynamically generated CSS and JS.)
I also tried this, to no effect:
<httpCompression>
<dynamicTypes>
<clear/>
</dynamicTypes>
<staticTypes>
<clear/>
</staticTypes>
</httpCompression>
(From my interpretation of the documentation, that should disable all default compression.)
Update
In my IHttpHandler, I call context.Response.Flush at the very end. If I remove this call, the response doesn't get double-compressed. I'm fine with this as a solution. Can anyone explain why this is happening?
Update 2
My best guess is that calling Flush puts the response into such a state that IIS doesn't think the response is already compressed (and so it applies default compression). Even though in my module I can check both...
that Response.Headers contains a Content-Encoding header and
that Response.Filter is non-null and is one of the System.IO.Compression types.
Not sure why IIS can't determine that the response is already compressed from those facts.

Changing IIS URL Rewrite config location

When used at site level, the IIS7 URL Rewrite 2 module saves its configuration in the web.config file of that site. I'm using Sitecore CMS, and best practice is to store any web.config customisations in a separate config file for ease of upgrading, staging/production setups etc.
Is there any way to specify a different config file for IIS7 redirects?
I know that application-level rewrites are stored in ApplicationHost.config, but I have several sites running on the server and would like to keep them separated.
Thanks, Adam
In order to support this best practice you've mentioned, Sitecore implements pluggable configs, but only for the elements inside <sitecore> section of web.config. So, unless IIS7 URL rewrite provides some way to move its stuff to a separate config (like ASP.NET does for connectionstrings.config), I'm afraid you'll have to keep it in the main web.config file.
Sorry if I'm saying obvious things.
You can also try to use rewrite maps
<rewrite>
<rewriteMaps configSource="rewriteMaps.config" />
</rewrite>
Sample rewriteMaps.config file:
<rewriteMaps>
<rewriteMap name="CustomRewrites" defaultValue="">
<add key="/instructions" value="/documents" />
</rewriteMap>
</rewriteMaps>
I'm not familiar with the url rewriting config, but I have an example of moving the url mapping to a separate file:
<urlMappings configSource="config\urlMappings.config"></urlMappings>
And that file looks like the following:
<?xml version="1.0"?>
<urlMappings enabled="true">
<add url="~/somedealer" mappedUrl="/?theme=4" />
<add url="~/someotherclient" mappedUrl="/?theme=12" />
</urlMappings>
I'm sure the url rewriting works the same way.

Enable IIS7 gzip

How can I enable IIS7 to gzip static files like js and css and how can I test if IIS7 is really gziping them before sending to the client?
Configuration
You can enable GZIP compression entirely in your Web.config file. This is particularly useful if you're on shared hosting and can't configure IIS directly, or you want your config to carry between all environments you target.
<system.webServer>
<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
<scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll"/>
<dynamicTypes>
<add mimeType="text/*" enabled="true"/>
<add mimeType="message/*" enabled="true"/>
<add mimeType="application/javascript" enabled="true"/>
<add mimeType="*/*" enabled="false"/>
</dynamicTypes>
<staticTypes>
<add mimeType="text/*" enabled="true"/>
<add mimeType="message/*" enabled="true"/>
<add mimeType="application/javascript" enabled="true"/>
<add mimeType="*/*" enabled="false"/>
</staticTypes>
</httpCompression>
<urlCompression doStaticCompression="true" doDynamicCompression="true"/>
</system.webServer>
Testing
To test whether compression is working or not, use the developer tools in Chrome or Firebug for Firefox and ensure the HTTP response header is set:
Content-Encoding: gzip
Note that this header won't be present if the response code is 304 (Not Modified). If that's the case, do a full refresh (hold shift or control while you press the refresh button) and check again.
You will need to enable the feature in the Windows Features control panel:
Global Gzip in HttpModule
If you don't have access to the final IIS instance (shared hosting...) you can create a HttpModule that adds this code to every HttpApplication.Begin_Request event :
HttpContext context = HttpContext.Current;
context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
HttpContext.Current.Response.AppendHeader("Content-encoding", "gzip");
HttpContext.Current.Response.Cache.VaryByHeaders["Accept-encoding"] = true;
Testing
Kudos, no solution is done without testing. I like to use the Firefox plugin "Liveheaders" it shows all the information about every http message between the browser and server, including compression, file size (which you could compare to the file size on the server).
under windows 2012 r2 it can be found here:
I only needed to add the feature in windows features as Charlie mentioned.For people who cannot find it on window 10 or server 2012+ find it as below. I struggled a bit
Windows 10
windows server 2012 R2
window server 2016
If you use YSlow with Firebug and analyse your page performance, YSlow will certainly tell you what artifacts on your page are not gzip'd!
If you are also trying to gzip dynamic pages (like aspx) and it isnt working, its probably because the option is not enabled (you need to install the Dynamic Content Compression module using Windows Features):
http://support.esri.com/en/knowledgebase/techarticles/detail/38616
For all the poor guys who have to struggle with a german/deutsche Server :)
Another easy way to test without installing anything, neither is it dependent on IIS version. Paste your url to this link - SEO Checkup
To add to web.config: http://www.iis.net/configreference/system.webserver/httpcompression
Try Firefox with Firebug addons installed. I'm using it; great tool for web developer.
I have enable Gzip compression as well in my IIS7 using web.config.

Resources