IIS URL Rewrite - URL gets partially decoded in the rewrite process - iis

I have an API service running that accepts various API calls with a long parameter string that works. I have recently created an IIS redirect site as a intermediary to support https where the API system only supports http calls. The https re-write process works fine. However I noticed that IIS URL rewrite process partially decode the URL before sending it to the API service where the service fails to decode the URL. API call details are as follows:
Calling the API service directly(this works fine)
Original URL:
http://10.0.0.119:8041/datasnap/rest/TTransactionsModule/GetTransactions/%22%5B%7B%22FilterTypeID%22%3A6001%2C%22NotOperator%22%3Afalse%2C%22SortOrder%22%3A0%2C%22StartGroup%22%3A0%2C%22EndGroup%22%3A0%2C%22Values%22%3A%5B%22SO%22%5D%2C%22OperatorType%22%3A%22operator_Equals%22%2C%22SortType%22%3A%22SortType_Ascending%22%2C%22LogicOp%22%3A%22LogicOp_And%22%2C%22IsValid%22%3A%22False%22%2C%22RefCount%22%3A%220%22%2C%22Changed%22%3Afalse%7D%2C%7B%22FilterTypeID%22%3A6003%2C%22StartGroup%22%3A1%2C%22EndGroup%22%3A1%2C%22AvailableOperators%22%3A%5B%5D%2C%22NotOperator%22%3Afalse%2C%22OperatorType%22%3A%22operator_Between%22%2C%22Values%22%3A%5B%2213%2F05%2F2021%22%2C%2211%2F08%2F2021%22%5D%2C%22LogicOp%22%3A%22LogicOp_And%22%2C%22SortOrder%22%3A1%2C%22SortType%22%3A%22SortType_Descending%22%2C%22IsValid%22%3A%22False%22%2C%22RefCount%22%3A%220%22%7D%5D%22/1/1/false
Decoded URL (Please note that encoding needs to be done to send dates falling in the URL):
http://10.0.0.119:8041/datasnap/rest/TTransactionsModule/GetTransactions/"[{"FilterTypeID":6001,"NotOperator":false,"SortOrder":0,"StartGroup":0,"EndGroup":0,"Values":["SO"],"OperatorType":"operator_Equals","SortType":"SortType_Ascending","LogicOp":"LogicOp_And","IsValid":"False","RefCount":"0","Changed":false},{"FilterTypeID":6003,"StartGroup":1,"EndGroup":1,"AvailableOperators":[],"NotOperator":false,"OperatorType":"operator_Between","Values":["13/05/2021","11/08/2021"],"LogicOp":"LogicOp_And","SortOrder":1,"SortType":"SortType_Descending","IsValid":"False","RefCount":"0"}]"/1/1/false
The parameter section that the API service receives:
%22%5B%7B%22FilterTypeID%22%3A6001%2C%22NotOperator%22%3Afalse%2C%22SortOrder%22%3A0%2C%22StartGroup%22%3A0%2C%22EndGroup%22%3A0%2C%22Values%22%3A%5B%22SO%22%5D%2C%22OperatorType%22%3A%22operator_Equals%22%2C%22SortType%22%3A%22SortType_Ascending%22%2C%22LogicOp%22%3A%22LogicOp_And%22%2C%22IsValid%22%3A%22False%22%2C%22RefCount%22%3A%220%22%2C%22Changed%22%3Afalse%7D%2C%7B%22FilterTypeID%22%3A6003%2C%22StartGroup%22%3A1%2C%22EndGroup%22%3A1%2C%22AvailableOperators%22%3A%5B%5D%2C%22NotOperator%22%3Afalse%2C%22OperatorType%22%3A%22operator_Between%22%2C%22Values%22%3A%5B%2213%2F05%2F2021%22%2C%2211%2F08%2F2021%22%5D%2C%22LogicOp%22%3A%22LogicOp_And%22%2C%22SortOrder%22%3A1%2C%22SortType%22%3A%22SortType_Descending%22%2C%22IsValid%22%3A%22False%22%2C%22RefCount%22%3A%220%22%7D%5D%22
Calling the API service via the IIS rewrite process:
Original URL that gets passed to the ISS site (Exactly the same call other than the https and dns) :
https://10.0.0.119:9015/datasnap/rest/TTransactionsModule/GetTransactions/%22%5B%7B%22FilterTypeID%22%3A6001%2C%22NotOperator%22%3Afalse%2C%22SortOrder%22%3A0%2C%22StartGroup%22%3A0%2C%22EndGroup%22%3A0%2C%22Values%22%3A%5B%22SO%22%5D%2C%22OperatorType%22%3A%22operator_Equals%22%2C%22SortType%22%3A%22SortType_Ascending%22%2C%22LogicOp%22%3A%22LogicOp_And%22%2C%22IsValid%22%3A%22False%22%2C%22RefCount%22%3A%220%22%2C%22Changed%22%3Afalse%7D%2C%7B%22FilterTypeID%22%3A6003%2C%22StartGroup%22%3A1%2C%22EndGroup%22%3A1%2C%22AvailableOperators%22%3A%5B%5D%2C%22NotOperator%22%3Afalse%2C%22OperatorType%22%3A%22operator_Between%22%2C%22Values%22%3A%5B%2213%2F05%2F2021%22%2C%2211%2F08%2F2021%22%5D%2C%22LogicOp%22%3A%22LogicOp_And%22%2C%22SortOrder%22%3A1%2C%22SortType%22%3A%22SortType_Descending%22%2C%22IsValid%22%3A%22False%22%2C%22RefCount%22%3A%220%22%7D%5D%22/1/1/false
The parameter section that the API service receives from the ISS rewrite process:
%22%5B%7B%22FilterTypeID%22:6001,%22NotOperator%22:false,%22SortOrder%22:0,%22StartGroup%22:0,%22EndGroup%22:0,%22Values%22:%5B%22SO%22%5D,%22OperatorType%22:%22operator_Equals%22,%22SortType%22:%22SortType_Ascending%22,%22LogicOp%22:%22LogicOp_And%22,%22IsValid%22:%22False%22,%22RefCount%22:%220%22,%22Changed%22:false%7D,%7B%22FilterTypeID%22:6003,%22StartGroup%22:1,%22EndGroup%22:1,%22AvailableOperators%22:%5B%5D,%22NotOperator%22:false,%22OperatorType%22:%22operator_Between%22,%22Values%22:%5B%2213/05/2021%22,%2211/08/2021%22%5D,%22LogicOp%22:%22LogicOp_And%22,%22SortOrder%22:1,%22SortType%22:%22SortType_Descending%22,%22IsValid%22:%22False%22,%22RefCount%22:%220%22%7D%5D%22
When the parameter sections compared in either case it is clear that the URL revived via the IIS rewrite process decoded some characters such as ":" and "," (Example: near 6001 in the parameter section)
Can someone help me to fix this problem. Need to set the IIS re-write process to pass the exact URL parameter list it received to the API service without any decoding or encoding.
My IIS re-write web.config file content is as follows (Note that need to set the maxRequestLength, maxUrlLength, maxQueryStringLength for long URLs and requestValidationMode="2.0" to support cirtan URL validations)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://localhost:8041/{R:1}" appendQueryString="false" />
</rule>
</rules>
</rewrite>
</system.webServer>
<system.web>
<httpRuntime maxRequestLength="2097151" maxUrlLength="2097151" maxQueryStringLength="2097151" requestValidationMode="2.0" />
</system.web>
</configuration>
Thanks in advance,
Dan

In iis there is a feature flag, useOriginalURLEncoding that allows you to turn off this non-compliant URL Encoding when set to true.
To set the flag to go IIS Manager, then select Configuration Editor and go to the section system.webServer/rewrite/rules, where you will find the useOriginalURLEncoding flag, set the flag to false, and URL Rewrite will no longer encode the URL.

Related

Using emsserver/emsserver.dll in URL of API Call in Production Environment

I have created an application that utilizes RAD Studio's EMS Server functionality. The development has been completed and tested in a production environment. The EMS Server documentation shows that in order to make an API call the emsserver.dll needs to be included in the URL.
https://{hostname}/emsserver/emserver.dll/API/Login?token={TokenValue}
Most APIs I have encountered do not have the dll embedded into the URL.
https://{hostname}/API/Login?token={TokenValue}
This is not a big deal as the API call works fine as is. I was just wondering if there is property or setting I can use in RAD Server or IIS in order to default the emsserver/emsserver.dll portion of the URL.
Do you mean you want to redirect or rewrite the url from https://{hostname}/API/Login?token={TokenValue} to https://{hostname}/emsserver/emserver.dll/API/Login?token={TokenValue} in IIS?
If this is your reuqimrent, I suggest you could try to use url rewrite extension to achieve your reuqirement.
You could install it from this url and add below url rewrite rule into your web.config file.
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect to dll">
<match url="API/Login" />
<action type="Rewrite" url="https://{hostname}/emsserver/emserver.dll/API/Login" />
</rule>
</rules>
</rewrite>
</system.webServer>

URL ReWriting to a different server - rules are ignored and default website is answering requests

I'm struggling with IIS' URL Rewrite and ARR Modules.
Basically, here's the current state of affairs:
I have a main webserver, awnsering all of my requests. Let's name this MAINWEBSERVER.
I have a secondary server with a specific application that's working as intended if you access it internally but needs to be exposed to the outside via domain to work as a webservice. Let's name this server APPSERVER.
I wish to receive my requests on MAINWEBSERVER and rewrite the URL if it matches my wildcard.
In this case, my Wildcard is https://example.com/MYAPPLICATION* .
And my desired redirect is https://APPSERVER/MYAPPLICATION/WhateverIsLeftInTheUrl .
So here's my rule sitting on my MAINWEBSERVER:
<rewrite>
<rules>
<rule name="Rewrite to Application" patternSyntax="Wildcard" stopProcessing="true">
<match url="https://example.com/MYAPPLICATION*" />
<action type="Rewrite" url="https://APPSERVER/MYAPPLICATION{R:1}" logRewrittenUrl="true" />
</rule>
</rules>
</rewrite>
NOTE: I need the URL rewritten for certificate SAN purposes (it won't validate APPSERVER/MYAPPLICATION, so I want to use a mask that is validated by my certificate, such as https://example.com/MYAPPLICATION).
The steps I took were:
Installing ARR (activating proxy settings);
Installing URL ReWrite Module;
Configuring wildcard rule for https://example.com/MYAPPLICATION;
Configuring rewrite for https://APPSERVER/MYAPPLICATION{R:1} (in case it has querystrings I wish to keep them);
Generated personal certificates to validate HTTPS requests between MAINWEBSERVER and APPSERVER;
Whenever I make my request the rule is ignored (despite the same URL matching the wildcard perfectly) and the default website application awnsers, considering my wildcard a querystring parameter.
I've tried this both at server level and at default website level, even with Reverse Proxy Rules. I also have experimented with Fiddler and Failed Request Tracing but to no effect.
In the FRT all that is displayed is a 302 HTTP CODE and in the end a 200 Status Code when the default website loads.
Note that I believe this was working on a different server before, using this same rule although there was no default website.

Is it possible to configure IIS (specifically, in Azure) to work with HistoryLocation?

I have React app which ends up being built with webpack. We host an API which this app talks to on Azure and would like to host the UI built on top of it out there as well.
When hitting the URL the first time, and navigating around, all of the history location stuff works. However, when we refresh the page, we receive a 404 error (which is to be expected if IIS is serving this).
Is it possible to configure Azure to handle this sort of thing? Should we just give up on this type of application and host a webpack vm?
Similar questions:
Reactjs HistoryLocation get 404 on refresh
React-router urls don't work when refreshing or writting manually
If do understand your question and situation correctly, the solution would be to redirect all requests to your only one HTML page (assuming index.html).
This can be achieved with the URL rewrite module of IIS.
By default any Azure Web App will have a file in its web root folder named web.config. This is standard XML file. Open it with favorite editor and locate <system.webserver> section. Then place the following additional sections inside. Note, the <rewrite> element should be direct descendant of the <system.webserver> one:
<rewrite>
<rules>
<rule name="Rewrite to index.html">
<match url=".*" />
<action type="Rewrite" url="index.html" />
</rule>
</rules>
</rewrite>
Again, based on the assumption that you serve everything from index.html, you can change this file in the rewrite rule to represent the file you are serving content from.

Application Request Routing: Get Original URL

I'm trying to get the original URL from within my application (MVC 5) after a reverse proxy rewrite has occurred.
I've tried everything I can find e.g.
Setting my own server variable to the value of {HTTP_HOST} (my server variable started with HTTP). This either contains the current URL or null.
Using HTTP_X_ORIGINAL_URL server variable which does not include the hostname.
Looking at all the built in server variables.
Setting the value preserveHostHeaders as detailed here: https://stackoverflow.com/a/7180527/4950, this caused the site to hang
Any ideas?
Tried on IIS7 and IIS7.5 with ARR 3.0 and Url Rewrite 2.0
This answer is inspired by Setting HTTP request headers and IIS server variables in the IIS documentation. They do something similar, but oddly it avoids detecting whether the original URL was accessed with HTTP or HTTPS.
First, you need to have administrative access to your IIS server in order to set up a new allowed server variable in the URL Rewrite module. This is described in the linked article, but here are the basic steps:
In IIS Manager, navigate to your web site or application folder.
Open the URL Rewrite feature.
In the Actions pane, click "View Server Variables...", then click "Add..."
Enter a name for your server variable.
If you want to access it as an HTTP header, prefix it with HTTP. For example, HTTP_X_MY_HEADER is accessible as the X-MY-HEADER header.
Then, in your rewrite rule, set the server variable value to {CACHE_URL}. You can do this through the UI, or directly in web.config, as shown below.
NOTE: be sure to set your match, conditions, and actions as needed.
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="original URL sample" stopProcessing="true">
...
<serverVariables>
<set name="HTTP_X_MY_HEADER" value="{CACHE_URL}" />
</serverVariables>
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
The resulting header will explicitly include the port number, e.g. http://foo.example:80/bar, so you may need to deal with that depending on your needs.

Using IIS and ARR to reverse proxy returns "The server returned an invalid or unrecognized response"

I'm in the process of migrating from one site to another and, although the websites sit on the same server, they aren't in the same application pool.
As such, what I'm proposing is similar to the IIS article 'Reverse Proxy with URL Rewrite v2 and Application Request Routing'.
My setup as as follows:
Default Website (accepts connections on *:80 and *:443).
New Website (accepts connections on *:81)
I've enabled proxying in the ARR module and have one rewrite rule in 'New Website'. Currently, I only have one page in the new site (new-page), but this will increase gradually as we migrate over.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Reverse Proxy to New Website" stopProcessing="true">
<match url="^new-page" />
<action type="Rewrite" url="http://www.mysite.com:81/new-page" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
When I go to www.mysite.com/index.htm, I see my old homepage, which is correct.
However, if I go to www.mysite.com/new-page, I receive an error:
HTTP Error 502.3 Bad Gateway
The server returned an invalid or unrecognized response
Any help with this would be greatly appreciated.
Edit:
I have also enabled WinHttp tracing, and a log of the request today can be found here at pastebin.
I have some further information (retrieved from IIS Failed Request Logging) below.
It appears that ARR has an issue with headers that have spaces in.
The new application has a single header with a space, and replacing it with a hyphen fixed the issue.
I just ran into this. However, my problem had to do with conflicting cookies.
A good test is to use a different browser (or incognito in Chrome). If it works on the other browser, it could be the cookies. Try deleting the cookies to see if that helps. If it's something you can control, try changing the cookie name between different sites/environments you may have. If it's out of your control (you're doing a reverse proxy to some tool you've purchased, this may not be possible).

Resources