URL-encoded slash in URL

C#asp.net Mvcasp.net Mvc-RoutingUrlencode

C# Problem Overview


My Map is:

routes.MapRoute(
   "Default",                                             // Route name
   "{controller}/{action}/{id}",                          // URL with params
   new { controller = "Home", action = "Index", id = "" } // Param defaults
);

If I use the URL http://localhost:5000/Home/About/100%2f200 there is no matching route. I change the URL to http://localhost:5000/Home/About/100 then the route is matched again.

Is there any easy way to work with parameters that contain slashes? Other escaped values (space %20) seem to work.

EDIT:

To encode Base64 works for me. It makes the URL ugly, but that's OK for now.

public class UrlEncoder
{ 
    public string URLDecode(string  decode)
    {
        if (decode == null) return null;
        if (decode.StartsWith("="))
        {
            return FromBase64(decode.TrimStart('='));
        }
        else
        {
            return HttpUtility.UrlDecode( decode) ;
        }
    }

    public string UrlEncode(string encode)
    {
        if (encode == null) return null;
        string encoded = HttpUtility.PathEncode(encode);
        if (encoded.Replace("%20", "") == encode.Replace(" ", ""))
        {
            return encoded;
        }
        else
        {
            return "=" + ToBase64(encode);
        }
    }

    public string ToBase64(string encode)
    {
        Byte[] btByteArray = null;
        UTF8Encoding encoding = new UTF8Encoding();
        btByteArray = encoding.GetBytes(encode);
        string sResult = System.Convert.ToBase64String(btByteArray, 0, btByteArray.Length);
        sResult = sResult.Replace("+", "-").Replace("/", "_");
        return sResult;
    }

    public string FromBase64(string decode)
    {
        decode = decode.Replace("-", "+").Replace("_", "/");
        UTF8Encoding encoding = new UTF8Encoding();
        return encoding.GetString(Convert.FromBase64String(decode));
    }
}

EDIT1:

At the end it turned out that the best way was to save a nicely formated string for each item I need to select. Thats much better because now I only encode values and never decode them. All special characters become "-". A lot of my db-tables now have this additional column "URL". The data is pretty stable, thats why I can go this way. I can even check, if the data in "URL" is unique.

EDIT2:

Also watch out for space character. It looks ok on VS integrated webserver but is different on iis7 https://stackoverflow.com/questions/1651711/properly-url-encode-space-character

C# Solutions


Solution 1 - C#

If it's only your last parameter, you could do:

routes.MapRoute(
    "Default",                                                // Route name
    "{controller}/{action}/{*id}",                            // URL with parameters
    new { controller = "Home", action = "Index", id = "" });  // Parameter defaults

Solution 2 - C#

Here's a simple explanation of the solution and a summation of what has already been said.

Request side:

  1. UrlEncode your path.
  2. Replace the '%' with '!'.
  3. Make the request.

Response side:

  1. Replace the '!' with '%'.
  2. UrlDecode your path.
  3. Use the parameters as they were intended.

Rinse, repeat, enjoy.

Solution 3 - C#

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.

Solution 4 - C#

One other option is to use a querystring value. Very lame, but simpler than custom encoding.

http://localhost:5000/Home/About?100%2f200

Solution 5 - C#

Same for Java / Tomcat.

There is still a problem if you have got an encoded "/" (%2F) in your URL.

RFC 3986 - Section 2.2 says: "If data for a URI component would conflict with a reserved character's purpose as a delimiter, then the conflicting data must be percent-encoded before the URI is formed." (RFC 3986 - Section 2.2)

But there is an Issue with Tomcat:

> http://tomcat.apache.org/security-6.html - Fixed in Apache Tomcat 6.0.10 > > important: Directory traversal CVE-2007-0450 > > Tomcat permits '', '%2F' and '%5C' > [...] . > > The following Java system properties > have been added to Tomcat to provide > additional control of the handling of > path delimiters in URLs (both options > default to false): > > * org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: > true|false > * org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH: > true|false > > Due to the impossibility to guarantee > that all URLs are handled by Tomcat as > they are in proxy servers, Tomcat > should always be secured as if no > proxy restricting context access was > used. > > Affects: 6.0.0-6.0.9

So if you have got an URL with the %2F character, Tomcat returns: "400 Invalid URI: noSlash"

You can switch of the bugfix in the Tomcat startup script:

set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%   -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true 

Solution 6 - C#

You can avoid the double encoding/decoding suggestions above and simply use HttpServerUtility.UrlTokenEncode and the corresponding UrlTokenDecode.

Solution 7 - C#

That's interesting about .NET 4. Anyway, this link describes RFC 1738 and includes which characters need encoding and which are just "unsafe". link text

If I want an SEO friendly URL, (like when you want to put a forum post subject in the URL), is skip encoding and replace anything that's not A-Z, a-z, 0-9.

public static string CreateSubjectSEO(string str)
    {
        int ci;
        char[] arr = str.ToCharArray();
        for (int i = 0; i < arr.Length; i++)
        {
            ci = Convert.ToInt32(arr[i]);
            if (!((ci > 47 && ci < 58) || (ci > 64 && ci < 91) || (ci > 96 && ci < 123)))
            {
                arr[i] = '-';
            }
        }
        return new string(arr);
    }

Solution 8 - C#

For inbound encoded '/' issue, I was able to fix my issue by adding '*' to catchall the id parameter and then was able to passing an encoded '/' into the the control correctly (the parameter was a string with an encoded '/')

routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{*id}",
            defaults: new 
            { 
                controller = "Control", 
                action = "Action", 
                id = UrlParameter.Optional 
            })

Solution 9 - C#

As suggested here when the problem was faced by Symfony 1.x developers (+ suggested in PHP comments for urlencode()):

  • Encode '/' to '%2F' before urlencode()
  • Decode '%2F' to '/' after (if necessary) urldecode()

Note: you can use rawurlencode(), but you will still have to urlencode '/' twice.

Advantages:

  • Avoids the need of additional escaping processes (if replacing '/' with a special character like '!' or '_')

  • Do not relies on any server setting such as AllowEncodedSlashes for Apache

Solution 10 - C#

Just use Server.UrlDecode. It will work, I've tested.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMathias FView Question on Stackoverflow
Solution 1 - C#mmxView Answer on Stackoverflow
Solution 2 - C#Don RollingView Answer on Stackoverflow
Solution 3 - C#Andrew ArnottView Answer on Stackoverflow
Solution 4 - C#Jon GallowayView Answer on Stackoverflow
Solution 5 - C#simonoxView Answer on Stackoverflow
Solution 6 - C#silentnoiseView Answer on Stackoverflow
Solution 7 - C#BillBView Answer on Stackoverflow
Solution 8 - C#user11406534View Answer on Stackoverflow
Solution 9 - C#Frosty ZView Answer on Stackoverflow
Solution 10 - C#shijas kmView Answer on Stackoverflow