Share via


How IIS6 Compression Schemes interact with ISAPI Filters

Question:

Hi

we configure IIS6 for HTTP compression for static and dynamic pages. And its priority is high. We wrote one ISAPI filter where I capture body of response.

When we send request for dynamic pages like (asp) with Content-Encoding of GZIP and DEFLATE then we are able to capture proper body means body in uncompressed format.

But in case of static pages (html pages) when we sent request first time we capture uncompressed body. But next time when se sent request for same page then we try to capture body then we get compressed format of the body not uncompress format.

Why it is so in case of dynamic we are getting uncompressed format all the time but in case of static we are getting compressed format. There is any specific reason. There is any way so that I can capture body in uncompressed format.

Answer:

Unless you cache the static page's content that first time, it is not possible for you to dynamically capture the uncompressed entity body of a statically compressed resource.

The reason is due to how the two IIS compression schemes work:

  • Static Compression scheme only applies to content served by the IIS Static File Handler. On first request to a URL that qualifies for static compression, IIS first sends the uncompressed page as-is and simultaneously kicks off a compression thread to compress that page and cache its result as a file under the "IIS Temporary Compressed Files" folder. On subsequent requests to that URL, IIS opens and sends the cached file in "IIS Temporary Compressed Files" as-is, triggering SF_NOTIFY_SEND_RAW_DATA along the way. This caching of the compressed response makes sense because the resource is "static" and supposedly non-changing.
  • Dynamic Compression scheme applies to content served by the CGI or ISAPI Handlers. On every request to such a URL, IIS takes the chunk of dynamic output from the CGI/ISAPI, call SF_NOTIFY_SEND_RAW_DATA, compresses it, and directly sends it out using chunked-encoding. There is no caching because the CGI/ISAPI could send anything - so everything has to be done on the fly.

As you can see, for Dynamic Compression, everytime the CGI/ISAPI makes a dynamic output, IIS fires a corresponding SF_NOTIFY_SEND_RAW_DATA event, so the ISAPI Filter sees the uncompressed data prior to IIS dynamically compressing and sending it out.

Meanwhile, for Static Compression, IIS cannot use optimizations like VectorSend/TransmitFile because your filter requires SF_NOTIFY_SEND_RAW_DATA notifications, so IIS must open/read the file in user mode to be able to fire those events.

  • On the first request the original uncompressed file is read and sent, so an ISAPI Filter sees the uncompressed file content go by in SF_NOTIFY_SEND_RAW_DATA.
  • On subsequent requests, the pre-compressed file from "IIS Temporary Compressed Files" cache directory is read and sent as-is, so an ISAPI Filter sees the compressed file contents in SF_NOTIFY_SEND_RAW_DATA.

If you think about it, it does not make optimizational sense for IIS to cache both uncompressed and compressed entity simply to make SF_NOTIFY_SEND_RAW_DATA see uncompressed data... nor does it make sense for IIS to repeatedly compress static content or decompress cached content... SF_NOTIFY_SEND_RAW_DATA is an absolute/performance optimization killer.

If you must have the uncompressed entity body of every response, then you either need to make your ISAPI Filter cache that first uncompressed static response, or you turn off Static Compression and its efficiencies and make all files dynamically compressed... because what you want to do (capture and filter all output response data) is contrary to the efficiency design of Static Compression (send data directly, without filtering intervention).

//David