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>
Related
I have an controller called Test Controller and the method name is Test
The Test Method accepts one parameter. But when the parameter contains value having space slash the web api is giving error. I am using WEB API 2.
[Route("Test/{companyName}")]
[AcceptVerbs("GET", "POST")]
[System.Web.HHttpGet]
public HttpResponseMessage Test(string companyName)
{
}
the parameter value is BTL / Force Motor Ltd.
I have tried but nothing happened.
<uri>
<schemeSettings>
<add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
</schemeSettings>
</uri>
You need to URL Encode the values you are sending to your API, like this:
http://yourApiDomainName/api/yourControllerName/?companyName=BTL%20%2F%20Force%20Motor%20Ltd
[SPACE] when URL encoded beomes: %20
[Forward Slash] when URL encoded becomes: %2F
you dont need to http decode the values in your controller, as these values will be decoded by the framework as soon as they reach your controller. So you will see 'BTL%20%2F%20Force%20Motor%20Ltd' as 'BTL / Force Motor Ltd' inside your controller.
for full list of URL Encodings see this:
http://www.w3schools.com/tags/ref_urlencode.asp
Your issue has nothing to do with WebAPI itself but how ASP.Net handles some specific Urls. This may also affect any dots (".") that get passed in to your API. Here's what worked for me:
Add this line to your web.config under system.web
<httpRuntime relaxedUrlToFileSystemMapping="true" />
Phil Haacked has a great article that goes into more detail.
I have a controller in an MVC 4 .NET application that receives a string as a parameter from an URL. This comes from an aspx page redirected to the controller in Route.config.
If I send this value for the parameter in the client: fwdgerhb+bhrth+ftrgbhrt
I get the following value at the server: fwdgerhb bhrth ftrgbhrt
The server is interpreting the URL parameter value as an encoded URL and replaces + by . But it has not been URL encoded. This will occur for other combinations of special chars if they appear in the parameter value.
Is there a config parameter in IIS Server to configure the server to not try to URL-decode this value?
Example Request:
mypage.aspx?value=cat+dog (NOT ENCODED)
Route Config
static void RegisterRoutes(RouteCollection routes)
{
routes.MapRouteLowercase(
name: "MyRouter",
url: "mypage.aspx",
defaults: new { controller = "My", action = "DoLog" }
);
}
The controller:
public class MyController : Controller
{
[AllowAnonymous]
public ActionResult DoLog(string value)
{
//Here value has "cat dog"
}
}
You can use the following to grab the query-string manually from the controller:
Request.QueryString.Get("value");
Or, to get it from the view:
Html.ViewContext.HttpContext.Request.QueryString.Get("value");
But honestly, why not just encode the string yourself before you send it through the routing:
HttpUtility.UrlEncode(value);
and then when you get the the value again:
HttpUtility.UrlDecode(value);
So that way you have control of your string
Update
You can also do the following to allow your routeConfig to allow the "+" attribute:
<location path="CustomHttpHandler">
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
</system.webServer>
</location>
Here is a question that tells you the ups and downs of turning this on and off: Is Enabling Double Escaping Dangerous?
Yes, MVC automatically URL decodes action parameters, but you can still access the URL encoded version through a query string. As you can see in this question: Is MVC2 ASP.Net URLDecoding automatically?
You can also try to access a server variable named UNENCODED_URL. More information about this scenario can be found here: URL Rewrite Module Configuration Reference
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.
I have an MVC method:
public void PushFile([FromBody]FileTransport fileData)
Class is:
public class FileTransport
{
public string fileData;
}
In fileData I put byte[] from a file converted into a string (UTF-8), so the string can be large.
Problem is: if the string is too large (somewhere above 15000 characters) the fileData parameter is null. If the string is not that large, everything works fine and the parameter is as it should be.
How can I allow MVC to accept larger strings, or do I need to compress the string somehow beforehand?
EDIT:
Already tried:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483644"/>
</webServices>
</scripting>
</system.web.extensions>
But does not work. Maybe because MVC uses JSON.NET instead of the normal JsonSerializer?
Did you try to increase max length of the request?
<system.web>
<httpRuntime maxRequestLength="{REQUEST_LENGTH}"/>
<system.web>
Simple Point is - you dont put the string into the URL. Simple like that. Add it as payload. URL's are ressource locators, not "Content carriers".
I figured out it had nothing to do with content length. If seems like the Json does not encode properly with some characters on the sender's side, that's when MVC controller recieved null.
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.