Rule not working in rewrite rules despite valid regex - regex

Our webconfig file uses Url Rewrite, essentially pushing any http traffic to https
This works fine other than developing locally. For a while we have to simply remember to comment out the code from the web.config and uncomment it again for commit. Naturally this isn't a good way to work.
The code is simple
<rewrite>
<rules>
<rule name="Redirect-AllWWW-ToSecureNonWWW">
<match url="^((?!local).)*$" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(?:www\.)(.+)$" />
</conditions>
<action type="Redirect" url="https://{C:1}/{R:0}"/>
</rule>
<rule name="Redirect-AllNonSecure-ToSecureNonWWW-ExcludingLocalhost">
<match url="^((?!local).)*$" />
<conditions>
<add input="{HTTP_HOST}" pattern="^localhost$" negate="true" />
<add input="{HTTPS}" pattern="^off$" />
<add input="{HTTP_HOST}" pattern="^(?:www\.)?(.+)" />
</conditions>
<action type="Redirect" url="https://{C:1}/{R:0}" />
</rule>
</rules>
</rewrite>
And as per the regex101 , it works!
https://regex101.com/r/3Mz6w1/1
However, when on localhost, I am still directed to HTTPS
Why does it work in regex101 and not in my web.config file

This seems to be related to Redirect rule not working
quote from URL Rewrite Module Configuration Reference
A rewrite rule pattern is used to specify a pattern to which the current URL path is compared.
...
A pattern is specified within a <match> element of a rewrite rule.
According to this piece of official information, you must be sure that <match url compares only with URL paths which never contain host names, not the entire URL.
For Url Rewrite Module, URL path of this question is questions/44944175/rule-not-working-in-rewrite-rules-despite-valid-regex for example. No stackoverflow.com no https:// no query strings but only the path without leading slash.
To ignore requests for host names containing local you need some conditions looking for a local match with HTTP_HOST header.
<rewrite>
<rules>
<rule name="Redirect-AllWWW-ToSecureNonWWW" stopProcessing="true">
<match url=".*" />
<conditions>
<!-- continue if http host name does not contain "local" -->
<add input="{HTTP_HOST}" pattern="local" negate="true" />
<add input="{HTTP_HOST}" pattern="^(?:www\.)(.+)$" />
</conditions>
<action type="Redirect" url="https://{C:1}/{R:0}" />
</rule>
<rule name="Redirect-AllNonSecure-ToSecureNonWWW-ExcludingLocalhost" stopProcessing="true">
<match url=".*" />
<conditions>
<!-- continue if http host name does not contain "local" -->
<add input="{HTTP_HOST}" pattern="local" negate="true" />
<add input="{HTTPS}" pattern="^off$" />
<add input="{HTTP_HOST}" pattern="^(?:www\.)?(.+)" />
</conditions>
<action type="Redirect" url="https://{C:1}/{R:0}" />
</rule>
</rules>
</rewrite>

Related

IIS rewrite rule not working in live environment

I have 4 servers in azure, 3 are load balanced and the 4th is for CMS purposes only.
SSL certificate has been added for the main website, but not for the sobdomain that the CMS is on.
I wrote a rule that should find any url that doesnt contain "backoffice" and match any other page to change it to https.
This works on regexr.com but for some reason doesnt work
<rewrite>
<rules>
<rule name="http to https" stopProcessing="true">
<match url="(https?:\/\/(?!backoffice).*)" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://www.WEBSITENAME.com{R:1}" />
</rule>
</rules>
</rewrite>
Url Rewriting 2.1 is installed on all 4 servers and i have created a load balance set in azure for https.
going to https manually works fine (along with loadbalancing).
Additional information:
I've tried many rules, including the existing answer. I can see things happening, like assets being brought in as https, but the page itself does not redirect.
There are 2 load balance sets, one for port 80 and the other for port 443. I don't know if this is corect, or could be a potential cause in the redirect not happening.
Your rule should be like that:
<rule name="http to https" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
<add input="{REQUEST_URI}" pattern="/backoffice" negate="true" />
</conditions>
<action type="Redirect" url="https://www.WEBSITENAME.com{R:0}" />
</rule>
This rule will exclude requests with /backoffice path.
Also for issue of mixing content you need to fix your paths for css/js/images to relatives. Example:
<img src="/path/to/your/image.jpg"/>
Another way to fix mixed content is create outbound rule, which will change your output HTML (replace http: to https:):
<rewrite>
...
<outboundRules>
<rule name="Rewrite external references to use HTTPS" preCondition="IsHTML">
<match filterByTags="Script, Link, Img, CustomTags" customTags="HTML5Tags" pattern="^http://(.*)$" />
<action type="Rewrite" value="https://{R:1}" />
</rule>
<preConditions>
<preCondition name="IsHTML">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
<customTags>
<tags name="HTML5Tags">
<tag name="Video" attribute="src" />
</tags>
</customTags>
</outboundRules>
</rewrite>
Using the previous answer as a starting point, i made a few minor changes, to use HTTP_HOST rather than REQUEST_URI for the pattern negation and it works.
<system.webServer>
<rewrite xdt:Transform="InsertIfMissing">
<rules>
<rule name="http to https" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
<add input="{HTTP_HOST}" pattern="^backoffice\.WEBSITENAME\.com$" negate="true" />
</conditions>
<action type="Redirect" url="https://www.WEBSITENAME.com/{R:0}" />
</rule>
</rules>
</rewrite>
</system.webServer>

IIS redirect with regex [duplicate]

Whenever someone makes request over HTTP protocol I rewrite the url to make it HTTPS. This is the code in web.config:
<rule name="Imported Rule 1-1" enabled="true" stopProcessing="true">
<match url="^(?!https://).*" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{SERVER_PORT}" pattern="80" ignoreCase="false" />
</conditions>
<action type="Rewrite" url="https://abc.com/{R:1}" />
</rule>
However when I browse on http:// I get IIS error
HTTP Error 500.50 - URL Rewrite Module Error. The expression "https://abc.com/{R:1}" cannot be expanded.
How can I resolve this? I am utterly confused.
The matches are zero based.
<action type="Rewrite" url="https://abc.com/{R:1}" />
Won't work because you only have one match. You need:
<action type="Rewrite" url="https://abc.com/{R:0}" />
Also, this won't work, because you can only match on the path below the site root.
<match url="^(?!https://).*" ignoreCase="false" />
It looks like you are checking for ssl. Try this instead:
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
You can redirect through web config to
Hope it will help full
<rule name="Redirect to WWW" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^abc.com$" />
</conditions>
<action type="Redirect" url="http://www.abc.com/{R:0}" redirectType="Permanent" />
</rule>

Reduce Chained URL Redirects [IIS/Regex/ReWrite]

I have implemented some URL Redirects combined on IIS/ColdFusion is working fine but I am not able to deal with some regex pattern to reduce unneeded redirects.
Currently IIS is only handling a single redirect (at most) only if it finds a template name within the URL. e.g. IIS redirects a URL such as
http://example.com/index.cfm/something/pretty/?page=1
to
http://example.com/something/pretty/?page=1
For instance, it just removes the template name from the URL leaving everything intact following it. The final URL above is a valid one according to my application.
But in addition, if a trailing slash (/) is not found in the final URL, ColduFusion application is handling this case and appends a forward slash at the end, then redirects to a URL that ends with a forward slash (/) before a query string (if there is). It works with some logic to maintain PATH_INFO and QUERY_STRING intact. But that is actually causing multiple redirects in the following situation.
[INIT] http://example.com/index.cfm/sport/badminton
[Redirect 1] [IIS-301] http://example.com/sport/badminton
[Redirect 2] [CF-301] http://example.com/sport/badminton/
Now that I want to handle all of this in IIS and cover all cases in one Rule, I am not able to make (or find) a regex pattern that could do it.
Current IIS redirect pattern
^index.cfm/(.*)$
I have tried various ones along with the most simple
^index.cfm/(.*[^/])$
But it doesn't cover a URL with a QUERY_STRING. You can take me as real naive in making regular expressions.
Update 1: I found that the proper term for the issue is "Chained" redirects and found an article at moz.com which is kind of handling the same issue I've referred above. I guess it should work, and while I am on it changing the rules as required on my server, I thought I should update this question with something I have found for others who may have such an issue. I'll update this as soon as I could use this solution to fix the issue at my side.
Sorry that I couldn't have an answer over here but as I updated above question about an article at moz.com, I have implemented that approach and successfully recovered from the Chained/Multiple redirects.
Previously our web application was supporting the following URL
https://www.example.com/index.cfm/something/pretty/
Than we used URL ReWriting in IIS and removed index.cfm from the URL. But we had trouble that there were multiple/chained redirections to redirect from non-https, non-www, or no trailing slash, etc.
https://moz.com/blog/what-every-seo-should-know-about-iis#chaining
After reading the article above, I've implemented following set of rules on IIS that now takes care of all the cases we had previously handled on IIS and on ColdFusion separately.
<rules>
<!-- rewrite url to furnish with prefix(_) to better match individual parts -->
<rule name="Remove index.cfm" stopProcessing="false">
<match url="(.*?)/?index\.cfm/(.*)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_METHOD}" pattern="GET" />
</conditions>
<action type="Rewrite" url="_{R:2}" />
</rule>
<rule name="Add Trailing Slash" stopProcessing="false">
<match url="(.*[^/])$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="_{R:1}/" />
</rule>
<rule name="ToLower Everything in URL" enabled="true" stopProcessing="false">
<match url="(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_METHOD}" pattern="GET" />
<add input="{R:1}" pattern="[A-Z]" ignoreCase="false" />
</conditions>
<action type="Rewrite" url="_{ToLower:{R:1}}" />
</rule>
<!-- Now redirect the final prefix-furnished URL -->
<!-- match if there is at least one (_) at the start of the furnished URL. Redirect to the final URL -->
<rule name="http[non www] to https[www] redirect" stopProcessing="true">
<match url="^(_*)(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^www\.yoursite\.com$" negate="true" />
<add input="{HTTP_METHOD}" pattern="GET" />
<add input="{SERVER_PORT}" pattern="80" />
</conditions>
<action type="Redirect" url="https://www.example.org/{R:2}" />
</rule>
<rule name="http[www] to https[www] redirect" stopProcessing="true">
<match url="^(_*)(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_METHOD}" pattern="GET" />
<add input="{SERVER_PORT}" pattern="80" />
</conditions>
<action type="Redirect" url="https://www.example.org/{R:2}" />
</rule>
<rule name="https[non www] to https[www] redirect" stopProcessing="true">
<match url="^(_*)(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^www\.yoursite\.com$" negate="true" />
<add input="{HTTP_METHOD}" pattern="GET" />
<add input="{SERVER_PORT}" pattern="443" />
</conditions>
<action type="Redirect" url="https://www.example.org/{R:2}" />
</rule>
<!-- this rule is supposed to run final redirect if non above redirect rules occured -->
<rule name="http// redirect" enabled="true" stopProcessing="true">
<match url="^(_+)(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_METHOD}" pattern="GET" />
</conditions>
<action type="Redirect" url="{R:2}" />
</rule>
<!-- now after failing/running all rules above when the IIS reaches at this point, it's the fully validated/funrished URL that qualifies to serve with response. Rewrite the URL to run index.cfm as a template -->
<rule name="URL ReWrite" enabled="true" stopProcessing="true">
<match url="^(.*)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" pattern="/admin" negate="true" />
</conditions>
<action type="Rewrite" url="index.cfm/{R:1}" />
</rule>
These rules are strictly according to our requirement where we wanted all requests to be routed to [https], you must check the moz.com article above for reference.
Hope this could help others.

Web.config rewrite module

I am trying to figure out how to add a rule to my web.config so it detects any link that has anything in the url beyond the .com portion - and then does not process the next input condition which detects if the device is mobile and then redirects to m.mysite.com.
For example here are some example cases I would want it to skip over the mobile redirect:
If a incoming link is www.mysite.com/coupon/etc
If a incoming link is www.mysite.com?c=1
I do want it to redirect to the mobile site in all cases where its just the base domain of www.mysite.com or mysite.com.
Here is my current web.config rewrite section.
<rewrite>
<rules>
<rule name="MobileRedirect" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*" ignoreCase="true"/>
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_COOKIE}" pattern="persistdesktop=1" ignoreCase="true" negate="true"/>
<add input="{HTTP_USER_AGENT}" pattern="android|blackberry|googlebot-mobile|iemobile|iphone|ipod|opera mobile|palmos|webos"/>
</conditions>
<action type="Redirect" url="http://m.mysite.com" appendQueryString="false" redirectType="Found"/>
</rule>
</rules>
So my best guess is that I need to add another condition above the other two. And then do I change the conditions logicalGrouping parameter to MatchAny? Or do I create another rule above this existing rule?
Thanks!
You haven't set the ignoreCase attribute value to true for HTTP_USER_AGENT. The match URL pattern and the Query string pattern need some changes.
Change the rewrite configuration to:
<rewrite>
<rules>
<rule name="MobileRedirect" stopProcessing="true">
<match url="^$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_COOKIE}" pattern="persistdesktop=1" negate="true" />
<add input="{HTTP_USER_AGENT}" pattern="android|blackberry|googlebot-mobile|iemobile|iphone|ipod|opera" ignoreCase="true"/>
<add input="{QUERY_STRING}" pattern="^$"/>
</conditions>
<action type="Redirect" url="http://m.mysite.com" redirectType="Found" />
</rule>
</rules>
</rewrite>

Rewrite rule to HTTPS except when on localhost

I am using the answer given here as the basis for trying to add a rewrite rule to my web.config file. I want it to match any url that is not running on localhost in order to force https.
Here is what I have right now:
<system.webServer>
<rewrite> <!-- force https - https://stackoverflow.com/a/15119044/51 -->
<rules>
<rule name="Redirect HTTP to HTTPS" stopProcessing="true">
<match url="^((?!localhost).)*$"/>
<conditions>
<add input="{HTTPS}" pattern="^OFF$"/>
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther"/>
</rule>
</rules>
</rewrite>
</system.webServer>
I am trying to use a negative lookaround in order to only match url's that do not include "localhost" within the url. But this is not working.
So how should this rule be set up in order to only rewrite non-localhost url's?
Try this condition:
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect HTTP to HTTPS" stopProcessing="true">
<match url="^(.*)$"/>
<conditions>
<add input="{HTTPS}" pattern="^OFF$"/>
<add input="{HTTP_HOST}" matchType="Pattern" pattern="^localhost$" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther"/>
</rule>
</rules>
</rewrite>
</system.webServer>
Using a negate condition against the localhost pattern should do the trick.
Adding to anubhava's answer, you can replace the add element for localhost with the following 2 entries to cater for both localhost and 127.0.0.1 with optional ports e.g localhost:59400 which is the case when debugging through visual studio and IIS
<add input="{HTTP_HOST}" matchType="Pattern" pattern="^localhost(:\d+)?$" negate="true" />
<add input="{HTTP_HOST}" matchType="Pattern" pattern="^127\.0\.0\.1(:\d+)?$" negate="true" />
With the original answer, localhost:123 would be redirected to https which may not be desirable.
Regular expression updated, this works for me, with a custom Port
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
<add input="{HTTP_HOST}" matchType="Pattern" pattern="(localhost)(:\d+)" negate="true" />
<add input="{HTTP_HOST}" matchType="Pattern" pattern="(127.0.0.1)(:\d+)" negate="true" />