Question

I am trying to set up a reverse proxy for Jenkins using IIS 7.5, Application Request Routing 3.0 (ARR), and URL Rewrite 2.0.

I have the proxy mostly working, but am running into issues with URLs that contain the percent symbol (%).

No matter what I try, the proxy insists on either de-encoding or re-encoding the percent sign in the rewritten URL.

This is how I want the URLs rewritten:

http://my.proxy/a%2Fb -> http://my.host:8080/a%2Fb

This is how the URLs are actually being rewritten:

http://my.proxy/a%2Fb -> http://my.host:8080/a/b
- or -
http://my.proxy/a%2Fb -> http://my.host:8080/a%252Fb

How can I get IIS\ARR\Rewrite to stop re-encoding my rewritten URLs?

Things I've tried:

  1. A normal reverse-proxy (rewrites the URL as http://my.host:8080/a/b):

    <rule name="ReverseProxyInboundRule1" stopProcessing="true"> <match url="(.*)" ignoreCase="true" /> <action type="Rewrite" url="http://my.host:8080/{R:1}" /> </rule>

  2. Using the UNENCODED_URL server variable (rewrites the URL as http://my.host:8080/a%252Fb):

    <rule name="ReverseProxyInboundRule1" stopProcessing="true"> <match url="(.*)" ignoreCase="false" /> <conditions logicalGrouping="MatchAll"> <add input="{UNENCODED_URL}" pattern="/(.*)" /> </conditions> <action type="Rewrite" url="http://my.host:8080/{C:1}" /> </rule>

  3. Just entering the URL in straight (as a test - also rewrites the URL as http://my.host:8080/a%252Fb):

    <rule name="ReverseProxyInboundRule1" stopProcessing="true"> <match url="(.*)" ignoreCase="false" /> <action type="Rewrite" url="http://my.host:8080/a%2Fb" /> </rule>

  4. All the ideas in Scott Hanselman's excellent "Experiments in Wackiness: Allowing percents, angle-brackets, and other naughty things in the ASP.NET/IIS Request URL"

    1. <httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters="*,:,&amp;,\" relaxedUrlToFileSystemMapping="true" />
    2. <security> <requestFiltering allowDoubleEscaping="true" /> </security>'

Note: I ran into this behavior when my IIS reverse proxy ran afoul of Jenkins' built-in reverse proxy checking system which attempts to do an HTTP redirect to a URL of this form.

No correct solution

OTHER TIPS

Joseph, that is a great summary of all the ways I've tried to resolve the exact same issue, having IIS with SSL routing traffic to my Gerrit instance. When I found your post I hoped that maybe someone figured out a magic way to configure it but I guess it's not possible. I have tried one more thing, I've written a custom rewrite provider for IIS so that I can undecode the percent signs before routing is done, but then I realized that the encoding takes place later and this is pointless (I forgot about your step nr 3 that shows it very good).

I couldn't however get rid of IIS like out did, so I have figured a workaround. I have implemented a simple service that acts as additional proxy between IIS and Gerrit. When you configure IIS like in step 2, requests that are forwarded will get %25 in place of percent characters in the urls. Instead of reaching Gerrit, IIS forwards the requests to the proxy service. The service changes all occurrences of %25 to % (decodes percents) and forwards it to Gerrit. Nothing needs to be done with the response. For those who want to go this way you can start from my simple implementation of the proxy in C#:

https://gist.github.com/gralin/b5edfd908a41fc7268a7757698af1e66

I was able to fix this issue using the second approach and setting useOriginalURLEncoding="false":

<rules useOriginalURLEncoding="false">
    <rule name="ReverseProxyInboundRule1" stopProcessing="true">
        <match url="(.*)" ignoreCase="false" />
        <conditions logicalGrouping="MatchAll">
            <add input="{UNENCODED_URL}" pattern="/(.*)" />
        </conditions>
        <action type="Rewrite" url="http://my.host:8080/{C:1}" />
    </rule>
</rules>

See also the official blog post for background information. The wording of useOriginalURLEncoding is a bit unfortunate.

I have thought using proxy with url contains % symbol has the problem, but after that i have found out it wasn't. The issue that the proxy URL too long.

I use datatable with option server-side: true and type: GET. Then when loading content from server with the proxy url too long, there is a problem. I have improve the size of url request and the issue has been fixed.

<system.webServer>
    <security>
        <requestFiltering>
            <requestLimits maxQueryString="4000" maxUrl="2000" />
        </requestFiltering>
    </security>
    <rewrite>...</rewrite>
    ...
</system.webServer>

But keep in mind that allowing long query string and url is a security risk, more over, it’s a bad design.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top