Merge pull request #1156 from felfert/master
[mono.git] / mcs / class / System.Web / System.Web.Util / UrlUtils.cs
index 179158ec1ab20f1b8cf8f6c4fd2784b1cadbc4aa..4f07e83f1345769d5dfa62d699c17d526a0eda12 100644 (file)
 //
 
 using System.Web.SessionState;
+using System.Text;
 namespace System.Web.Util {
        
-       internal class UrlUtils {
+#if VISUAL_STUDIO
+       public
+#else
+       internal 
+#endif
+       class UrlUtils {
 
                // appRoot + SessionID + vpath
-               internal static string InsertSessionId (string id, string path)
+               public static string InsertSessionId (string id, string path)
                {
                        string dir = GetDirectory (path);
                        if (!dir.EndsWith ("/"))
@@ -54,25 +60,45 @@ namespace System.Web.Util {
                        return Canonic (appvpath + "(" + id + ")/" + path);
                }
 
-               internal static string GetSessionId (string path)
+               public static string GetSessionId (string path)
                {
+#if TARGET_DOTNET
+                       return null;
+#else
+                       if (path == null)
+                               return null;
+
                        string appvpath = HttpRuntime.AppDomainAppVirtualPath;
-                       if (path.Length <= appvpath.Length)
+                       int appvpathlen = appvpath.Length;
+
+                       if (path.Length <= appvpathlen)
                                return null;
 
-                       path = path.Substring (appvpath.Length);
-                       if (path.Length == 0 || path [0] != '/')
+                       path = path.Substring (appvpathlen);
+                       
+                       int len = path.Length;
+                       if (len == 0 || path [0] != '/') {
                                path = '/' + path;
+                               len++;
+                       }                       
 
-                       int len = path.Length;
                        if ((len < SessionId.IdLength + 3) || (path [1] != '(') ||
                            (path [SessionId.IdLength + 2] != ')'))
                                return null;
 
                        return path.Substring (2, SessionId.IdLength);
+#endif
+               }
+
+               public static bool HasSessionId (string path)
+               {
+                       if (path == null || path.Length < 5)
+                               return false;
+
+                       return (StrUtils.StartsWith (path, "/(") && path.IndexOf (")/") > 2);
                }
 
-               internal static string RemoveSessionId (string base_path, string file_path)
+               public static string RemoveSessionId (string base_path, string file_path)
                {
                        // Caller did a GetSessionId first
                        int idx = base_path.IndexOf ("/(");
@@ -101,7 +127,7 @@ namespace System.Web.Util {
                        if (rlength == 0)
                                return "";
 
-                       relPath = relPath.Replace ("\\", "/");
+                       relPath = relPath.Replace ('\\', '/');
                        if (IsRooted (relPath))
                                return Canonic (relPath);
 
@@ -129,7 +155,7 @@ namespace System.Web.Util {
                                return Canonic (basePath + slash + relPath);
                        }
 
-                       if (basePath == null || basePath == "" || basePath [0] == '~')
+                       if (basePath == null || basePath.Length == 0 || basePath [0] == '~')
                                basePath = HttpRuntime.AppDomainAppVirtualPath;
 
                        if (basePath.Length <= 1)
@@ -140,8 +166,10 @@ namespace System.Web.Util {
 
                static char [] path_sep = {'\\', '/'};
                
-               internal static string Canonic (string path)
+               public static string Canonic (string path)
                {
+                       bool isRooted = IsRooted(path);
+                       bool endsWithSlash = path.EndsWith("/");
                        string [] parts = path.Split (path_sep);
                        int end = parts.Length;
                        
@@ -149,61 +177,88 @@ namespace System.Web.Util {
                        
                        for (int i = 0; i < end; i++) {
                                string current = parts [i];
+
+                               if (current.Length == 0)
+                                       continue;
+
                                if (current == "." )
                                        continue;
 
                                if (current == "..") {
-                                       if (dest == 0) {
-                                               if (i == 1) // see bug 52599
-                                                       continue;
-
-                                               throw new HttpException ("Invalid path.");
-                                       }
-
                                        dest --;
                                        continue;
                                }
+                               if (dest < 0)
+                                       if (!isRooted)
+                                               throw new HttpException ("Invalid path.");
+                                       else
+                                               dest = 0;
 
                                parts [dest++] = current;
                        }
+                       if (dest < 0)
+                               throw new HttpException ("Invalid path.");
 
                        if (dest == 0)
                                return "/";
 
-                       return String.Join ("/", parts, 0, dest);
+                       string str = String.Join ("/", parts, 0, dest);
+                       str = RemoveDoubleSlashes (str);
+                       if (isRooted)
+                               str = "/" + str;
+                       if (endsWithSlash)
+                               str = str + "/";
+
+                       return str;
                }
                
-               internal static string GetDirectory (string url)
+               public static string GetDirectory (string url)
                {
                        url = url.Replace('\\','/');
                        int last = url.LastIndexOf ('/');
 
                        if (last > 0) {
-#if NET_2_0
+                               if (last < url.Length)
+                                       last++;
                                return RemoveDoubleSlashes (url.Substring (0, last));
-#else
-                               return url.Substring (0, last);
-#endif
                        }
 
                        return "/";
                }
 
-#if NET_2_0
-               internal static string RemoveDoubleSlashes (string input)
+               public static string RemoveDoubleSlashes (string input)
                {
                        // MS VirtualPathUtility removes duplicate '/'
-                       string str = input;
-                       string x;
-                       while ((x = str.Replace ("//", "/")) != str) {
-                               str = x;
+
+                       int index = -1;
+                       for (int i = 1; i < input.Length; i++)
+                               if (input [i] == '/' && input [i - 1] == '/') {
+                                       index = i - 1;
+                                       break;
+                               }
+
+                       if (index == -1) // common case optimization
+                               return input;
+
+                       StringBuilder sb = new StringBuilder (input.Length);
+                       sb.Append (input, 0, index);
+
+                       for (int i = index; i < input.Length; i++) {
+                               if (input [i] == '/') {
+                                       int next = i + 1;
+                                       if (next < input.Length && input [next] == '/')
+                                               continue;
+                                       sb.Append ('/');
+                               }
+                               else {
+                                       sb.Append (input [i]);
+                               }
                        }
 
-                       return str;
+                       return sb.ToString ();
                }
-#endif
 
-               internal static string GetFile (string url)
+               public static string GetFile (string url)
                {
                        url = url.Replace('\\','/');
                        int last = url.LastIndexOf ('/');
@@ -213,12 +268,12 @@ namespace System.Web.Util {
                                return url.Substring (last+1);
                        }
 
-                       throw new Exception (String.Format ("GetFile: `{0}' does not contain a /", url));
+                       throw new ArgumentException (String.Format ("GetFile: `{0}' does not contain a /", url));
                }
                
-               internal static bool IsRooted (string path)
+               public static bool IsRooted (string path)
                {
-                       if (path == null || path == "")
+                       if (path == null || path.Length == 0)
                                return true;
 
                        char c = path [0];
@@ -228,7 +283,7 @@ namespace System.Web.Util {
                        return false;
                }
 
-               internal static bool IsRelativeUrl (string path)
+               public static bool IsRelativeUrl (string path)
                {
                        return (path [0] != '/' && path.IndexOf (':') == -1);
                }