views:

6013

answers:

7

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 http://stackoverflow.com/questions/1651711/properly-url-encode-space-character

+7  A: 

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
Mehrdad Afshari
+3  A: 

Gath Adams recommends Base64 encoding on any parameters that can contain slashes. He also explains the issue in more detail: Blog entry: http://gathadams.com/2009/01/06/allowing-special-characters-forward-slash-hash-asterisk-etc-in-aspnet-mvc-urls/

Tomalak
Whoa, there partner! Base64 encoding includes the slash character too! That's not a solution you can rely on for this problem.
Andrew Arnott
This is correct. I did not think of that.
Tomalak
A: 

http://gathadams.com/2009/01/06/allowing-special-characters-forward-slash-hash-asterisk-etc-in-aspnet-mvc-urls/ gives a "404 - file not found" error.

xraminx
works again :-)
Malcolm Frexner
+1  A: 

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

http://localhost:5000/Home/About?100%2f200
Jon Galloway
+2  A: 

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.

Andrew Arnott
This sounds great. I will use this as the answer once .NET 4.0 is released.
Malcolm Frexner
A: 

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);
    }
BillB
+1  A: 

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 
simonox