"%" character causing issues in IIS URL rewrite regex - regex

I'm replatforming an online shop, and part of that process is writing 301 redirects for old links customers may have bookmarked to hit their new addresses. All of them work apart from the ones in which the old address contains the % character. It seems to somehow be interfering with the regex. The rule is:
<rule name="Custom 41 redirect" stopProcessing="true">
<match url="^c80/How-to-%20Use-Shop-Name\.aspx" ignoreCase="true" />
<action type="Redirect" url="/how-to-use-shop-name" redirectType="Permanent" />
</rule>
Testing using the built in regex tester in IIS tells me that hitting
/c80/How-to-%20Use-Shop-Name.aspx
Matches the pattern, yet the rule fails to redirect me when I hit that address.
I should also stress that there are about 400 rewrites in my web.config, but only the 3 which contain the % character break.

Since the string that is tested against the regex is already Url-decoded, you no longer need the %20 in your regex. Just use a plain space:
<match url="^c80/How-to- Use-Shop-Name\.aspx" ignoreCase="true" />
Also, in case the space is optional, you may use a ? after it:
<match url="^c80/How-to- ?Use-Shop-Name\.aspx" ignoreCase="true" />

Related

IIS: Rewrite URL with regex but keep query strings

I'm have the following link
https://example.com/myapp/green?&lang=en&instance=some%20instance
I need to rewrite it to the following link
https://example.com/myapp?color=green&lang=en&instance=some%20instance
The color in the link can be any color but it needs to be rewritten like in the 2nd link so that the trailing slash is replaced with a ? followed by the word color= and the ? at the end of the color word needs to be removed.
/myapp/green? becomes /myapp?color=green,
/myapp/blue? becomes /myapp?color=blue
and so forth, all while keeping the rest of the query string &lang=en&instance=some%20instance intact
I've tried regexing my way out of this but I usually catch everything or unintentionally omit the rest of the query string.
Any ideas on what's the best approach?
EDIT: noticed that IIS, when applying to application level (not website level), the input URL path is after '/myapp/' and I need that trailing slash removed. Does this mean I'll have to apply it to the website level?
You could use below url rewrite rule(add this rule at site level):
<rule name="color query" enabled="true" stopProcessing="true">
<match url="myapp/(.*)/$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="lang=(.*)&instance=(.*)" />
</conditions>
<action type="Redirect" url="http://www.sample1.com/myapp?color={R:1}&lang={C:1}&instance={C:2}" appendQueryString="false" />
</rule>
Note: you could not remove the myapp/ from URL it will be added automatically in URL.

Rewrite Map Rule to match any URL extension

I'm fairly new to rewrite maps, but we did get ours to work on a very basic level. After a website redesign, we set up an extensive rewrite map (thousands o rules) to point the old pages to the new ones. The trouble we're having is that we're having to add multiple values for the same page in order for the rewrite to work.
Example:
http://www.abc123.com/About --> http://www.abc123.com/about-us
http://www.abc123.com/About.aspx --> http://www.abc123.com/about-us
http://www.abc123.com/about/ --> http://www.abc123.com/about-us
http://www.abc123.com/about.aspx --> http://www.abc123.com/about-us
There should be a way to wildcard anything after the base URL in the regular expression - I'm expecting something like this: ^./[about]$ which would be great if ALL urls contained "about" but they don't.
Also note that we aren't redirecting by directory, but rather by file name. It's that our CMS is set up not to use the .aspx extension, so any extension will work.
What I want is to only have to have ONE rule for each URL that looks like:
"http://www.abc123.com/about" and it will point all of the above variations to the new URL regardless if it does not have an extension or if the extension is .html, .asp, .aspx, or .whatever
Is that beyond the capabilities of the rewrite rules or is there some basic regular expression I am missing?
Here is the rule we are using:
<rule name="Redirect Rule for Legacy Redirects" enabled="true" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{Redirects:{REQUEST_URI}}" pattern="(.+)" />
</conditions>
<action type="Redirect" url="{C:1}" appendQueryString="false" />
</rule>
Any insight would be much appreciated.
[Hh][Tt][Tt][Pp]://(([^/])/)[Aa][Bb][Oo][Uu][Tt].*
See https://regex101.com/r/rZhJyz/1, just append "about-us" to the Group #1 match.
Had to figure this out today. It can be done by using the <match url> regex to strip off the extension, and then using the matched portion from here as the input for the rewrite map lookup.
The rewrite map keys must NOT have a starting /.
The rule (and sample map) looks like this, example for stripping off .aspx extension (could be generalised):
<rewrite>
<rewriteMaps>
<rewriteMap name="Test">
<add key="test" value="http://www.google.com" />
<add key="test.aspx" value="http://www.google.com" />
</rewriteMap>
</rewriteMaps>
<rules>
<rule name="Rewrite Map Optional Aspx Extension" stopProcessing="true">
<match url="^(.*?)(\.aspx)?$" />
<conditions>
<add input="{Test:{R:1}}" pattern="(.+)" />
</conditions>
<action type="Redirect" url="{C:1}" appendQueryString="false" />
</rule>
</rules>
</rewrite>
The important changes from a standard rewrite map rule are:
Adding (\.aspx)? as an optional part of the match url, and have have added ? to .* to make the initial .* not greedy so it doesn't include the extension.
Changed {Test:{REQUEST_URI}} to {Test:{R:1}} so it uses the matched input from the match url (.*)
Take out leading / from rewrite map keys

Regex check if string only has numbers after last instance of character and before last instance of another

I'm trying to write a particular regex pattern for a rewrite rule in IIS and if it matches the pattern to stop processing any more rules.
The Url will look something like this:
somesite.com/somepath/34343.aspx
I need to see if I only have numbers in the section 34343 as I can have
somesite.com/somepath/something343.aspx
I have tried matching the pattern like so:
([0-9]*).aspx$
But this picks up the latter URL and stops processing the rules so later matches aren't run. I need them to run on the later rules and not stop processing.
So if anyone can help, I need some way to check if I only have numbers after the last trailing slash and before the last .(dot)
I have also tried this:
(.)/(.).(.*)
which seems to give me what I want, inasmuch as it gives me grouped matches:
Full Match- somesite.com/somepath/34343.aspx
Group 1- somesite.com/somepath
Group 2- 34343
Group 3- aspx
But I don't know how to use Group 2 to then check that text for only numbers?
Can anyone help please?
Thanks
EDIT
Thanks for the replies, but these two patterns aren't working for me. I plug them into the IIS Url rewrite tool and whilst the rather wonderful test pattern option tells me that they match, they rule just doesn't fire.
<rule name="Ignore id with aspx" enabled="true" stopProcessing="true">
<match url="^(.*\/\d+\..+)$" ignoreCase="true" />
<!--OR-->
<match url="^.*\/\d+\.[^.]+$" ignoreCase="true" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
</rule>
Or at least it doesn't stop processing anymore subsequent rules.
Coincidentally, the rule I said I was using ([0-9]*).aspx$ does fire and does stop processing the subsequent rules.
You can make the regex like this:
(.*\/)+(\d*\..+)
This will check if it contains only digits.
Thanks for the help, but I managed to figure out why it wasn't firing the rule and it appears to now be working.
I setup Failed Request Tracing Rules and noticed that the rule had removed the base url http://somesite.com/ from the check. So it was only looking for the last bit of the Url.
As the Url's in question were http://somesite.com/12345.apsx it was easy to then check for just numbers and .aspx in the request.
<rule name="Ignore id with aspx" enabled="true" stopProcessing="true">
<match url="^\d*\..+[aspx]" ignoreCase="true" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="None" />
</rule>

IIS: Removing Trailing Dots from URL

I want to remove trailing dots such as ... from all urls on IIS. I tried to use the following rule:
<rule name="RemoveTrailingDots" stopProcessing="true">
<match url="^([^.]*)\.+$" />
<action type="Redirect" redirectType="Permanent" url="{R:1}" />
</rule>
This works as expected on my local PC but not on my website.
For example I expected /fruits/apple... to be redirected to /fruits/apple but no redirect happens.
Thanks
Your problem is you're requiring that everything before the trailing dots be completely devoid of dots. You might try something like
<match url="^(.*[^.])\.+$" />
This will match any number of characters, followed by a single non-dot character (as part of the capture), followed by dots (which aren't captured).
That said, I don't understand why you even want this. URLs with trailing dots are not even remotely a common thing to have.

How to redirect subfolder to query in Mod Rewrite for IIS 7.0?

I'm using Mod Rewrite for IIS 7.0 from iis.net and want to redirect requests:
http://example.com/users/foo to http://example.com/User.aspx?name=foo
http://example.com/users/1 to http://example.com/User.aspx?id=1
I have created 2 rules:
<rule name="ID">
<match url="/users/([0-9])" />
<action type="Rewrite" url="/User.aspx?id={R:1}" />
</rule>
<rule name="Name">
<match url="/users/([a-z])" ignoreCase="true" />
<action type="Rewrite" url="/User.aspx?name={R:1}" />
</rule>
It passes a test into iis mmc test dialog, but doesn't in debug (URL like http://localhost:9080/example.com/users/1 or …/users/foo) and doesn't on real IIS!
What have I done wrong?
The obvious problem is that your current regexes only match one character in the user name or one number. You'll need to add a plus quantifier inside the parentheses in order to match multiple letters or numbers. See this page for more info about regex quantifiers. Note that you won't be matching plain URLs like "/users/" (no ID or name). Make sure this is what you intended.
The other problem you're running into is that IIS evaluates rewrite rules starting from the first character after the initial slash. So your rule to match /users/([0-9]) won't match anything because when the regex evaluation happens, the URL looks like users/foo not /users/foo. The solution is to use ^ (which is the regex character that means "start of string") at the start of the pattern instead of a slash. Like this:
<rule name="ID">
<match url="^users/([0-9]+)" />
<action type="Rewrite" url="/User.aspx?id={R:1}" />
</rule>
<rule name="Name">
<match url="^users/([a-z]+)" ignoreCase="true" />
<action type="Rewrite" url="/Users.aspx?name={R:1}" />
</rule>
Note that you're choosing Users.aspx for one of these URLs and User.aspx (no plural) for the other. Make sure this is what you intended.
BTW, the way I figured these things out was by using IIS Failed Request Tracing to troubleshoot rewrite rules. This made diagnosing this really easy. I was able to make a test request and look through the trace to find where each rewrite rule is being evaluated (it's in a section of the trace called "PATTERN_MATCH". For the particular PATTERN_MATCH for one of your rules, I saw this:
-PATTERN_MATCH
Pattern /users/([0-9]+?)
InputURL users/1
Negate false
Matched false
Note the lack of the beginning slash.
You should use <match url="/users/([0-9]+)" /> and <match url="/users/([a-z]+)" ignoreCase="true" />, respectively, to match the complete id/user and not just their first letter/digit. But I don't know why your regex would have failed on a single digit, so there must be another issue, too.
As for your second question, I'm not sure I understand completely. How can you tell the difference between a folder name and a user name? Will a folder always have a trailing slash?