url-rewritingweb-configurl-rewrite-module

web.config rewrite emitted image file


I'm trying to use the web.config's <rewrite> section to override an emitted GIF file that is used for styling a menu toolbar. The GIF is emitted from a DLL that I don't have full access to (External tool).

I've tried several variations, and so far, the closest that I have come is to accidentally rewrite everything on the page to the recreated/restyled GIF sprite I created.

The URL will look similar to this:

https://localhost:1365/WebResource.axd?d=zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1&t=638435890000000000

The WebResource.axd's "d" parameter value doesn't change, the only part that does is the value of the "t" parameter.

I've had success using the section using this rule:

<configuration>
    <rewriter>
        <redirect url="^~/WebResource\.axd\?d=zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1(.*)$" to="~/CSS/SpriteOverrides/ToolBars.gif" />
    </rewriter>
</configuration>

However, I'm trying to use the <rewrite> section's rules to that I can make use of the more robust values available in the <rule>, in particular the "stopProcessing" property. So ultimately, it would look something like this:

<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="RadEditorToolbarSprite" enabled="true" stopProcessing="true">
                    <match url="/.*WebResource\.axd\?d=zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1.*"></match>
                    <action type="Rewrite" url="/CSS/SpriteOverrides/ToolBars.gif"></action>
                </rule>
            </rules>
        <rewrite>
    <system.webServer>
</configuration>

I'm not at all an expert in using RegEx, but as near as I can tell using matches via an online tool such as https://www.regex101.com, many of the following examples should form some variation of a match:

/.*WebResource\.axd\?d=zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1.*
\/WebResource\.axd\?d=zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1(.*)$
WebResource\.axd\?d=zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1(.*)$
/WebResource\.axd\?d=zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1.*

(WebResource\.axd\?d=zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1.*)?
    => Changes everything to the graphic

None of these, or the original example in the <redirect> seem to create a successful match where the URL is successfully rewritten to my ToolBars.gif.

I feel like there must be something simple that I'm missing, and I'm not sure if I need into any of the "{R:x}" values when building out my <match url="">. Does anyone have any thoughts/ideas for what I might be doing incorrectly here?

Thank you in advance for any help.


Solution

  • Going to answer this, just in case it will end up helping anyone else.

    So the TL;DR answer is that I was trying to match against the wrong thing. I ended up enabling the Failed Request Tracing to check the rewrite rule, and found that the actual request coming in was for the WebResource.axd, and the Query String portion of the URL was not really being tested against the regex match, meaning that unless I tried to match against everything and effectively rewrite all traffic (or at least everything that was a WebResource request), the rule wouldn't kick in.

    The fix was to create a <conditions> block in the rule to test specifically against the query string, leading to this as an initial solution:

    <rule name="WebResourceOverrideRule" enabled="true" stopProcessing="true">
        <match url="^WebResource\.axd$" />
        <conditions>
            <add input="{QUERY_STRING}" pattern="(?:^|&amp;)d=(zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1)(?:&amp;|$)" />
        </conditions>
        <action type="Rewrite" url="CSS/SpriteOverrides/ToolBars.gif" appendQueryString="False" redirectType="Permanent" />
    </rule>
    

    The condition checks the query string specifically for the "d=" value to match the specific request I was looking for, and rewrites it to the URL/image that I wanted.

    That's the basic answer/solution.


    If you're looking to go further into the final fix, I actually ended up doing some digging, and learned about <rewriteMaps>

    Some interesting reading in terms of debugging which led me to the Failed Request Tracing: https://nicolas.guelpa.me/blog/2015/02/21/rewrite-redirect-iis.html (specifically the "How to debug" section, although all of it was relevant/interesting to me) https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-failed-request-tracing-to-trace-rewrite-rules (Taught me how to actually set up the request tracing, and what I was looking for)

    Those were both very helpful in diagnosing the actual problem.

    A bit more research, which led me in the direction of the <rewriteMaps> can be found here: https://yaplex.com/examples-iis-rewrite-rules/ https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-rewrite-maps-in-url-rewrite-module

    The above taught me how to create <rewriteMaps>, but also led me a bit down the rabbit hole as to how powerful they can be. For instance, now that I'm using <rewriteMaps>, I can create a generic rule for all WebResource.axd files, and if there are any that I need to override in the future, rather than needing to create a new <rule> in the rewrite section, I can use the existing <rule>, and add a new key/value pair to the <rewriteMap> I set up to handle WebResource.axd calls.

    The second of the URLs above showed me that you can actually create secondary .config files for rules/maps, and load them via the general web.config, which also is handy. With that in place, when debugging via Visual Studio (or another tool), you should be able to make the changes to test without needing to alter the web.config, which means that you'd need to shut down iis express, recompile, and start it again after making the change, so it can streamline testing.

    The ultimate solution that I ended up using was this:

    <rule name="WebResourceOverrideRule" enabled="true" stopProcessing="true">
        <match url="^WebResource\.axd$" />
        <conditions>
            <add input="{QUERY_STRING}" pattern="(?:^|&amp;)d=(.*?(?=&amp;))(?:&amp;|$)" />
            <add input="{WebResourceOverrides:{C:1}}" pattern="(.+)" />
        </conditions>
        <action type="Rewrite" url="{C:1}" appendQueryString="False" redirectType="Permanent" />
    </rule>
    
    <rewriteMaps>
        <rewriteMap name="WebResourceOverrides">
            <add key="zcXN5Gw-34RBUm_X_907PZUSePk1HAk6aIHCp5Dp3XUp-KQFCEEOLKazKeFqN9mAdZuYIY1BUUkjwExiZJQBv8YrrpYTnZFyW6nm6TD34T3ej6FgsJEn2bHckL85ESOIqQyg_sJo8juhiXSTsTTy--IAgtI1" value="CSS/SpriteOverrides/ToolBars.gif" />
        </rewriteMap>
    </rewriteMaps>
    

    From my understanding, the rule checks the query string for any WebResource.axd request, looks at the query string, and tests it by capturing the "d=" value, then sending that to the <rewriteMap> for the WebResourceOverrides section. If the value of the "d=" query parameter matches the "key" for any <add> sections in the map, the "value" is returned. The second part of the condition checks to make sure that the returned value has value, and if so, rewrites to the replacement URL.

    One thing to note that I also learned... If, for instance, you are rewriting an emitted CSS file using this technique, and that CSS file has references to images/external sources, those may need to be updated, since the WebResource.axd will be rewritten, and then loaded as though it is from the root of the site, rather than where the CSS file is located. As such, relative pathing may no longer be correct, and should be updated as though the CSS file was located at the root of the site, rather than in a subfolder.

    Anyway, hope that this helps someone else out there who may run into the same issue. I'm sure there are other ways to improve upon this idea, especially with the regex matching, since that really isn't my strongest programming area, but this solution seems to work with my original problem, and it can easily/quickly be expanded upon as necessary, making it far more flexible than creating multiple rewrite <rule> items in the web.config for multiple WebResource.axd calls. I've already checked, and the same idea can be used for ScriptResource.axd files which is nice, since should a browser introduce a breaking change to javascript that is emitted from an external tool, it can be debugged/updated/fixed relatively quickly without necessarily needing to wait for an update from the provider of the tool.