Specify multiple (gzip + brotli) httpCompression schemes in IIS7/8/8.5 and prioritise brotli
Asked Answered
O

2

11

I'm trying to get the new Brotli compression scheme working in IIS using "Brotli compression module for Microsoft IIS" by iisspeed.com.

The Brotli compression module itself works fine if I change the <httpCompression> config section in applicationHost.config to only have the Brotli module.

The problem is that I want to have both gzip and Brotli, and prefer Brotli

The documentation on iisspeed.com says to do this:

<httpCompression directory="path\to\temp\folder" minFileSizeForComp="50">
        <scheme name="br" dll="path\to\iisbrotli.dll" />
        <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" />
        ...
</httpCompression>

However I have discovered that this does not work.

The browser (Chrome in this example) sends the following accept-encoding header:

accept-encoding: gzip, deflate, sdch, br

This means the browser can accept Brotli encoding br as well as gzip. I want IIS to prefer br over gzip but there doesn't appear to be a way to prioritise each <scheme> element in the config. I've tried changing the order in the .config file but it has no effect.

IIS always uses gzip even though br is supported and would be preferred because it's a smaller file size.

I have scoured Google to find that there used to be a priority setting for each compression scheme in IIS 6 but it seems to have been removed in IIS7+.

It's called HcPriority and went into the IIS6 metabase XML file.

See the following links:

https://msdn.microsoft.com/en-us/library/ms525366(v=vs.90).aspx

https://blogs.iis.net/ksingla/changes-to-compression-in-iis7

https://forums.iis.net/t/1150520.aspx

Is there anything I can do for IIS7+ to tell IIS to prefer br over gzip if the client accepts it?

Oceanus answered 20/10, 2016 at 14:10 Comment(0)
I
11

It appears the Brotli module you referenced requires a paid license, so I haven't tried it, but I encountered a similar issue with my own open source Brotli plugin for IIS.

As you pointed out, current browsers advertise Brotli support after gzip and deflate in the Accept-Encoding header.

The HTTP RFC gives no specific guidance on how to choose from many Accept-Encoding values with the same priority, so it would be acceptable to return br content to those clients. However, it appears IIS always chooses the first one (left to right) that matches one of its configured compression schemes.

If you wish to leave both schemes enabled, you can modify the Accept-Encoding header value on requests as they enter your IIS pipeline. The IIS URL Rewrite Module can do this with a simple rule.

The Accept-Encoding header is represented by the HTTP_ACCEPT_ENCODING Server Variable in the IIS pipeline, and you can modify it before it reaches the Compression Module(s). Here is a sample configuration:

<rewrite>
    <allowedServerVariables>
        <add name="HTTP_ACCEPT_ENCODING" />
    </allowedServerVariables>
    <rules>
        <rule name="Prioritize Brotli">
            <match url=".*" />
            <conditions>
                <add input="{HTTP_ACCEPT_ENCODING}" pattern="\bbr(?!;q=0)\b" />
            </conditions>
            <serverVariables>
                <set name="HTTP_ACCEPT_ENCODING" value="br" />
            </serverVariables>
        </rule>
    </rules>
</rewrite>

The rule above looks for the string br (surrounded by word boundaries -- and not immediately followed by ;q=0) in the Accept-Encoding header and re-writes it to be just plain br, giving IIS only one choice.

Note that the default URL Rewrite configuration does not allow modification of the HTTP_ACCEPT_ENCODING variable. The allowedServerVariables element overrides that restriction and must be configured in applicationHost.config. The rewrite rule can then be defined at any level in the config hierarchy, although it probably makes sense to make it global.

Inbound answered 8/2, 2018 at 4:3 Comment(3)
I've marked this as the answer because I think it's the most elegant solution that would, in theory, work for any other type of plugin or module. It's a universal solution. Thanks.Oceanus
Do I need to put that entry in applicationHost.config file?Memory
That's the most simple solution. At a minimum, the allowedServerVariables config has to go in applicationHost.config. The rules can be defined per site or folder in web.config if necessary.Inbound
S
2

From your second link (emphases mine):

HcPriority is removed as scheme to use when multiple ones appear in Accept-Encoding header of request is picked depending on scheme which is appear first in Accept-Encoding header (assuming no q factor). This is as per HTTP specs.

Also discussed here: HTTP: What is the preferred Accept-Encoding for “gzip,deflate”?

If you make make the same request with Accept-Encoding: br, gzip, deflate, via an HTTP client that allows you to manually set the request headers (e.g. Postman or Fiddler) or a browser extension that allows you to change the request headers (e.g. ModHeader for Chrome), you should see the response encoded with Brotli even when gzip and/or deflate are available.

EDIT: I was able to get the Brotli module to work as desired (i.e. use Brotli encoding when it is tied for the most-preferred regardless of ordering in Accept-Encoding) by registering it as a global native module and ordering it before both the dynamic and static compression modules.

Spirogyra answered 1/12, 2016 at 23:54 Comment(2)
Thanks for the answer, though it doesn't really answer my question which is how to get the web server to decide the preference (without manual coding a solution), rather than the browser. Perhaps it's not possible but I will wait to see if anyone has any bright ideas.Oceanus
I edited to my answer to reflect an alternative (and successful) way of achieving what you want--hope it helps.Spirogyra

© 2022 - 2024 — McMap. All rights reserved.