Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

I am trying to compare two server variables as part of a URL rewrite condition. But first, some context...

In IIS, if you request http://www.example.com/foo and foo is a directory, IIS sends a 302 "Object moved" redirect to http://www.example.com/foo/ as a "courtesy redirect" (Source).

If you are using IIS+ARR as reverse proxy with SSL offloading, the request that the back-end IIS node receives is over http, not https.

Combine these two behaviors, and IIS's courtesy redirects drop SSL. The courtesy redirect uses the same scheme as the request that IIS received (Source), http in this case instead of https.

I'd like to create an outbound rewrite rule that will compare the incoming URL with the outgoing Location header and rewrite it from http to https in this case:

  • The response is a redirect: {RESPONSE_STATUS} is 302
  • The incoming request was over SSL: {HTTPS} is "on"
  • The incoming URL does not end in a slash.
  • The outgoing Location header ends in a slash.

All of the above is handled in the precondition. The tricky part is the last bit:

  • The path of the outgoing Location header is the same as the incoming URL with a slash appended.

Below is the code I have so far. The precondition and header rewrite both work fine. However, the condition causes a 500 error (URL Rewrite module error), presumably because I'm using {REQUEST_URI} in the pattern. I've tried separating the condition into two and using capture groups, but that didn't work either. Any ideas?

<rule name="Fix: Courtesy Redirect + SSL Offloading = SSL dropped" preCondition="Courtesy Redirect Drops SSL" enabled="true">
    <match serverVariable="RESPONSE_LOCATION" pattern="^http://(.+/)$" />
    <conditions>
        <add input="{RESPONSE_LOCATION}" pattern="{REQUEST_URI}/" />
    </conditions>
    <action type="Rewrite" value="https://{R:1}" />
</rule>
<preConditions>
    <preCondition name="Courtesy Redirect Drops SSL">
        <add input="{RESPONSE_STATUS}" pattern="^302$" />
        <add input="{HTTPS}" pattern="^on$" />
        <add input="{REQUEST_URI}" pattern=".*[^/]$" />
        <add input="{RESPONSE_LOCATION}" pattern="^http://.+/$" />
    </preCondition>
</preConditions>
share|improve this question

1 Answer 1

You can use a custom rewrite provider: http://www.iis.net/learn/extensions/url-rewrite-module/developing-a-custom-rewrite-provider-for-url-rewrite-module

A provider is a C# code, which turns one string into another string. You can then use it in a similar way how you'd use rewrite map:

You can pick a separator, which is not valid in a url at all (maybe space or something like that, I'll use "|" so it's visible in this post but you should pick some other string).

You'll write a rule to set value of server variable "IsItMatching". The value of the server variable will be set using your custom url rewrite provider:

{provider_name:{server_variable_1}|{server_variable_2}}

The C# code implementing the provider will then do this (pseudo-code, no error checking):

string Rewrite(string input)
{
    string[] inputVariables = input.split(separator);
    if (inputVariables[0] == inputVariables[1] + "/")
        return "yes";
    else
        return "no";
}

Then you'll write one more rule to check whether the value of the "IsItMatching" server variable is "yes" or "no".

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.