Removing trailing slash at the end of file names in a folder - trailing-slash

Removing trailing slash at the end of file names in a folder
http://www.example.com/directory/index.php/ should return to http://www.example.com/directory/index.php (that is without trailing slash at the end - it can be any file type like html, php, asp )
I tried with RewriteRule ^(.*)/$ $1 [R=301,L] , but when some one type the url with slash at the end it redirects to http://www.example.com/file which should be returned as http://www.example.com/directory/index.php
Help Appreciated.

Try using this in your "web.config".
It should be a "redirect" action not a "rewrite" as follows (It worked well for me):
<rule name="Remove trailing slash" stopProcessing="true">
<match url="(.*)/$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}" />
</rule>
Hope this help you too.

Related

Replace specific query string value with IIS redirect maps

I'm trying to create a redirect rule for a .NET Core project that would replace a query string value so to help deploy a migration on some identifiers. For example the URL:
http://www.somesite.com/page.html?somevar=abc&id=1234&othervar=cde
should redirect to
http://www.somesite.com/page.html?somevar=abc&id=b64540a6-b12d-443f-973f-673e4451ccbe&othervar=cde
On the rewrite file I've created a rewrite map as such:
<rewriteMaps>
<rewriteMap name="newIdentifierMap">
<add key="1234" value="b64540a6-b12d-443f-973f-673e4451ccbe" />
</rewriteMap>
</rewriteMaps>
But now I'm having some trouble creating the rule to use this map. This is what I was doing...
<rule>
<match url=".*" />
<conditions>
<add input="{newIdentifierMap:REQUEST_URI}" pattern="(.*)id=([0-9]+)(.*)" />
</conditions>
<action type="Redirect" url="" RedirectType="Permanent" />
</rule>
Now I'm block without knowing how exactly to replace the values in the map.
Thanks for any help!
Solution
After checking the answer provided by #abraham-qian I was able to solve the issue by applying the following rules:
<rule>
<match url="(.*)" />
<conditions>
<add input="{QUERY_STRING}" pattern="(.*)(\bid=([0-9]+))(.*)" />
</conditions>
<action type="Redirect" url="{R:0}?{C:1}id={newIdentifierMap:{C:3}}{C:4}" RedirectType="Permanent" appendQueryString="false" />
</rule>
<rewriteMaps>
<rewriteMap name="newIdentifierMap">
<add key="1234" value="b64540a6-b12d-443f-973f-673e4451ccbe" />
</rewriteMap>
</rewriteMaps>
This seems to be working fine with any number of variables before or after the id variable in the querystring.
In order to match the ID segment, we could use {Query_String} server variable.
Please refer to below code snippets,
<rewrite>
<rules>
<rule name="MyRules" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{QUERY_STRING}" pattern="(.*)(\bid=([0-9]+))(.*)" />
</conditions>
<!--{C:3} is the value of id, it is referred by the above condition.-->
<action type="Redirect" url="Https://vabqia969vm:448/{MyMap:{C:3}}" appendQueryString="false" />
</rule>
</rules>
<rewriteMaps>
<rewriteMap name="MyMapName" defaultValue="">
<add key="1234" value="HtmlPage1.html"></add>
</rewriteMap>
</rewriteMaps>
</rewrite>
However, there is an issue that we should uncheck the option Append Query String, or will cause an endless loop since the appended query string meets the condition. We have to match each query field one by one. Like this,
(somevar=.*)&(\bid=([0-9]+))&(othervar=.*)
We had better modify the rules according to your situation.
Feel free to let me know if there is anything I can help with.

IIS Url Rewrite Rules - www/SSL - web.config

I am trying to write some rewrite rules in the <system.webServer> section of the web.config file.
My aim is that any url missing the www section would be rewritten as www.myurl.com. I believe that this should actually be a 301 redirect? To add to this, I also want to make sure that I am using SSL with HSTS.
I need to make sure that I don't fix this rule to a single domain, for example, it needs to work for foo.com and bar.com along with any others that I might choose to support in the future (there could be quite a few when I start looking at country specific domains).
Here is what I have so far:
<system.webServer>
<rewrite>
<rules>
<rule name="HTTP to HTTPS redirect" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
<rule name="Non WWW redirect" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(www|office365|bdf01)\." negate="true" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://www.{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
</rules>
<outboundRules>
<rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
<match serverVariable="RESPONSE_Strict_Transport_Security" pattern=".*" />
<conditions>
<add input="{HTTPS}" pattern="on" ignoreCase="true" />
</conditions>
<action type="Rewrite" value="max-age=31536000" />
</rule>
</outboundRules>
</rewrite>
</system.webServer>
The above has 3 rules:
- HTTP to HTTPS
- Non-WWW to WWW
- HSTS
It looks as though my HTTP-HTTPS rule is working fine, but that is the only one.
The non-www redirect needs to be able to allow specific sub-domains. THe example above should not add the www. to the url's of office365.foo.com or bdf01.foo.com This part doesn't work - See example 1.
I'm not certain how best to test HSTS, but I am using a website called woorank to review the website and it says that HSTS is not enabled. Not sure if this is working, but appears not
I'm not really sure how the pattern matching works within these rules, so would be more than happy for links to resources that can help me understand this part better. Any help would be gratefully appreciated
Example 1
When I go to the home page of http://foo.com, I should be taken to https://www.foo.com, instead I am taken to https://foo.com. Likewise, If I navigate to http://office365.foo.com I should actually get https://office365.foo.com but I still get the same http:// address.

IIS URL Rewrite

I have the following rewrite rule:
<rewrite>
<rules>
<rule name="FrontController" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="wcf/api.svc/auth/home" />
</rule>
</rules>
</rewrite>
This basically rewrites all non-file urls to web service api calls that returns index.html in an SPA backed by WCF.
The above rewrite ends up including all the query string parameters that were included with the original URL. What I need to do is also include the original URL, such as, 'wcf/api.svc/auth/products', as a query string parameter in the rewritten URL, such as 'https://domain.com/wcf/api.svc/auth/products?enc=lkjewro8xlkz' being transformed into 'https://domain.com/wcf/api.svc/auth/home?enc=lkjewro8xlkz&orig=wcf/api.svc/auth/products'.
Is this possible, and if so, what changes would I need to make to achieve it? I would like for my WCF application to know about the original URL so that it can configure the SPA to initialize to a particular view on load.
Thanks
It's quite possible.
You need to add the URL Encoded value of the {REQUEST_URI} to the Rewrite URL.
<rewrite>
<rules>
<rule name="FrontController" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="wcf/api.svc/auth/home?orig={UrlEncode:{REQUEST_URI}}" />
</rule>
</rules>
</rewrite>
With this rule, in your WCF endpoint orig parameter would be:
/wcf/api.svc/auth/products?enc=lkjewro8xlkz
If you don't want the query string part (?enc=lkjewro8xlkz), you'll need an extra condition to match the URI without query string.
<rewrite>
<rules>
<rule name="FrontController" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<!-- match any character up to a question mark -->
<add input="{REQUEST_URI}" pattern="^[^\?]+" />
</conditions>
<!-- {C:0} means the first match in conditions -->
<action type="Rewrite" url="wcf/api.svc/auth/home?orig={UrlEncode:{C:0}}" />
</rule>
</rules>
</rewrite>
Now, orig will be /wcf/api.svc/auth/products in the WCF endpoint.
Hope it helps.

Asp.net MVC4 Bundles being broken by URL Rewrite rule for trailing slash

I'm hosting my mvc4 application in a virtual path under an existing site:
ie: http://www.mysite.com/myApp
There is a well-known problem with relative paths being broken if the trailing slash is not provided in the URL.
So if the user types the URL as I did above, scripts, styles etc that are using a relative path are not going to be found.
If a trailing slash is provided, everything is ok.
To resolve this problem I installed URL Rewrite (http://www.iis.net/downloads/microsoft/url-rewrite) and added the rule to append the trailing slash if not present. This is a pre-defined rule that looks like:
<rewrite>
<rules>
<rule name="AddTrailingSlashRule1" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}/" />
</rule>
</rules>
So far so good, the only problem is that this is now breaking the bundles by adding a trailing slash between the bundle name/url and the chache busting:
ie:
http://www.mysite.com/myApp/bundles/myBundle/?v=8_EQPT2vzBgg4HcGhkeTQpLE1flm2VOsp3A1ZEy-C3k1
(Note the / between myBundle and ?v=8....)
I have tried excluding "bundles" from the conditions, but I had no luck.
I would like to know how I can either exclude certain paths from the conditions (not all my bundles are using "bundles" on the path) or maybe a simpler rule that allow me to add the trailing slash for the only case I need to care about: when the user forgets to type it at the end of my app url.
Thanks,
R.
UPDATE
I just added a permanent redirection condition to my main controller -the one that is more susceptible to be typed by the user directly on the address bar. This is resolving my issue.
I'm letting the question open just in case someone came up with a better idea by either tweaking the route engine or using a URL Rewrite.
This is the code:
public ActionResult Index()
{
if (!Request.Path.EndsWith("/"))
return RedirectPermanent(Request.Url.ToString() + "/");
return View();
}
Here's how to add an exclusion of a folder:
<rule name="AddTrailingSlashRule1" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{URL}" pattern="myBundle$" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}/" redirectType="Found" />
</rule>
Simply add new {URL} lines for your exclusions. This example 'ends with' myBundle, but you could use the following instead:
<add input="{URL}" pattern="/bundles/" negate="true" />
That will perform a contains search instead since it doesn't check for a start (^) or end ($).
And if you want to reverse the logic to only include certain paths then remove the negate="true" on the {URL} line, and set the pattern to what you want to include.
If you want to prevent this rule from happening when a query string is submitted you can use a condition as follow:
<rule name="Add Trailing Slash" stopProcessing="true">
<match url="^(.*)/$" negate="true" />
<action type="Redirect" url="{R:0}/" />
<conditions>
<add input="{QUERY_STRING}" pattern="(.+)" negate="true" />
</conditions>
</rule>
The condition will make sure this rule is not executed (negate="true") when (.+) (at least on character) is true against the query string.
I also changed the match to use a negate form that seems more clear and appropriate to me, but if your rule works for you, keep it the way it is!
This sounds like one of the symptoms that installing this fix is supposed to fix.
http://support.microsoft.com/kb/2520479

URL Rewrite rule - subfolder to query string value

I'm trying to create a rule the will take the subfolder from the URL and convert that to a query string value for example:
If I navigated to this URL: http://www.example.com/myfolder
I would like that to read http://www.example.com/default.aspx?folder=myfolder
This is where I'm up to:
<rule name="Rewrite Language">
<match url="([a-z]{2})(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/default.aspx?code={R:2}" />
</rule>
but this doesn't return the full subfolder value. I'll be honest I've stole this from a similar issue from this site, and I must confess I really have no idea what it all means!
I might be approaching this in the wrong way, my issue is that I can't be sure what the subfolder will be as this is generated dynamically from a random 6 character alphanumeric value.
Any help would be very much appreciated.
David
The IIS Manager has a GUI / wizard interface for creating the rules which I usually find quicker and easier than entering the rule into the web.config file manually. Worth checking out: IIS Manager -> select your site / application -> URL Rewrite -> Add Rule(s).
I think the following rule will do the trick for you:
<rule name="RewriteUserFriendlyURL1" 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="default.aspx?folder={R:1}" />
</rule>
Basically, the "match url" is a regular expression that is used to identify a part of the URL. In this case, it captures a group containing one or more characters (except for a /), with an optional / at the end of the URL. It will then rewrite the url to default.aspx?folder= followed by the value that was matched ({R:1} refers to the first captured group, which will contain the folder name).
This will work provided you only have a single subfolder name (not nested folders).
You could also add a second rule which works in the opposite direction, so browsing to http://www.example.com/default.aspx?folder=myfolder would result in the user seeing http://www.example.com/myfolder:
<rule name="RedirectUserFriendlyURL1" stopProcessing="true">
<match url="^default\.aspx$" />
<conditions>
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern="^folder=([^=&]+)$" />
</conditions>
<action type="Redirect" url="{C:1}" appendQueryString="false" />
</rule>