Append Query String to IIS Rewrite Map - asp.net

I have a ReWrite Map and I would like to append any query parameters in the requested URL to the rewritten URL.
For instance:
/page/abc/ ---> /index.cfm?page=abc (works)
/page/abc/?param1=111 ---> /index.cfm?page=abc&param1=111 (doesn't work)
/page/abc/?param3=333&param4=444 ---> /index.cfm?page=abc&param3=333&param4=444 (doesn't work)
My web.config is:
[...]
<rules>
<clear />
<rule name="Rewrite rule1 for SiteMapEngine">
<match url=".*" />
<conditions>
<add input="{SiteMapEngine:{REQUEST_URI}}" pattern="(.+)" />
</conditions>
<action type="Rewrite" url="{C:1}" appendQueryString="true" />
</rule>
</rules>
[...]

Short answer:
Use PATH_INFO server variable instead of REQUEST_URI, as you do not want to include the query string in the matching.
Full explanation:
This has caught me out before - basically it is a subtlety of using Rewrite Maps in the IIS URL Rewrite Module.
In your case, SiteMapEngine will be a static key-value list of URLs:
<rewrite>
<rewriteMaps>
<rewriteMap name="SiteMapEngine" defaultValue="">
<add key="/page/abc/" value="/index.cfm?page=abc" />
...
</rewriteMap>
</rewriteMaps>
...
</rewrite>
The {SiteMapEngine:{REQUEST_URI}} condition in your rule checks whether there is a key in this rewrite map matching the REQUEST_URI server variable:
{REQUEST_URI} = /page/abc/?param1=111
Notice that this variable includes the query string - it therefore fails to find a matching key.
Instead, use the PATH_INFO server variable, which is the equivalent of REQUEST_URI but without the query string:
{PATH_INFO} = /page/abc/
So the correct rule is:
<rule name="Rewrite rule1 for SiteMapEngine">
<match url=".*" />
<conditions>
<add input="{SiteMapEngine:{PATH_INFO}}" pattern="(.+)" />
</conditions>
<action type="Rewrite" url="{C:1}" />
</rule>

I'll be damned if I can find a reference for this, but it's my understanding that in some versions of IIS {REQUEST_URI} comes back without it's query string, and will be empty entirely if rewriting is enabled.
You should be able to use {PATH_INFO} instead.
This bug report (against Drupal!) is the issue you're describing, I think: http://drupal.org/node/298016
There's a hotfix from Microsoft, but I haven't tried it: http://support.microsoft.com/kb/954946

Here is my rule. It seems to work as expected:
<rule name="Insert index.cfm" enabled="true" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="index.cfm/{PATH_INFO}" appendQueryString="true" />
</rule>

Related

IIS Redirect HTTP to HTTPS and WWW to non-WWW

On IIS 10 with URL Rewrite Module 2.0 I need 2 rules
1) HTTP to HTTPS
2) WWW to non-WWW
First one created by Blank rule template.
For second one I use Canonical domain name template.
In my web.config rules likes like this:
<rewrite>
<rules>
<rule name="ForceHttps" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" />
</rule>
<rule name="CanonicalHostNameRule1" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^cooltechunder\.com$" negate="true" />
</conditions>
<action type="Redirect" url="https://cooltechunder.com/{R:1}" />
</rule>
</rules>
</rewrite>
All cases works fine expect one starting with: http://www.
See this image for results I have:
https://i.imgur.com/h2l3Yw6.png
You wrote stopProcessing="true".
This means that, if the rule matches, subsequent rules will be skipped.
From the documentation:
A rule may have the StopProcessing flag turned on. When the rule action is performed (i.e. the rule matched) and this flag is turned on, it means that no more subsequent rules will be processed and the request will be passed to the IIS request pipeline. By default, this flag is turned off.
It seems to me that this is the situation you are describing that you did not want.
So, remove it.
Ok, My problem was different and related to bindings.
I have to specify 'Host Name' in bindings, as specific ports used by other websites also
And I forgot to add 'www' versions of bindings also.
Now my bindings looks like this: https://i.imgur.com/Lhdv4nS.jpg
Also I have changed rewrite code to more compact one:
<rewrite>
<rules>
<rule name="Https and non-www">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTPS}" pattern="^OFF$" />
<add input="{HTTP_HOST}" pattern="^cooltechunder\.com$" negate="true" />
</conditions>
<action type="Redirect" url="https://cooltechunder.com/{R:1}" />
</rule>
</rules>
</rewrite>

Regex for URL rewrite with optional query string parameters

I have this rewrite rule:
<rule name="rentals by proptype+state+city+street test" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{UNENCODED_URL}" pattern="^/([a-zA-Z0-9\-+]+)/rent/province/([a-zA-Z\-+]+)/street/([a-zA-Z0-9%\-+]+)/([0-9a-zA-Z%\-+']+)$" />
</conditions>
<action type="Rewrite" url="search_new.aspx?proptype={C:1}&province={C:2}&city={C:3}&street={C:4}" appendQueryString="true" />
</rule>
I also tried:
<rule name="rentals by proptype+state+city+street test" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{UNENCODED_URL}" pattern="^/([a-zA-Z0-9\-+]+)/rent/province/([a-zA-Z\-+]+)/street/([a-zA-Z0-9%\-+]+)/([0-9a-zA-Z%\-+']+)$" />
<add input="{QUERY_STRING}" pattern=".*" />
</conditions>
<action type="Rewrite" url="search_new.aspx?proptype={C:1}&province={C:2}&city={C:3}&street={C:4}" appendQueryString="true" />
</rule>
This URL works: http://www.example.com/apartment/rent/province/texas/street/houston/mystreet
But when I add query string parameters, the URL throws a 404: http://www.example.com/apartment/rent/province/texas/street/houston/mystreet?rooms=3&pricemin=2500
I already checked here:
IIS URL Rewrite not working with query string
https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/url-rewrite-module-configuration-reference
https://msdn.microsoft.com/en-us/library/ms972974.aspx
It seems I have to use a QUERY_STRING server variable.
I actually just want to append the query string parameters, without having to write a special mapping for each parameter. I thought I could solve this through the appendQueryString="true" property, but that apparently doesn't work.
How can I make sure my rewrite rule works also with query string parameters?
When I look at your rule, I understand that you are looking for a complete match (^...$) with URL Path.
However {UNENCODED_URL} may contain query strings too. So this breaks your rule when the URL contains any query string, even if it's just a query separator (?).
To fix this you should look for a match until the beginning of the query string instead, not till the end.
Try the following rule.
<rule name="rentals by proptype+state+city+street test" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{UNENCODED_URL}" pattern="^/([a-zA-Z0-9\-+]+)/rent/province/([a-zA-Z\-+]+)/street/([a-zA-Z0-9%\-+]+)/([0-9a-zA-Z%\-+']+)" />
</conditions>
<action type="Rewrite" url="search_new.aspx?proptype={C:1}&province={C:2}&city={C:3}&street={C:4}" appendQueryString="true" />
</rule>

IIS Query string lost when using URL Rewrite rules

I am trying to get a site to work with a different URL, basically one is the real URL(fakesite.com) and the other is a Branded URL(NewFakeSite.com). So far ive managed to get it to work so that:
http://fakesite.com/uv/ExpressBranding/ExpressHome.aspx
and
http://NewFakeSite.com/uv/ExpressBranding/ExpressHome.aspx
Both go to the same site and are both able to work as functioning sites. The Problem comes with Querystrings, I cant seem to get the second site to pass along the Querystring so if I go to a URL with a Querystring like:
http://fakesite.com/uv/EnviSetup/Wizard/GeneralInformation.aspx?DashboardId=0
For the Second site it cant find the page and instead gives me:
https://NewFakeSite.com/uv/EnviSetup/Wizard/GeneralInformation.aspx
with no QueryString at all.As such I need to add the Querystring. My webconfig is below, its not just my code so certain pieces of it like the HTTP to HTTPS and adding uv were not written by me.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<remove name="Redirect to HTTPS" />
<remove name="Redirect to add uv folder to dotcom" />
<rule name="Redirect to add uv folder to dotcom" enabled="true" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{map add uv after dotcom:{REQUEST_URI}}" pattern="(.+)" />
</conditions>
<serverVariables />
<action type="Redirect" url="{C:1}" appendQueryString="false" />
</rule>
<rule name="Redirect to HTTPS" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTPS}" pattern="^OFF$" />
<add input="{SERVER_NAME}" pattern="opterra\.esightenergy\.com" negate="true" />
</conditions>
<serverVariables />
<action type="Rewrite" url="https://{HTTP_HOST}/{R:1}" appendQueryString="false" />
</rule>
<rule name="AddQueryStringForENVIDashBoards">
<match url="https://prod.utilityvision.com/uv/EnviSetup/EnviDashboardList.aspx(\?(.*))" />
<action type="Rewrite" url="HTTPS://opterra.esightenergy.com/uv/EnviSetup/Wizard/{C:1}" appendQueryString="false" />
<conditions>
<add input="{URL}" pattern="https://prod.utilityvision.com/uv/EnviSetup/Wizard/(.*)" />
</conditions>
</rule>
</rules>
</rewrite>
<httpRedirect enabled="false" destination="" exactDestination="false" childOnly="false" />
</system.webServer>
</configuration>
Any Help would be greatly appreciated I am new to IIS so I hope this is even possible. Thanks!
EDIT: I have tried setting the appendQueryString="True" but still no Querystring. Thanks mjw.
Edit 2: The main goal is to make make it so the URL shows up as something different then it was originally programmed as, The problem is the Query String doesnt come with the rest of the new URL. I have added some code changes to see if this would fix the problem but it did not the URL remained the same. The code sample above is not the original I added this:
<rule name="AddQueryStringForENVIDashBoards">
<match url="https://prod.utilityvision.com/uv/EnviSetup/EnviDashboardList.aspx(\?(.*))" />
<action type="Rewrite" url="HTTPS://opterra.esightenergy.com/uv/EnviSetup/Wizard/{C:1}" appendQueryString="false" />
<conditions>
<add input="{URL}" pattern="https://prod.utilityvision.com/uv/EnviSetup/Wizard/(.*)" />
</conditions>
</rule>
You have server variable for query string so you can use it to append value to the redirection url:
QUERY_STRING
So for your request http://fakesite.com/uv/EnviSetup/Wizard/GeneralInformation.aspx?DashboardId=0
Important Server variable values are:
HTTP_HOST: www.fakesite.com
PATH: /uv/EnviSetup/Wizard/GeneralInformation.aspx
QUERY_STRING: DashboardId=0
Also if you open IIS->Url Rewrite and go to your rule you will see there is a option to test rule, you can simply paste your url and have an overview how URL is parsed. You will then also realize which part you can use to append query string.
http://www.iis.net/learn/extensions/url-rewrite-module/testing-rewrite-rule-patterns

IIS7 URL Rewriting: How not to drop HTTPS protocol from rewritten URL?

I'm working on a website that uses IIS 7's URL rewriting feature to do a permanent redirect from example.com to www.example.com, as well as rewrites from similar domain names to the "main" one, such as from www.examples.com to www.example.com.
This rewrite rule - shown below - has worked well for some time now. However, we recently added HTTPS support and noticed that if users visit one of the URLs to be rewritten to www.example.com then HTTPS is dropped. For instance, if a user visits https://example.com they get redirected to http://www.example.com, whereas we would like them to be sent to https://www.example.com.
Here is the rewrite rule of interest (in Web.config):
<rule name="Canonical Host Name" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^example\.com$" />
<add input="{HTTP_HOST}" pattern="^(www\.)?example\.net$" />
<add input="{HTTP_HOST}" pattern="^(www\.)?example\.info$" />
<add input="{HTTP_HOST}" pattern="^(www\.)?examples\.com$" />
</conditions>
<action type="Redirect" url="http://www.example.com/{R:1}" redirectType="Permanent" />
</rule>
As you can see, the action element's url attribute points directly to http://, so I get why https://example.com is redirected to http://www.example.com. My question is, how do I fix this? I tried (naively) to just drop the http:// part from the url attribute, but that didn't work.
Here's Scott's answer with Hasan's improvements. This should cover mixed SSL/non-SSL sites. The rule basically says "if the url does not have www.example.com", do a permanent redirect to it. Essentially... you are redirecting people who visit you without www or directly to your IP address.
<rewrite>
<rules>
<rule name="Canonical Host Name" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^www\.example\.com$" negate="true" />
</conditions>
<action type="Redirect" url="{MapSSL:{HTTPS}}www.example.com/{R:1}" redirectType="Permanent" />
</rule>
</rules>
<rewriteMaps>
<rewriteMap name="MapSSL" defaultValue="http://">
<add key="ON" value="https://" />
<add key="OFF" value="http://" />
</rewriteMap>
</rewriteMaps>
</rewrite>
Figured out the answer with some help from my colleagues.
I needed to use multiple rules with a condition on {HTTPS}. Note the {HTTPS} condition in the rules below.
<rule name="Canonical Host Name (HTTP)" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTPS}" pattern="OFF" />
<add input="{HTTP_HOST}" pattern="^example\.com$" />
</conditions>
<action type="Redirect" url="http://www.example.com/{R:1}" redirectType="Permanent" />
</rule>
<rule name="Canonical Host Name (HTTPS)" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTPS}" pattern="ON" />
<add input="{HTTP_HOST}" pattern="^example\.com$" />
</conditions>
<action type="Redirect" url="https://www.example.com/{R:1}" redirectType="Permanent" />
</rule>
I then repeated the rule pair above for the alternate domain names.
If you just want to redirect based on the currently used protocol (as per your last sample) then there's a much simpler solution that will halve the amount of rules you will need. The following is what I've learned from a collegue of mine.
As you've seen, the {HTTPS} argument will contain the value ON or OFF. You can map this value to https:// or http:// by feeding this value into a rewritemap.
Here's how this would work:
1- Create a rewritemap section for mapping the {HTTPS} value:
<rewriteMap name="MapProtocol" defaultValue="OFF">
<add key="ON" value="https://" />
<add key="OFF" value="http://" />
</rewriteMap>
It's up to you to decide if you want to only include the protocol, or the semicolon and forward slashes as well. It doesn't matter for the solution, but keep it in mind wherever you refer to it.
2- Refer to this map wherever you need. In this sample it's used in outbound-rules, but it'll also work in your scenario:
<rule name="Outbound-Rule Name" stopProcessing="true" preCondition="ResponseIsHtml">
<match filterByTags="A, Link, Script" pattern="YOUR PATTERN" />
<action type="Rewrite" value="{MapProtocol:{HTTPS}}{HTTP_HOST}/REST OF RELATIVE LINK HERE" />
</rule>
That's it, the URL Rewrite module should now automagically use the correct protocol for your links depending on if you're using https, or, of course, http.
Hope this helps!
Here's a cross-domain solution which works not only on example.com but also on any domain
<rewrite>
<rules>
<rule name="Canonical Host Name" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^www\.([.a-zA-Z0-9]+)$" negate="true" />
</conditions>
<action type="Redirect" url="{MapProtocol:{HTTPS}}www.{HTTP_HOST}/{R:0}" redirectType="Permanent" />
</rule>
</rules>
<rewriteMaps>
<rewriteMap name="MapProtocol" defaultValue="OFF">
<add key="ON" value="https://" />
<add key="OFF" value="http://" />
</rewriteMap>
</rewriteMaps>
</rewrite>

IIS7 URL Rewrite Mod causes unwanted effects

This might be more a a regex question, but it is holding up our release. I'm unable to come up with a clever solution.
Basically, we want to rewrite www.oursite.com/Games.aspx?g=classic&m=etc to www.oursite.com/classic/?m=etc
The problem is that the rule itself (at least as generated by the URL Rewrite mod for IIS7) looks like this:
<rewrite>
<rules>
<rule name="RedirectUserFriendlyURL1" stopProcessing="true">
<match url="^Games\.aspx$" />
<conditions>
<add input="{REQUEST_METHOD}" negate="true" pattern="^POST$" />
<add input="{QUERY_STRING}" pattern="^g=([^=&]+)$" />
</conditions>
<action type="Redirect" url="{C:1}" appendQueryString="false" redirectType="Permanent" />
</rule>
<rule name="RewriteUserFriendlyURL2" stopProcessing="true">
<match url="([^/]+)/?$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="Games.aspx?g={R:1}" />
</rule>
</rules>
</rewrite>
And thus, any other file that matches a similar pattern, for example Item/?id=23 is being rewritten. In addition, our script resource file is being rewritten, so the whole site throws 30 javascript errors. According to our specs, it's unacceptable in our specs to have the url www.oursite.com/Games/classic OR www.oursite.com/g/classic. Any solution? Manythanks!
Perhaps instead of matching ([^/]+)/?$ in your second rule, you'd be better of explicitly stating which things you want to rewrite, in a regex OR statement:
(classic|somethingelse|athirdsomething)/?$
That way only the items you explicitly want to rewrite will be modified. I don't know how many of these you're potentially needed to rewrite, so if it's a large number, this might not be viable, but if it's only a few categories, then it's probably the most straightforward.
Alternatively, if there are only certain prefixes that shouldn't be rewritten, you could simply add negated conditions that pattern match those prefixes to your rewrite.

Resources