Caveat: I have an MVC site as an area in a .Net WebForms site. I'm explaining that in advance in the case that it sheds light on my issue.
Now the issue I am having is that I am routing values that could contain special characters like an apostrophe (single quote). If i do not encode the value it routes properly however, my Kendo MVC Grid creates a invalid template when using the unencoded single quote as a filter.
http://{base}/{area}/{controller}/{view}?customerName=Justin's%20Instance - Throws Invalid Template Error
http://{base}/{area}/{controller}/{view}?customerName=Justin's%20Instance - No Error
So I thought the easiest solution was to properly encode my querystring parameter prior to passing it as a route value. That resulted in a double encoding situation. Then I found out about MvcHtmlString.Create which is specifically designed to tell the routing system not to re-encode the string value. However, it is still double encoding.
var customerNameEncoded = MvcHtmlString.Create(HttpUtility.HtmlEncode(model.Name));
var routeResult = RedirectToAction("ManageCustomer", new { customerName = customerNameEncoded });
return routeResult;
This is the Url that is created:
http://{base/{area}/{controller}/{view}?customerName=Justin%26%2339%3Bs%20Instance
As you can see the ' is being encoded again. This is throwing the following error.
> System.Web.HttpRequestValidationException A potentially dangerous
> Request.QueryString value was detected from the client
> (customerName="Justin's Instance").
The web.config for the MVC area has the following tag: validateRequest="false"
The web.config for the overall website has the following: httpRuntime requestValidationMode="2.0"
Any ideas as to why this string is being double encoded and how to stop it from doing so?
There are two different types of encoding mixed here.
One is the HTML encoding which creates those &39; escape sequences.
Second is URL encoding which makes the %20 escape sequences.
I don't know what Kendo MVC Grid is by I think I know what the result of your action should be. Try this code
public ActionResult Index()
{
var customerNameEncoded = "Justin's Instance";
var url = Url.Action("ManageCustomer", new { customerName = customerNameEncoded });
return Redirect(url);
}
public ActionResult ManageCustomer(string customerName)
{
ViewBag.CustomerName = customerName;
return View();
}
If you stop the Index method just before it returns you'll see that url content is
"/Home/ManageCustomer?customerName=Justin%27s%20Instance"
what is the properly encoded URL.
You can also check what you get as customerName in ManageCustomer action and you'll see it's
"Justin's Instance"
Don't get confused by what you may see in the browser's address bar. Some browsers (like Firefox) do not show the encoded URL and may show something like ".../ManageCustomer?customerName=Justin's Instance"
1) Query string parameters are URL-encoded, not HTML-encoded. (% notation, rather than &# entities)
2) The config settings validateRequest and requestValidationMode apply to ASP.Net WebForms, not MVC. You must add the [ValidateInput(false)] attribute to the controller methods, as Bryan commented.
Related
In my ASP.NET MVC 4 application I have an action on controller that gets URL string as a parameter:
public ActionResult Get(string url)
{
var hash = TextUtil.GenerateShortStringHash(url);
...
return Content(html, "text/html");
}
The request looks like this: http://localhost:37779/api/get/http:%2F%2Fwww.mysite.com
But on some level application automatically replaces double slashes with single one.
Where does this happen? Is there any way to prevent such behavior? Thanks.
My suspicion is that because it's part of the hierarchical portion of the URL it's automatically converting the double slashes to a single slash because double slashes aren't allowed in that portion of the URL. Because URLs contain characters that aren't allowed in the hierarchical portion of the URL, it's best to specify it (suitably encoded) as part of the query string (if a GET request) or in the form parameters (for a POST).
http://localhost:37779/api/get/?url=http:%2F%2Fwww.mysite.com
I completely agree with #tvanfosson that such special characters should be passed as a query string parameter instead of using the path portion of the url. Scott Hanselman wrote a nice blog post explaining the challenges you will face if you attempt to pass such characters.
This being said, you could make it work using double encoding:
http://localhost:37779/api/get/http%253A%252F%252Fwww.mysite.com
and in your controller action:
public ActionResult Get(string url)
{
var hash = TextUtil.GenerateShortStringHash(HttpUtility.UrlDecode(url));
...
return Content(html, "text/html");
}
In order for this to work you need to add the following to your web.config to enable double encoding:
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true"/>
</security>
</system.webServer>
and also explicitly define the invalid characters so that : and / are not part of them or you will get 400 Bad Request:
<system.web>
<httpRuntime requestPathInvalidCharacters="<,>" />
</system.web>
On ASP.NET MVC 5.1 I have an action which receives an encrypted string, for example:
Nf7JnWp/QXfA9MNd52RxKpWg=
But I get a 404 error because of the slash inside this string ...
I tried to encode the string with HttpUtility.UrlEncode and WebUtility.UrlEncode;
But I keep having the same problems. Does anyone knows how to solve this?
Thank You,
Miguel
You can build a workaround for this by defining a custom route. Now I do not know how you named your controller or your action, so I'll use generic names.
routes.MapRoute(
"SpecialControllerName",
"CustomName/{*id}",
new { controller = "CustomName", action = "CustomAction", id = UrlParameter.Optional }
);
public ActionResult Name(string id)
{
//logic goes here
}
So what we did here, is take the action out of the equation. Now if you call http://yourdomain.com/CustomName/Nf7JnWp/QXfA9MNd52RxKpWg= it will call the Action method CustomName in the Controller CustomNameController.
Please note, that the asp.net Framework takes the first route in your route config, which matches its patterns. If you have your Defaultroute and place your new custom route below it, it will fail. Placing the Custom route above it, will work
Similar questions on SO:
ActionLink contains slash ('/') and breaks link
URLs with slash in parameter?
I need to change the URL on my address bar.
I looked for URL Rewrite but as far as I've seen it works for a request like this:
url.com/mypage.aspx?xp=asd&yp=okasd
and transforms that into:
url.com/mypage/asd/okasd
http://www.iis.net/downloads/microsoft/url-rewrite
That's not my scope. I already have MVC Routes working with url.com/mypage. The problem is that when I type that URL I am redirected (that's the behavior I want) to url.com/otherpage/actionX?param=value. The problem is that I still want the address bar to show url.com/mypage. Will URL Rewrite work for that?
I am asking because I don't know if it will work since it's an internal redirect (RedirectToAction) instead of a 'regular' access.
In case someone wonders why I can't make a route for that, as explained in my question I alread have one rule for that url.com/mypage that redirects to a 'router' which decides what action to call.
I've seen some questions, but I don't think they cover my specific problem:
MVC3 change the url
C# - How to Rewrite a URL in MVC3
UPDATE
This is my route:
routes.MapRoute(
"Profile", // Route name
"{urlParam}", // URL with parameters
new { controller = "Profile", action = "Router" } // Parameter defaults
);
Inside Router action I redirect to the correct action according to some validation done on urlParam. I need this behavior since each action returns a different View.
Updated my tags since I am now using MVC4
Thanks.
I once had to run a php site on a windows box. On the linux box it originally ran, it had a rewrite defined to make site process all request in only one php file (index.php).
I've installed and configured URL Rewrite with following parameters
Name : all to index.php
Match URL ------------------------------
Requested URL : Matches the Pattern
Using : Regular Expressions
Pattern : (.*)
Ignore Case : Checked
Conditions -----------------------------
Logical Grouping : Match All
Input : {REQUEST_FILENAME}
Type : Is Not a File
Action ---------------------------------
Action Type : Rewrite
Action Properties:
Rewrite Url : /index.php?$1
Append Query String : Checked
Log Rewritten URL : Checked
this makes all requests to site (except files like css and js files) to be processed by index.php
so url.com/user/1 is processed on server side as url.com/index.php?/user/1
since it works on server side client url stays same.
using this as you base you can build a rewrite (not a redirect).
Server.Transfer is exactly what you need, but that is not available on MVC.
On the MVC world you can use the TransferResult class defined in this thread.
With that... you add code to your ROUTE action that process the urlParam as always and instead of "redirecting" (RedirectToAction) the user to a new URL, you just "transfer" him/her to a new action method without changing the URL.
But there it a catch (I think, I have not tested it)... if that new page postbacks something... it will NOT use your router's action URL (url.com/mypage), but the real ACTION (url.com/otherpage)
Hope it helps.
In my opinion,you can try following things:
Return EmptyResult or RedirectResult from your Action method.
Also,you need to setup and construct outbound route for URL that you required.
Secondly, if these didn't work,the crude way to handle this situation is with Div tag and replacing the contents of Div with whatever HTML emitted by Action method. I am assuming here that in your problem context, you can call up jquery ajax call.
Hope this Helps.
The problem you have is that you redirect the user ( using 302 http code) to a new location, so browser ,reloads the page. you need to modify the routes to point directly to your controller. The route registration should be routes.MapRoute("specific", "my page", new { controller = "otherpage", action="actions", param="value"}).
This route should be registered first
I am trying to use a controller as an image handler, but how do i pass in a path to it?
Right now it looks like this (works for images without a path):
public void GetImage(string parameter)
{
var imageHandler = UnityGlobalContainer.Container.Resolve<IImageHandler>();
imageHandler.ProcessRequest(parameter);
}
But if i try to send in the path folder1\folder2\folder3\picture.jpg then it fails.
#Html.ActionLink("Show", "GetImage", "Utility", new { parameter = #"folder1\folder2\folder3\picture.jpg" }, new { })
produces this:
http://localhost:58359/Utility/GetImage/folder1%5Cfolder2%5Cfolder3%5Cpicture.jpg
and that leads to:
HTTP Error 400 - Bad Request.
How can i pass in a path to the controller using the normal mvc approach?
(I am using backward slashes and not forward slashes)
I have also tested using HttpUtility.UrlEncode on the parameter.
According to your code: The produced link in the html page should be:
http://localhost:58359/Utility/GetImage?parameter=folder1%5Cfolder2%5Cfolder3%5Cpicture.jpg
and the parameter variable should be correctly set to "folder1\folder2\folder3\picture.jpg" in the action method.
Notice that you might be vulnerable to directory traversal here.
In .NET 4.0 beta 2, the CLR team has offered a workaround.
Add this to your web.config file:
<uri>
<schemeSettings>
<add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
</schemeSettings>
</uri>
This causes the Uri class to behave according to the RFC describing URIs, allowing for slashes to be escaped in the path without being unescaped. The CLR team reports they deviate from the spec for security reasons, and setting this in your .config file basically makes you take ownership of the additional security considerations involved in not unescaping the slashes.
Can you not just decode the parameter?
http://msdn.microsoft.com/en-us/library/6196h3wt.aspx
Instead of calling the filename parameter 'parameter', and defining it in your route, call it 'filename' and DON'T define it in your route.
Your action code will be the same, but the filename will stop being part of the route and just be an ordinary URL parameter.
If you're afflicted by this season's fashion for disliking URL parameters, then you might find this repugnant, but that's just fashion and can safely be ignored.
Personally, I wouldn't pass paths like this into a web app, because I would be absolutely paranoid about creating traversal threats by mistake - I only ever pass in path-free filenames, validate them against a list and then fetch the file.
Take the following controller action
public ActionResult NextBySURNAME(int id, string data)
{
//code to process the data and edit the id accoringly not written yet
return RedirectToAction("Edit", new { id = id });
}
if I call it with
/Mycontroller/NextBySURNAME/12/Smith%20Simon
then it works fine (in this case editing record 12)
but
/Mycontroller/NextBySURNAME/12/Smith%20
gives me a 404
Now I know that in some cases in my problem domain trailing whitespace is significant, so I don't just want to trim it. So why is this breaking my route ?
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}/{data}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional, data=UrlParameter.Optional } // Parameter defaults
);
So I did some route debugging and found that routes that end with a space weren't even being evaluated by my MVC app. Therefore, IIS must be handling these requests poorly.
I added a rewrite rule to IIS 7.5 to match trailing spaces and rewrite them as the same url without the space. I'm not satisfied with this solution but haven't been able to find an explanation about why IIS mishandles URLs with trailing spaces.
I think the way escaped characters are handled is changeable in .NEt 4.0, but I have not tried it myself.
See http://msdn.microsoft.com/en-us/library/system.uri.aspx.
Andrews answer to URL-encoded slash in URL
Also How to create a Uri instance parsed with GenericUriParserOptions.DontCompressPath
This is all only wild guessing but maybe it helps.