2007-03-15 Igor Zelmanovich <igorz@mainsoft.com>
authorIgor Zelmanovich <igorz@mono-cvs.ximian.com>
Thu, 15 Mar 2007 09:46:53 +0000 (09:46 -0000)
committerIgor Zelmanovich <igorz@mono-cvs.ximian.com>
Thu, 15 Mar 2007 09:46:53 +0000 (09:46 -0000)
* VirtualPathUtility.cs: fixed: works properly with appRelative path.

svn path=/trunk/mcs/; revision=74340

mcs/class/System.Web/System.Web/ChangeLog
mcs/class/System.Web/System.Web/VirtualPathUtility.cs
mcs/class/System.Web/Test/System.Web/ChangeLog
mcs/class/System.Web/Test/System.Web/VirtualPathUtilityTest.cs

index aa60b209a60a035f82d44a9f76989fcfad5bede1..36bd79d6a81e18eb8313c9a8394eeb2a3e689140 100644 (file)
@@ -1,3 +1,7 @@
+2007-03-15 Igor Zelmanovich <igorz@mainsoft.com>
+
+       * VirtualPathUtility.cs: fixed: works properly with appRelative path.
+
 2007-03-13  Marek Habersack  <mhabersack@novell.com>
 
        * HttpApplicationFactory.cs: resources compiler no longer accepts
index 9cf387a2357c5bbc0c014c84ae781340ff87ce9f..c0e6774f270ef709d79245a3d77c39244adea5ba 100644 (file)
@@ -32,6 +32,7 @@
 #if NET_2_0\r
 \r
 using System.Web.Util;\r
+using System.Text;\r
 \r
 namespace System.Web {\r
 \r
@@ -51,33 +52,23 @@ namespace System.Web {
 \r
                public static string Combine (string basePath, string relativePath)\r
                {\r
-                       if (basePath == null || basePath == "")\r
-                               throw new ArgumentNullException ("basePath");\r
-\r
-                       if (relativePath == null)\r
-                               // LAME SPEC - MSDN Specifies ArgumentNullException but MS throws ArgumentException\r
-                               throw new ArgumentException ("relativePath");\r
-\r
-                       if (relativePath == "")\r
-                               // MS throw different exception for null or empty string.\r
-                               throw new ArgumentNullException ("relativePath");\r
-\r
-                       if (relativePath.Length == 1 && relativePath [0] == '~')\r
-                               return HttpRuntime.AppDomainAppVirtualPath;\r
-\r
-                       if (relativePath [0] == '~' && relativePath [1] == '/')\r
-                               return UrlUtils.RemoveDoubleSlashes ((HttpRuntime.AppDomainAppVirtualPath + relativePath.Substring (1)).Replace ('\\', '/'));\r
-\r
-                       if (basePath [0] != '/')\r
-                               throw new ArgumentException ("basePath is not an absolute path", "basePath");\r
-\r
-                       if (basePath.Length > 1 && basePath [basePath.Length - 1] != '/') {\r
-                               int lastSlash = basePath.LastIndexOf ('/');\r
-                               if (lastSlash >= 0)\r
-                                       return UrlUtils.Combine (basePath.Substring (0, lastSlash + 1), relativePath);\r
+                       basePath = Normalize (basePath);\r
+\r
+                       if (IsRooted (relativePath))\r
+                               return Normalize (relativePath);\r
+\r
+                       if (basePath [basePath.Length - 1] != '/') {\r
+                               if (basePath.Length > 1) {\r
+                                       int lastSlash = basePath.LastIndexOf ('/');\r
+                                       if (lastSlash >= 0)\r
+                                               basePath = basePath.Substring (0, lastSlash + 1);\r
+                               }\r
+                               else { // "~" only\r
+                                       basePath += "/";\r
+                               }\r
                        }\r
 \r
-                       return UrlUtils.Combine (basePath, relativePath);\r
+                       return Normalize (basePath + relativePath);\r
                }\r
 \r
                public static string GetDirectory (string virtualPath)\r
@@ -124,9 +115,14 @@ namespace System.Web {
                        return UrlUtils.GetFile (RemoveTrailingSlash (virtualPath));\r
                }\r
 \r
+               static bool IsRooted (string virtualPath)\r
+               {\r
+                       return IsAbsolute (virtualPath) || IsAppRelative (virtualPath);\r
+               }\r
+\r
                public static bool IsAbsolute (string virtualPath)\r
                {\r
-                       if (virtualPath == "" || virtualPath == null)\r
+                       if (String.IsNullOrEmpty (virtualPath))\r
                                throw new ArgumentNullException ("virtualPath");\r
 \r
                        return (virtualPath [0] == '/');\r
@@ -146,6 +142,10 @@ namespace System.Web {
                        return false;\r
                }\r
 \r
+               // MSDN: If the fromPath and toPath parameters are not rooted; that is, \r
+               // they do not equal the root operator (the tilde [~]), do not start with a tilde (~), \r
+               // such as a tilde and a slash mark (~/) or a tilde and a double backslash (~//), \r
+               // or do not start with a slash mark (/), an ArgumentException exception is thrown.\r
                public static string MakeRelative (string fromPath, string toPath)\r
                {\r
                        if (fromPath == null || toPath == null)\r
@@ -154,14 +154,37 @@ namespace System.Web {
                        if (toPath == "")\r
                                return toPath;\r
 \r
-                       if (toPath [0] != '/')\r
-                               throw new ArgumentOutOfRangeException (); // This is what MS does.\r
+                       toPath = ToAbsoluteInternal (toPath);\r
+                       fromPath = ToAbsoluteInternal (fromPath);\r
+\r
+                       if (String.CompareOrdinal (fromPath, toPath) == 0 && fromPath [fromPath.Length - 1] == '/')\r
+                               return "./";\r
+\r
+                       string [] toPath_parts = toPath.Split ('/');\r
+                       string [] fromPath_parts = fromPath.Split ('/');\r
+                       int dest = 1;\r
+                       while (toPath_parts [dest] == fromPath_parts [dest]) {\r
+                               if (toPath_parts.Length == (dest + 1) || fromPath_parts.Length == (dest + 1)) {\r
+                                       break;\r
+                               }\r
+                               dest++;\r
+                       }\r
+                       string res = "";\r
+                       for (int i = 1; i < fromPath_parts.Length - dest; i++) {\r
+                               res += "../";\r
+                       }\r
+                       res += String.Join ("/", toPath_parts, dest, toPath_parts.Length - dest);\r
+                       return res;\r
+               }\r
 \r
-                       if (fromPath.Length > 0 && fromPath [0] != '/')\r
-                               throw new ArgumentOutOfRangeException (); // This is what MS does.\r
+               private static string ToAbsoluteInternal (string virtualPath)\r
+               {\r
+                       if (IsAppRelative (virtualPath))\r
+                               return ToAbsolute (virtualPath);\r
+                       else if (IsAbsolute (virtualPath))\r
+                               return Normalize (virtualPath);\r
 \r
-                       Uri from = new Uri ("http://nothing" + fromPath);\r
-                       return from.MakeRelativeUri (new Uri ("http://nothing" + toPath)).AbsolutePath;\r
+                       throw new ArgumentOutOfRangeException ("Specified argument was out of the range of valid values.");\r
                }\r
 \r
                public static string RemoveTrailingSlash (string virtualPath)\r
@@ -191,22 +214,22 @@ namespace System.Web {
                // Not rooted, the ToAbsolute method raises an ArgumentOutOfRangeException exception.\r
                public static string ToAbsolute (string virtualPath, string applicationPath)\r
                {\r
-                       if (applicationPath == null || applicationPath == "")\r
+                       if (String.IsNullOrEmpty (applicationPath))\r
                                throw new ArgumentNullException ("applicationPath");\r
 \r
-                       if (virtualPath == null || virtualPath == "")\r
+                       if (String.IsNullOrEmpty (virtualPath))\r
                                throw new ArgumentNullException ("virtualPath");\r
 \r
                        if (IsAppRelative(virtualPath)) {\r
                                if (applicationPath [0] != '/')\r
                                        throw new ArgumentException ("appPath is not rooted", "applicationPath");\r
-                               return UrlUtils.RemoveDoubleSlashes ((applicationPath + (virtualPath.Length == 1 ? "/" : virtualPath.Substring (1))).Replace ('\\', '/'));\r
+                               return Normalize ((applicationPath + (virtualPath.Length == 1 ? "/" : virtualPath.Substring (1))));\r
                        }\r
 \r
                        if (virtualPath [0] != '/')\r
                                throw new ArgumentException (String.Format ("Relative path not allowed: '{0}'", virtualPath));\r
 \r
-                       return UrlUtils.RemoveDoubleSlashes (virtualPath.Replace ('\\', '/'));\r
+                       return Normalize (virtualPath);\r
 \r
                }\r
 \r
@@ -216,25 +239,163 @@ namespace System.Web {
                        if (apppath == null)\r
                                throw new HttpException ("The path to the application is not known");\r
 \r
-                       return ToAppRelative (apppath, virtualPath);\r
+                       return ToAppRelative (virtualPath, apppath);\r
                }\r
 \r
                public static string ToAppRelative (string virtualPath, string applicationPath)\r
                {\r
-                       if (applicationPath == null || applicationPath == "")\r
-                               throw new ArgumentNullException ("applicationPath");\r
+                       virtualPath = Normalize (virtualPath);\r
+                       \r
+                       if (IsAppRelative (virtualPath))\r
+                               return virtualPath;\r
 \r
-                       if (virtualPath == null || virtualPath == "")\r
-                               throw new ArgumentNullException ("virtualPath");\r
+                       if (!IsAbsolute (applicationPath))\r
+                               throw new ArgumentException ("appPath is not absolute", "applicationPath");\r
+                       \r
+                       applicationPath = Normalize (applicationPath);\r
 \r
-                       if (virtualPath.StartsWith (".."))\r
-                               throw new ArgumentException (String.Format ("Relative path not allowed: '{0}'", virtualPath));\r
+                       if (applicationPath.Length == 1)\r
+                               return "~" + virtualPath;\r
+\r
+                       int appPath_lenght = applicationPath.Length;\r
+                       if (String.CompareOrdinal (virtualPath, applicationPath) == 0)\r
+                               return "~/";\r
+                       if (String.CompareOrdinal (virtualPath, 0, applicationPath, 0, appPath_lenght) == 0)\r
+                               return "~" + virtualPath.Substring (appPath_lenght);\r
+\r
+                       return virtualPath;\r
+               }\r
+\r
+               static char [] path_sep = { '/' };\r
+\r
+               static string Normalize (string path)\r
+               {\r
+                       if (!IsRooted (path))\r
+                               throw new ArgumentException (String.Format ("The relative virtual path '{0}' is not allowed here.", path));\r
 \r
-                       if (applicationPath [0] != '/')\r
-                               throw new ArgumentOutOfRangeException ("appPath is not rooted", "applicationPath");\r
+                       if (path.Length == 1) // '/' or '~'\r
+                               return path;\r
 \r
-                       return MakeRelative (applicationPath, virtualPath);\r
+                       path = Canonize (path);\r
+\r
+                       if (path.IndexOf ('.') < 0)\r
+                               return path;\r
+\r
+                       bool starts_with_tilda = false;\r
+                       bool ends_with_slash = false;\r
+                       string [] apppath_parts= null;\r
+\r
+                       if (path [0] == '~') {\r
+                               if (path.Length == 2) // "~/"\r
+                                       return "~/";\r
+                               starts_with_tilda = true;\r
+                               path = path.Substring (1);\r
+                       }\r
+                       else if (path.Length == 1) { // "/"\r
+                               return "/";\r
+                       }\r
+\r
+                       if (path [path.Length - 1] == '/')\r
+                               ends_with_slash = true;\r
+\r
+                       string [] parts = path.Split (path_sep, StringSplitOptions.RemoveEmptyEntries);\r
+                       int end = parts.Length;\r
+\r
+                       int dest = 0;\r
+\r
+                       for (int i = 0; i < end; i++) {\r
+                               string current = parts [i];\r
+                               if (current == ".")\r
+                                       continue;\r
+\r
+                               if (current == "..") {\r
+                                       dest--;\r
+\r
+                                       if(dest >= 0)\r
+                                               continue;\r
+\r
+                                       if (starts_with_tilda) {\r
+                                               if (apppath_parts == null) {\r
+                                                       string apppath = HttpRuntime.AppDomainAppVirtualPath;\r
+                                                       apppath_parts = apppath.Split (path_sep, StringSplitOptions.RemoveEmptyEntries);\r
+                                               }\r
+\r
+                                               if ((apppath_parts.Length + dest) >= 0)\r
+                                                       continue;\r
+                                       }\r
+                                       \r
+                                       throw new HttpException ("Cannot use a leading .. to exit above the top directory.");\r
+                               }\r
+\r
+                               if (dest >= 0)\r
+                                       parts [dest] = current;\r
+                               else\r
+                                       apppath_parts [apppath_parts.Length + dest] = current;\r
+                               \r
+                               dest++;\r
+                       }\r
+\r
+                       StringBuilder str = new StringBuilder();\r
+                       if (apppath_parts != null) {\r
+                               starts_with_tilda = false;\r
+                               int count = apppath_parts.Length;\r
+                               if (dest < 0)\r
+                                       count += dest;\r
+                               for (int i = 0; i < count; i++) {\r
+                                       str.Append ('/');\r
+                                       str.Append (apppath_parts [i]);\r
+                               }\r
+                       }\r
+                       else if (starts_with_tilda) {\r
+                               str.Append ('~');\r
+                       }\r
+\r
+                       for (int i = 0; i < dest; i++) {\r
+                               str.Append ('/');\r
+                               str.Append (parts [i]);\r
+                       }\r
+\r
+                       if (str.Length > 0) {\r
+                               if (ends_with_slash)\r
+                                       str.Append ('/');\r
+                       }\r
+                       else {\r
+                               return "/";\r
+                       }\r
+\r
+                       return str.ToString ();\r
                }\r
+\r
+               static string Canonize (string path)\r
+               {\r
+                       int index = -1;\r
+                       for (int i=0; i < path.Length; i++) {\r
+                               if ((path [i] == '\\') || (path [i] == '/' && (i + 1) < path.Length && (path [i + 1] == '/' || path [i + 1] == '\\'))) {\r
+                                       index = i;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       if (index < 0)\r
+                               return path;\r
+\r
+                       StringBuilder sb = new StringBuilder (path.Length);\r
+                       sb.Append (path, 0, index);\r
+\r
+                       for (int i = index; i < path.Length; i++) {\r
+                               if (path [i] == '\\' || path [i] == '/') {\r
+                                       int next = i + 1;\r
+                                       if (next < path.Length && (path [next] == '\\' || path [next] == '/'))\r
+                                               continue;\r
+                                       sb.Append ('/');\r
+                               }\r
+                               else {\r
+                                       sb.Append (path [i]);\r
+                               }\r
+                       }\r
+\r
+                       return sb.ToString ();\r
+               }\r
+\r
        }\r
 }\r
 \r
index 5042b76cb80416f1a12829b30ae01efcdf63c03d..fb9fddd8223d6b5c362d8be2e691e51169bae00e 100644 (file)
@@ -1,3 +1,7 @@
+2007-03-15 Igor Zelmanovich <igorz@mainsoft.com>
+
+       * VirtualPathUtilityTest.cs: new tests.
+
 2007-03-06 Igor Zelmanovich <igorz@mainsoft.com>
 
        * StaticSiteMapProviderTest.cs: removed NotWorking attributes..
index cb26d09c2eaf58c7f4ee8e1c2690c040d2a1244f..4fd8d68090da9b0ed3fb450bacf2cc5e7d4f285c 100644 (file)
@@ -58,10 +58,118 @@ namespace MonoTests.System.Web {
                        Assert.AreEqual ("/there", VPU.Combine ("/hi", "there"), "A1");\r
                        Assert.AreEqual ("/hi/you", VPU.Combine ("/hi/there", "you"), "A2");\r
                        Assert.AreEqual ("/hi/there/you", VPU.Combine ("/hi/there/", "you"), "A3");\r
+                       \r
+                       Assert.AreEqual ("/there/", VPU.Combine ("/hi", "there/"), "A1");\r
+                       Assert.AreEqual ("/hi/you/", VPU.Combine ("/hi/there", "you/"), "A2");\r
+                       Assert.AreEqual ("/hi/there/you/", VPU.Combine ("/hi/there/", "you/"), "A3");\r
+\r
+                       Assert.AreEqual ("/there", VPU.Combine ("/hi", "/there"), "A1");\r
+                       Assert.AreEqual ("/you", VPU.Combine ("/hi/there", "/you"), "A2");\r
+                       Assert.AreEqual ("/you", VPU.Combine ("/hi/there/", "/you"), "A3");\r
+               }\r
+\r
+               [Test]\r
+               public void Combine3 ()\r
+               {\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi/", ".."), "A1");\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi/there", ".."), "A2");\r
+                       Assert.AreEqual ("/hi", VPU.Combine ("/hi/there/", ".."), "A3");\r
+\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi/", "../"), "A1");\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi/there", "../"), "A2");\r
+                       Assert.AreEqual ("/hi/", VPU.Combine ("/hi/there/", "../"), "A3");\r
+                       \r
+                       Assert.AreEqual ("/", VPU.Combine ("/", "."), "A1");\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi", "."), "A2");\r
+                       Assert.AreEqual ("/hi", VPU.Combine ("/hi/", "."), "A3");\r
+\r
+                       Assert.AreEqual ("/", VPU.Combine ("/", "./"), "A1");\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi", "./"), "A2");\r
+                       Assert.AreEqual ("/hi/", VPU.Combine ("/hi/", "./"), "A3");\r
+\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi", "there/../"), "A1");\r
+                       Assert.AreEqual ("/hi", VPU.Combine ("/hi/there", "you/.."), "A2");\r
+\r
+                       Assert.AreEqual ("/there/", VPU.Combine ("/hi", "there/./"), "A1");\r
+                       Assert.AreEqual ("/hi/you", VPU.Combine ("/hi/there", "you/."), "A2");\r
+                       \r
+                       Assert.AreEqual ("/blah2/", VPU.Combine ("/ROOT", "/blah1/../blah2/"));\r
+                       Assert.AreEqual ("/blah1/blah2/", VPU.Combine ("/ROOT", "/blah1/./blah2/"));\r
+\r
+                       Assert.AreEqual ("/blah1", VPU.Combine ("/ROOT", "/blah1/blah2/.."));\r
+                       Assert.AreEqual ("/", VPU.Combine ("/ROOT", "/blah1/.."));\r
+                       Assert.AreEqual ("/blah1/", VPU.Combine ("/ROOT", "/blah1/blah2/../"));\r
+                       Assert.AreEqual ("/", VPU.Combine ("/ROOT", "/blah1/../"));\r
+\r
+                       Assert.AreEqual ("/blah1", VPU.Combine ("/ROOT", "/blah1/."));\r
+                       Assert.AreEqual ("/", VPU.Combine ("/ROOT", "/."));\r
+                       Assert.AreEqual ("/blah1/", VPU.Combine ("/ROOT", "/blah1/./"));\r
+                       Assert.AreEqual ("/", VPU.Combine ("/ROOT", "/./"));\r
+\r
+                       Assert.AreEqual ("/", VPU.Combine ("///hi/", ".."), "A1");\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi/there/me/..", ".."), "A1");\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi/there/../", ".."), "A1");\r
+                       Assert.AreEqual ("/hi/me", VPU.Combine ("/hi/there/../", "me"), "A1");\r
+                       Assert.AreEqual ("/", VPU.Combine ("/hi/there/../you", ".."), "A1");\r
+                       Assert.AreEqual ("/hi/me", VPU.Combine ("/hi/there/../you", "me"), "A1");\r
+                       Assert.AreEqual ("/hi/you/me", VPU.Combine ("/hi/there/../you/", "me"), "A1");\r
+               }\r
+\r
+               [Test]\r
+               public void Combine4 ()\r
+               {\r
+                       new WebTest (PageInvoker.CreateOnLoad (Combine4_Load)).Run ();\r
+               }\r
+\r
+               public static void Combine4_Load (Page p)\r
+               {\r
+                       Assert.AreEqual ("~", VPU.Combine ("/ROOT", "~"), "/ROOT, ~");\r
+                       Assert.AreEqual ("~/blah1", VPU.Combine ("/ROOT", "~/blah1"), "/ROOT, ~/blah1");\r
+                       Assert.AreEqual ("~/blah1/", VPU.Combine ("/ROOT", "~/blah1/"));\r
+\r
+                       Assert.AreEqual ("~/blah2/", VPU.Combine ("/ROOT", "~/blah1/../blah2/"));\r
+                       Assert.AreEqual ("~/blah1/blah2/", VPU.Combine ("/ROOT", "~/blah1/./blah2/"));\r
+\r
+                       Assert.AreEqual ("~/blah1", VPU.Combine ("/ROOT", "~/blah1/blah2/.."));\r
+                       Assert.AreEqual ("~", VPU.Combine ("/ROOT", "~/blah1/.."));\r
+                       Assert.AreEqual ("~/blah1/", VPU.Combine ("/ROOT", "~/blah1/blah2/../"));\r
+                       Assert.AreEqual ("~/", VPU.Combine ("/ROOT", "~/blah1/../"));\r
+\r
+                       Assert.AreEqual ("~/blah1", VPU.Combine ("/ROOT", "~/blah1/."));\r
+                       Assert.AreEqual ("~", VPU.Combine ("/ROOT", "~/."));\r
+                       Assert.AreEqual ("~/blah1/", VPU.Combine ("/ROOT", "~/blah1/./"));\r
+                       Assert.AreEqual ("~/", VPU.Combine ("/ROOT", "~/./"));\r
+\r
+                       Assert.AreEqual ("/", VPU.Combine ("~/ROOT", "~/.."), "~/ROOT, ~/..");\r
+                       Assert.AreEqual ("/", VPU.Combine ("~/ROOT", ".."));\r
+                       Assert.AreEqual ("~", VPU.Combine ("~/ROOT/", ".."));\r
+                       Assert.AreEqual ("~/", VPU.Combine ("~/ROOT/", "../"));\r
+                       Assert.AreEqual ("~/folder", VPU.Combine ("~/ROOT", "folder"));\r
+                       Assert.AreEqual ("~/ROOT/folder", VPU.Combine ("~/ROOT/", "folder"));\r
+                       Assert.AreEqual ("~/ROOT/folder/", VPU.Combine ("~/ROOT/", "folder/"));\r
+\r
+                       Assert.AreEqual ("/", VPU.Combine ("~", ".."));\r
+                       Assert.AreEqual ("~/me", VPU.Combine ("~", "me"));\r
+                       Assert.AreEqual ("/me", VPU.Combine ("~", "../me"));\r
+                       Assert.AreEqual ("~/me", VPU.Combine ("~", "./me"));\r
+                       \r
+                       Assert.AreEqual ("/me", VPU.Combine ("~/..", "me"));\r
+\r
+                       Assert.AreEqual ("/", VPU.Combine ("~/hi/there/..", ".."), "A1");\r
+                       Assert.AreEqual ("~", VPU.Combine ("~/hi/there/../", ".."), "A1");\r
+                       Assert.AreEqual ("/", VPU.Combine ("~/hi/there/../", "../.."), "A1");\r
+                       Assert.AreEqual ("~/hi/me", VPU.Combine ("~/hi/there/../", "me"), "A1");\r
+                       Assert.AreEqual ("~", VPU.Combine ("~/hi/there/../you", ".."), "A1");\r
+                       Assert.AreEqual ("~/hi/me", VPU.Combine ("~/hi/there/../you", "me"), "A1");\r
+                       Assert.AreEqual ("~/hi/you/me", VPU.Combine ("~/hi/there/../you/", "me"), "A1");\r
+                       \r
+                       Assert.AreEqual (HttpRuntime.AppDomainAppVirtualPath, VPU.Combine ("/ROOT", HttpRuntime.AppDomainAppVirtualPath));\r
+                       Assert.AreEqual (HttpRuntime.AppDomainAppVirtualPath, VPU.Combine ("~/ROOT", HttpRuntime.AppDomainAppVirtualPath));\r
                }\r
 \r
                [Test]\r
                [ExpectedException (typeof (ArgumentException))]\r
+               // The relative virtual path 'hi/there' is not allowed here.\r
                public void Combine_ArgException1 ()\r
                {\r
                        Assert.AreEqual ("hi/there/you", VPU.Combine ("hi/there", "you"), "A1");\r
@@ -69,11 +177,34 @@ namespace MonoTests.System.Web {
 \r
                [Test]\r
                [ExpectedException (typeof (ArgumentException))]\r
+               // The relative virtual path 'hi/there' is not allowed here.\r
                public void Combine_ArgException2 ()\r
                {\r
                        Assert.AreEqual ("hi/there", VPU.Combine ("hi/there", null), "A1");\r
                }\r
 \r
+               [Test]\r
+               [ExpectedException (typeof (ArgumentNullException))]\r
+               public void Combine_ArgException2_1 ()\r
+               {\r
+                       Assert.AreEqual ("hi/there", VPU.Combine ("/hi/there", null), "A1");\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (ArgumentException))]\r
+               // The relative virtual path 'hi/there' is not allowed here.\r
+               public void Combine_ArgException2_2 ()\r
+               {\r
+                       Assert.AreEqual ("hi/there", VPU.Combine ("hi/there", "/dir"), "A1");\r
+               }\r
+               \r
+               [Test]\r
+               [ExpectedException (typeof (HttpException))]\r
+               public void Combine_ArgException2_3 ()\r
+               {\r
+                       Assert.AreEqual ("hi/there", VPU.Combine ("/../hi", null), "A1");\r
+               }\r
+\r
                [Test]\r
                [ExpectedException (typeof (ArgumentNullException))]\r
                public void Combine_ArgException3 ()\r
@@ -104,6 +235,26 @@ namespace MonoTests.System.Web {
                {\r
                        Assert.AreEqual ("/hi", VPU.Combine ("/hi", ""), "A1");\r
                }\r
+               \r
+               [Test]\r
+               [ExpectedException (typeof (HttpException))]\r
+               public void Combine_ArgException6 ()\r
+               {\r
+                       VPU.Combine ("/ROOT", "..");\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (HttpException))]\r
+               public void Combine_ArgException7 ()\r
+               {\r
+                       VPU.Combine ("/ROOT", "/..");\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (HttpException))]\r
+               public void Combine_ArgException8 () {\r
+                       VPU.Combine ("/ROOT", "./..");\r
+               }\r
 \r
                [Test]\r
                public void GetDirectory ()\r
@@ -348,6 +499,10 @@ namespace MonoTests.System.Web {
                        VPU.MakeRelative ("", null);\r
                }\r
 \r
+               // LAMESPEC: MSDN: If the fromPath and toPath parameters are not rooted; that is, \r
+               // they do not equal the root operator (the tilde [~]), do not start with a tilde (~), \r
+               // such as a tilde and a slash mark (~/) or a tilde and a double backslash (~//), \r
+               // or do not start with a slash mark (/), an ArgumentException exception is thrown.\r
                [Test]\r
                [ExpectedException (typeof (ArgumentOutOfRangeException))]\r
                public void MakeRelative3 ()\r
@@ -373,9 +528,60 @@ namespace MonoTests.System.Web {
         [Category ("NotWorking")]\r
         public void MakeRelative6()\r
         {\r
-            //The test is not working due to the : System.URI.MakeRelativeUri - not implemented exception\r
-            Assert.AreEqual("./", VPU.MakeRelative("/", "/"));\r
-        }\r
+                       Assert.AreEqual ("./", VPU.MakeRelative ("/", "/"));\r
+                       Assert.AreEqual ("directory1", VPU.MakeRelative ("/directory1", "/directory1"));\r
+                       Assert.AreEqual ("directory2", VPU.MakeRelative ("/directory1", "/directory2"));\r
+                       Assert.AreEqual ("directory1", VPU.MakeRelative ("/", "/directory1"));\r
+                       Assert.AreEqual ("", VPU.MakeRelative ("/directory1", "/"));\r
+                       Assert.AreEqual ("./", VPU.MakeRelative ("/directory1/", "/directory1/"));\r
+                       Assert.AreEqual ("directory1/file1.aspx", VPU.MakeRelative ("/directory1", "/directory1/file1.aspx"));\r
+                       Assert.AreEqual ("file1.aspx", VPU.MakeRelative ("/directory1/file1.aspx", "/directory1/file1.aspx"));\r
+                       Assert.AreEqual ("file1.aspx", VPU.MakeRelative ("/directory1/", "/directory1/file1.aspx"));\r
+                       Assert.AreEqual ("../directory2/file2.aspx", VPU.MakeRelative ("/directory1/file1.aspx", "/directory2/file2.aspx"));\r
+               }\r
+\r
+               [Test]\r
+               [Category ("NotWorking")]\r
+               public void MakeRelative6_a ()\r
+               {\r
+                       Assert.AreEqual ("directory1", VPU.MakeRelative ("/directory1/../", "/directory1"));\r
+                       Assert.AreEqual ("", VPU.MakeRelative ("/directory1", "/directory1/../"));\r
+                       Assert.AreEqual ("./", VPU.MakeRelative ("/", "/directory1/../"));\r
+                       Assert.AreEqual ("directory1", VPU.MakeRelative ("/directory1", "/directory2/../directory1"));\r
+               }\r
+\r
+               [Test]\r
+               [Category ("NotWorking")]\r
+               [Category ("NunitWeb")]\r
+               public void MakeRelative7 ()\r
+               {\r
+                       new WebTest (PageInvoker.CreateOnLoad (MakeRelative7_Load)).Run (); \r
+               }\r
+\r
+               public static void MakeRelative7_Load (Page p)\r
+               {\r
+                       Assert.AreEqual ("./", VPU.MakeRelative ("~", "~"));\r
+                       Assert.AreEqual ("./", VPU.MakeRelative ("~/", "~/"));\r
+                       Assert.AreEqual ("./", VPU.MakeRelative ("~//", "~//"));\r
+                       Assert.AreEqual ("./", VPU.MakeRelative ("~", "~//"));\r
+                       Assert.AreEqual ("directory1", VPU.MakeRelative ("~/directory1", "~/directory1"));\r
+                       Assert.AreEqual ("directory2", VPU.MakeRelative ("~/directory1", "~/directory2"));\r
+                       Assert.AreEqual ("directory1", VPU.MakeRelative ("~/", "~/directory1"));\r
+                       Assert.AreEqual ("", VPU.MakeRelative ("~/directory1", "~/"));\r
+                       Assert.AreEqual ("./", VPU.MakeRelative ("~/directory1/", "~/directory1/"));\r
+                       Assert.AreEqual ("directory1/file1.aspx", VPU.MakeRelative ("~/directory1", "~/directory1/file1.aspx"));\r
+                       Assert.AreEqual ("file1.aspx", VPU.MakeRelative ("~/directory1/", "~/directory1/file1.aspx"));\r
+                       Assert.AreEqual ("../directory2/file2.aspx", VPU.MakeRelative ("~/directory1/file1.aspx", "~/directory2/file2.aspx"));\r
+\r
+                       Assert.AreEqual ("directory1", VPU.MakeRelative ("~/directory1/../", "~/directory1"));\r
+                       Assert.AreEqual ("", VPU.MakeRelative ("~/directory1", "~/directory1/../"));\r
+                       Assert.AreEqual ("./", VPU.MakeRelative ("~/", "~/directory1/../"));\r
+                       Assert.AreEqual ("directory1", VPU.MakeRelative ("~/directory1", "~/directory2/../directory1"));\r
+\r
+\r
+                       Assert.AreEqual ("../", VPU.MakeRelative ("~", "/"));\r
+                       Assert.AreEqual ("NunitWeb/", VPU.MakeRelative ("/", "~"));\r
+               }\r
 \r
                [Test]\r
                public void RemoveTrailingSlash2 ()\r
@@ -472,7 +678,8 @@ namespace MonoTests.System.Web {
                }\r
         public static void ToAbsolute7_Load(Page p)\r
         {\r
-            Assert.AreEqual("/", VPU.ToAbsolute("/"));\r
+                       Assert.AreEqual ("/", VPU.ToAbsolute ("/"));\r
+                       Assert.AreEqual ("/", VPU.ToAbsolute ("//"));\r
         }\r
                [Test]\r
                public void ToAbsolute8 ()\r
@@ -482,6 +689,26 @@ namespace MonoTests.System.Web {
                        Assert.AreEqual ("/blah/blah/", VPU.ToAbsolute ("/blah\\blah/", "/ROOT"));\r
                }\r
 \r
+               [Test]\r
+               public void ToAbsolute8_a ()\r
+               {\r
+                       Assert.AreEqual ("/blah2/", VPU.ToAbsolute ("/blah1/../blah2/", "/ROOT"));\r
+                       Assert.AreEqual ("/blah2/", VPU.ToAbsolute ("/blah1//../blah2/", "/ROOT"));\r
+                       Assert.AreEqual ("/blah2/", VPU.ToAbsolute ("/blah1/\\../blah2/", "/ROOT"));\r
+                       Assert.AreEqual ("/blah2/", VPU.ToAbsolute ("/blah1\\\\../blah2/", "/ROOT"));\r
+                       Assert.AreEqual ("/blah1/blah2/", VPU.ToAbsolute ("/blah1/./blah2/", "/ROOT"));\r
+\r
+                       Assert.AreEqual ("/blah1", VPU.ToAbsolute ("/blah1/blah2/..", "/ROOT"));\r
+                       Assert.AreEqual ("/", VPU.ToAbsolute ("/blah1/..", "/ROOT"));\r
+                       Assert.AreEqual ("/blah1/", VPU.ToAbsolute ("/blah1/blah2/../", "/ROOT"));\r
+                       Assert.AreEqual ("/", VPU.ToAbsolute ("/blah1/../", "/ROOT"));\r
+\r
+                       Assert.AreEqual ("/blah1", VPU.ToAbsolute ("/blah1/.", "/ROOT"));\r
+                       Assert.AreEqual ("/", VPU.ToAbsolute ("/.", "/ROOT"));\r
+                       Assert.AreEqual ("/blah1/", VPU.ToAbsolute ("/blah1/./", "/ROOT"));\r
+                       Assert.AreEqual ("/", VPU.ToAbsolute ("/./", "/ROOT"));\r
+               }\r
+\r
                [Test]\r
                public void ToAbsolute9 ()\r
                {\r
@@ -490,6 +717,117 @@ namespace MonoTests.System.Web {
                        Assert.AreEqual ("/ROOT/blah", VPU.ToAbsolute ("~/blah", "/ROOT/"));\r
                }\r
 \r
+               [Test]\r
+               public void ToAppRelative ()\r
+               {\r
+                       Assert.AreEqual ("~/hi", VPU.ToAppRelative ("~/hi", null));\r
+                       Assert.AreEqual ("~/hi", VPU.ToAppRelative ("~/hi", ""));\r
+                       Assert.AreEqual ("~/hi", VPU.ToAppRelative ("~/hi", "/.."));\r
+                       Assert.AreEqual ("~/hi", VPU.ToAppRelative ("~/hi", "me"));\r
+\r
+                       Assert.AreEqual ("~", VPU.ToAppRelative ("~", "/ROOT"));\r
+                       Assert.AreEqual ("~/", VPU.ToAppRelative ("~/", "/ROOT"));\r
+                       Assert.AreEqual ("~/blah", VPU.ToAppRelative ("~/blah", "/ROOT/"));\r
+                       Assert.AreEqual ("~/blah2/", VPU.ToAppRelative ("~/blah1/../blah2/", "/ROOT/"));\r
+\r
+                       Assert.AreEqual ("~/", VPU.ToAppRelative ("/ROOT", "/ROOT"));\r
+                       Assert.AreEqual ("~/", VPU.ToAppRelative ("/ROOT/", "/ROOT"));\r
+                       Assert.AreEqual ("~/blah/blah/", VPU.ToAppRelative ("/ROOT/blah//blah//", "/ROOT"));\r
+                       Assert.AreEqual ("~/blah/blah/", VPU.ToAppRelative ("/ROOT/blah\\blah/", "/ROOT"));\r
+\r
+                       Assert.AreEqual ("~/blah2/", VPU.ToAppRelative ("/ROOT/blah1/../blah2/", "/ROOT"));\r
+                       Assert.AreEqual ("~/blah1/blah2/", VPU.ToAppRelative ("/ROOT/blah1/./blah2/", "/ROOT"));\r
+\r
+                       Assert.AreEqual ("~/blah1", VPU.ToAppRelative ("/ROOT/blah1/blah2/..", "/ROOT"));\r
+                       Assert.AreEqual ("~/", VPU.ToAppRelative ("/ROOT/blah1/..", "/ROOT"));\r
+                       Assert.AreEqual ("~/blah1/", VPU.ToAppRelative ("/ROOT/blah1/blah2/../", "/ROOT"));\r
+                       Assert.AreEqual ("~/", VPU.ToAppRelative ("/ROOT/blah1/../", "/ROOT"));\r
+\r
+                       Assert.AreEqual ("~/blah1", VPU.ToAppRelative ("/ROOT/blah1/.", "/ROOT"));\r
+                       Assert.AreEqual ("~/", VPU.ToAppRelative ("/ROOT/.", "/ROOT"));\r
+                       Assert.AreEqual ("~/blah1/", VPU.ToAppRelative ("/ROOT/blah1/./", "/ROOT"));\r
+                       Assert.AreEqual ("~/", VPU.ToAppRelative ("/ROOT/./", "/ROOT"));\r
+\r
+                       Assert.AreEqual ("~/ROOT", VPU.ToAppRelative ("/ROOT", "/"));\r
+                       Assert.AreEqual ("~/ROOT", VPU.ToAppRelative ("/ROOT", "/hi/.."));\r
+                       Assert.AreEqual ("~/ROOT", VPU.ToAppRelative ("/ROOT/hi/..", "/"));\r
+               }\r
+\r
+               [Test]\r
+               public void ToAppRelative2 ()\r
+               {\r
+                       new WebTest (PageInvoker.CreateOnLoad (ToAppRelative2_Load)).Run ();\r
+               }\r
+               \r
+               public static void ToAppRelative2_Load (Page p)\r
+               {\r
+                       Assert.AreEqual ("~/hi", VPU.ToAppRelative ("~/../NunitWeb/hi", "/NunitWeb"));\r
+               }\r
+               \r
+               [Test]\r
+               [ExpectedException(typeof(ArgumentNullException))]\r
+               public void ToAppRelative_Exc1 ()\r
+               {\r
+                       VPU.ToAppRelative ("/ROOT/hi", "");\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (ArgumentNullException))]\r
+               public void ToAppRelative_Exc2 ()\r
+               {\r
+                       VPU.ToAppRelative ("/ROOT/hi", null);\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (ArgumentException))]\r
+               public void ToAppRelative_Exc3 ()\r
+               {\r
+                       VPU.ToAppRelative ("/ROOT/hi", "hi");\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (HttpException))]\r
+               public void ToAppRelative_Exc4 () {\r
+                       VPU.ToAppRelative ("/ROOT/hi", "/../hi");\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (ArgumentNullException))]\r
+               public void ToAppRelative_Exc5 ()\r
+               {\r
+                       VPU.ToAppRelative (null, "/ROOT");\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (ArgumentNullException))]\r
+               public void ToAppRelative_Exc6 ()\r
+               {\r
+                       VPU.ToAppRelative ("", "/ROOT");\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (ArgumentException))]\r
+               //The relative virtual path 'hi' is not allowed here.\r
+               public void ToAppRelative_Exc7 ()\r
+               {\r
+                       VPU.ToAppRelative ("hi", "/ROOT");\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (ArgumentException))]\r
+               //The relative virtual path 'hi' is not allowed here.\r
+               public void ToAppRelative_Exc7_a ()\r
+               {\r
+                       VPU.ToAppRelative ("hi", null);\r
+               }\r
+\r
+               [Test]\r
+               [ExpectedException (typeof (HttpException))]\r
+               public void ToAppRelative_Exc8 ()\r
+               {\r
+                       VPU.ToAppRelative ("/../ROOT/hi", "/ROOT");\r
+               }\r
+\r
                [Test]\r
                [ExpectedException (typeof (ArgumentException))]\r
                public void ToAbsolute10 ()\r