3

I have a web api that uses .Net 4.7.1 and I noticed some strange behavior when performing a get on one of the endpoints. When I perform a get to the endpoint http://localhost:52684/api/v1/some-resource?client_timezone=%2B0500 the parameter client timezone is received as " 0500" rather than "+0500". the only thing I can think of is that the Url is being decoded twice so the "%2B" turns into "+" and then " ". Does anyone know of any common causes of this or why it might be happening?

Here's a similar endpoint on the controller

[HttpGet]
[Authorize]
[ApiRoute("some-resource", StartingVersion = 1)]
[EnableCors("*", "*", "GET", "*")]
public IHttpActionResult SomeResource([FromUri] string timezone)
{
    if (!DataValidationUtililties.IsValidClientTimezone(timezone))
    {
        return BadRequest();
    }
    return Ok();
}
David Carek
  • 1,103
  • 1
  • 12
  • 26
  • 4
    Do you have an example of where this is happening in your code? Can you post that code? – Justin Pearce Aug 13 '18 at 19:16
  • I believe that + is interpreted as a space. If you google "a b c" the query becomes "https://www.google.co.uk/search?q=a+b+c&oq=a+b+c" see how the spaces become pluses. – Neil Aug 13 '18 at 19:25
  • Yes but I encoded the + to %2B – David Carek Aug 13 '18 at 19:27
  • Its not a duplicate I explicitly state that I am using %2B in the query string which ends up turning into a space. That post says use %2B not the + in the query string which is what I'm doing. – David Carek Aug 13 '18 at 19:42
  • I do think it is a duplicate because Web API has no problems with query string and an encoded `+` character. Chances are you are double decoding in some custom filter you wrote. – Igor Aug 13 '18 at 19:55

1 Answers1

1

I think I found the reason why. I created a SnakeCaseActionSelector which essentially rewrites all request URIs. In doing so it decodes the url and never encodes the query string parameters again.

public class SnakeCaseActionSelector : ApiControllerActionSelector
{
    public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
    {
        var requestUri = controllerContext.Request.RequestUri;
        var queryPairs = controllerContext.Request.GetQueryNameValuePairs().ToList();
        if (!queryPairs.Any())
        {
            return base.SelectAction(controllerContext);
        }
        queryPairs = queryPairs.Select(x =>
                new KeyValuePair<string, string>(CamelCaseToSnakeCaseConverter.FromSnakeCase(x.Key), x.Value))
            .ToList();
        var newQueryParams = queryPairs.Select(x => $"{x.Key}={x.Value}").Aggregate((x, y) => x + "&" + y);
        var builder = new UriBuilder(requestUri)
        {
            Query = newQueryParams
        };
        controllerContext.Request.RequestUri = builder.Uri;

        return base.SelectAction(controllerContext);
    }
}
David Carek
  • 1,103
  • 1
  • 12
  • 26