Why Outbound rules in URL rewrite?

If we want to make any changes in the response headers or content after the processing has been completed by the specific handler or execution engine before sending it to the client, we can use outbound rules.

How to create an outbound rule?

To create an outbound rule click on the site-> go to url rewrite-> click on Add rule(s)-> select blank rule under outbound rules

clip_image002

Sections in an outbound rule:

clip_image003

1) Precondition: you can specify over here as to what kind of responses your rule should be executed. Probably you can specify the rule to be executed to all html responses specifying content type as text/html

2) Matching scope: over here you can specify which section you want to modify, either response headers or Response content section

a) Response: if you want to modify the content then you can select this as the matching scope

b) Server variable: if you want to modify the headers or remove the headers then you can select this as matching scope

3) Pattern: Pattern is the place where you define a regular expression to match the current value of a header or content tag(for eg: <a href>)

4) Conditions: This is similar to the conditions section in inbound rules.

5) Action Type: This can be rewrite or none

6) Value: Here we replace the existing value with new value.

Let’s consider some scenarios and create few outbound rules.

Scenario 1:

This is the most common requirement among managements where they don’t want to reveal the server information from where the content is provided. Imagine we want to remove the Server header in the response.

clip_image004

Over here matching scope will be server variable as we are trying to modify a response header

To query for any response header the response header variable name will be preceded by RESPONSE_Headername, so over here the variable name will RESPONSE_SERVER

Pattern can be .*

Action type will be rewrite and the rewrite value will be 0.

clip_image005

Below is how the rule looks like in IIS.

clip_image007

Below is the config snippet in web.config

<rule name="removingserverheader" enabled="true">

<match serverVariable="RESPONSE_SERVER" pattern=".*" />

<action type="Rewrite" value="0" />

</rule>

Note: Similarly if you want remove asp.net version from the headers i.e. X-Powered-By then the server variable would be RESPONSE_X_POWERED_BY and the rule would be similar as above.

Scenario 2:

Imagine you have a href tag in your code hardcoded with the value or link of an old server and you don’t have the authority to change the code but would like to change the href value to point to new address then you can use URL rewrite outbound rule to modify the content or html response before sending it to the client.

<a href="http://oldcontoso.com"><img src="welcome.png" alt="IIS7" width="571" height="411" /></a>

Let’s consider that old url was http://oldcontoso.com and the new url to be rewritten to is http://contosso.com

Over here we are trying to change the content of the html response before sending it to the client so the Matching scope will be Response

Match the content within will be A

Pattern will be .*oldcontoso.com

Action Type will be rewrite and the new value will be http://contosso.com

Below is how the rule looks like in IIS.

clip_image009

Below is the snippet in the web.config

<rule name="changinghref" enabled="false">

<match filterByTags="A" pattern=".*oldcontoso.com" />

<action type="Rewrite" value="http://contosso.com" />

</rule>

Scenario 3:

Imagine we had hardcoded a response.redirect statement to an old url and we want it to be rewritten to the new url. In the code we have Response.redirect(“http://oldcontosso.com”), but the new url is http://contosso.com

Whenever we have a redirect a 302 response along with the location tag of the redirect url will be send to the client. So the catch over here is to modify the Response header location and set it to new url before sending the response to the client.

Over here the Matching scope will be server variable as it is a response header and the Variable name will be RESPONSE_LOCATION, pattern will be .*oldcontosso.com

Action type will be rewrite and new value will be http://contosso.com

Below is how the rule looks like in IIS

clip_image011

Below is the entry in web.config

<rule name="changinglocationtag value" enabled="false">

<match serverVariable="RESPONSE_LOCATION" pattern=".*oldcontosso.com" />

<action type="Rewrite" value="http://contosso.com" />

</rule>

Note: While modifying the response body in outbound rules we have to be careful because if we have compression turned on then we might get 500.52 error.

If we get 500.52 error when browsing the application and work around for Dynamic compression and outbound URL rewrite to work together is to have:

· Adding LogRewrittenUrlEnabled registry key under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp\Rewrite to 0 or by running below command line: “reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp\Rewrite /v LogRewrittenUrlEnabled /t REG_DWORD /d 0

· Set the dynamicCompressionBeforeCache property to false for /system.webServer/urlCompression configuration element. Can be done from adding in web.config as below

<urlCompression doStaticCompression=”false” doDynamicCompression=”true” dynamicCompressionBeforeCache=”false” />

OR

By running the below command from command prompt

appcmd.exe set config "WEBSITENAME" -section:system.webServer/urlCompression /dynamicCompressionBeforeCache:"False"

· Re-arrange the IIS modules to have URL Rewrite module (RewriteModule) to run before Dynamic Compression module (DynamicCompressionModule). In IIS manager under Modules section, click on View ordered List and make sure that DynamicCompressionModule is above RewriteModule.

· Reset IIS

We have another scenario where my application pool is running under 32 bit on a 64 bit machine i.e. Enable 32-Bit Applications was set to true for my application pool setting and after running process monitor found out that LogRewrittenUrlEnabled registry key was expected in below location.

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\Microsoft\Inetstp\Rewrite.

Workaround for Dynamic compression and outbound URL rewrite to work together for a 32-bit enabled application is to have:

· Adding LogRewrittenUrlEnabled registry key under HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\Microsoft\Inetstp\Rewrite to 0 or by running below command line: “reg add HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\Microsoft\Inetstp\Rewrite /v LogRewrittenUrlEnabled /t REG_DWORD /d 0”

· Set the dynamicCompressionBeforeCache property to false for /system.webServer/urlCompression configuration element. Can be done from adding in web.config as below

<urlCompression doStaticCompression=”false” doDynamicCompression=”true” dynamicCompressionBeforeCache=”false” />

OR

By running the below command from command prompt

appcmd.exe set config "WEBSITENAME" -section:system.webServer/urlCompression /dynamicCompressionBeforeCache:"False"

· Re-arrange the IIS modules to have URL Rewrite module (RewriteModule) to run before Dynamic Compression module (DynamicCompressionModule). In IIS manager under Modules section, click on View ordered List and make sure that DynamicCompressionModule is above RewriteModule.

· Reset IIS.

Rewrite Maps:

• A rewrite map is an arbitrary collection of name and value pairs that can be used within rewrite rules to generate a substitution URL during rewriting.

• Rewrite maps are particularly useful when you have a large set of rewrite rules and all of these rules use static strings (that is, when there is no pattern matching used)

Scenario 1:

Imagine you have a requirement where requests coming into a.aspx should be rewritten to b.aspx and request coming in to c.aspx should be rewritten to d.aspx. Instead of creating 2 redundant rules for this static change in resources, you can create a single rule to achieve this requirement. This can be achieved in two steps. 1) Creating a rewrite map 2) Creating an inbound rule and utilizing the rewrite map.

1) Creating the rewrite map:

Over here we will create rewrite map which will contain key value pairs mapping a.aspx to b.aspx and c.aspx to d.aspx

To create a rewrite map click on a site-> go to url rewrite-> click on view rewrite maps-> Add rewrite map

clip_image013

clip_image015

After creating the rewrite map you need to you need to create a [key:value] pair. To do that click on Add Mapping Entry.

clip_image017

Repeat the above step twice to map a.aspx to b.aspx and to map c.aspx to d.aspx

2) Creating the inbound rule:

Now we have the rewrite map and we need to create an inbound rule to dynamically replace the value as b.aspx if the requested resource is a.aspx and as d.aspx if the requested resource is c.aspx

Over here you can have the pattern set to .* that is match anything and the pattern will be stored in {R:0}. Now we will have the resource name in {R:0} and we need to check if it is a.aspx or c.aspx and fetch the value from rewrite maps accordingly.

Add a condition with condition input as {keyvalue:{R:0}} (where keyvalue is the rewrite map name and it contains key:value pair array) and this input will fetch the value of the resource. Below are the values that will be fetched.

{keyvalue:a.aspx}->b.aspx

{keyvalue:c.aspx}->d.aspx

{keyvalue:anythingelse}-> null value

And in the condition the value returned should not be null and should contain a resource name, so the pattern would be (.+).

I have put in the pattern within braces() because I am storing the pattern section or value returned in variable {C:1}. These are similar to value arrays{R:x}. Any pattern within condition is stored in a variable array {C:x} where x is an integer.

clip_image019

So the new resource value is now in a variable called {C:0} or {C:1}

The action type will be Rewrite and the Rewrite value will be {C:0}.

Below is how the rule looks like in IIS.

clip_image021

clip_image022

Below is the rule in config section

Rewrite Maps:

<rewriteMaps>

<remove name="page" />

<rewriteMap name="keyvalue">

<add key="a.aspx" value="b.aspx" />

<add key="c.aspx" value="d.aspx" />

</rewriteMap>

</rewriteMaps>

Inbound rule:

<rule name="rewritemaps" enabled="false" patternSyntax="ECMAScript">

<match url=".*" />

<conditions trackAllCaptures="true">

<add input="{keyvalue:{R:0}}" pattern="(.+)" />

</conditions>

<action type="Rewrite" url="{C:0}" />

</rule>

I think this was helpful. I will update the next blog on how to use URL Rewrite with ARR.