2004-06-09 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System / System / Uri.cs
index ba6680e35534a9b3fbbe788cc6429c315a705cb9..ddec91998adac4327992ea181c218c6c60e5db64 100755 (executable)
@@ -17,6 +17,7 @@
 using System.Net;
 using System.Runtime.Serialization;
 using System.Text;
+using System.Collections;
 
 // See RFC 2396 for more info on URI's.
 
@@ -95,8 +96,6 @@ namespace System
 
                        host = EscapeString (host, false, true, false);
                        path = EscapeString (path);
-                       query = EscapeString (query);
-                       fragment = EscapeString (fragment, false, false, true);
                }
 
                public Uri (Uri baseUri, string relativeUri) 
@@ -113,25 +112,9 @@ namespace System
 
                        userEscaped = dontEscape;
 
-                       this.scheme = baseUri.scheme;
-                       this.host = baseUri.host;
-                       this.port = baseUri.port;
-                       this.userinfo = baseUri.userinfo;
-                       this.isUnc = baseUri.isUnc;
-                       this.isWindowsFilePath = baseUri.isWindowsFilePath;
-                       this.isUnixFilePath = baseUri.isUnixFilePath;
-                       this.isOpaquePart = baseUri.isOpaquePart;
-
                        if (relativeUri == null)
                                throw new NullReferenceException ("relativeUri");
 
-                       if (relativeUri == String.Empty) {
-                               this.path = baseUri.path;
-                               this.query = baseUri.query;
-                               this.fragment = baseUri.fragment;
-                               return;
-                       }
-
                        int pos = relativeUri.IndexOf (':');
                        if (pos != -1) {
 
@@ -146,18 +129,30 @@ namespace System
 
                                        host = EscapeString (host, false, true, false);
                                        path = EscapeString (path);
-                                       query = EscapeString (query);
-                                       fragment = EscapeString (fragment, false, false, true);
                                        return;
                                }
                        }
 
+                       this.scheme = baseUri.scheme;
+                       this.host = baseUri.host;
+                       this.port = baseUri.port;
+                       this.userinfo = baseUri.userinfo;
+                       this.isUnc = baseUri.isUnc;
+                       this.isWindowsFilePath = baseUri.isWindowsFilePath;
+                       this.isUnixFilePath = baseUri.isUnixFilePath;
+                       this.isOpaquePart = baseUri.isOpaquePart;
+
+                       if (relativeUri == String.Empty) {
+                               this.path = baseUri.path;
+                               this.query = baseUri.query;
+                               this.fragment = baseUri.fragment;
+                               return;
+                       }
+                       
                        // 8 fragment
                        pos = relativeUri.IndexOf ('#');
                        if (pos != -1) {
                                fragment = relativeUri.Substring (pos);
-                               if (!userEscaped)
-                                       fragment = EscapeString (fragment, false, false, true);
                                relativeUri = relativeUri.Substring (0, pos);
                        }
 
@@ -245,15 +240,18 @@ namespace System
                }               
                
                // Properties
-               
+
                public string AbsolutePath { 
                        get { return path; } 
                }
 
                public string AbsoluteUri { 
-                       get { 
-                               if (cachedAbsoluteUri == null)
-                                       cachedAbsoluteUri = GetLeftPart (UriPartial.Path) + query + fragment;
+                       get {
+                               if (cachedAbsoluteUri == null) {
+//                                     cachedAbsoluteUri = GetLeftPart (UriPartial.Path) + query + fragment;
+                                       string qf = IsFile ? query + fragment : EscapeString (query + fragment);
+                                       cachedAbsoluteUri = GetLeftPart (UriPartial.Path) + qf;
+                               }
                                return cachedAbsoluteUri;
                        } 
                }
@@ -301,7 +299,8 @@ namespace System
                                        return true;
                                        
                                try {
-                                       return IPAddress.IsLoopback (IPAddress.Parse (host));
+                                       if (IPAddress.Loopback.Equals (IPAddress.Parse (host)))
+                                               return true;
                                } catch (FormatException) {}
 
                                try {
@@ -323,9 +322,13 @@ namespace System
                        get {
                                if (!IsFile)
                                        return path;
+
+                               bool windows = (path.Length > 3 && path [1] == ':' &&
+                                               (path [2] == '\\' || path [2] == '/'));
+
                                if (!IsUnc) {
                                        string p = Unescape (path);
-                                       if (System.IO.Path.DirectorySeparatorChar == '\\')
+                                       if (System.IO.Path.DirectorySeparatorChar == '\\' || windows)
                                                return p.Replace ('/', '\\');
                                        else
                                                return p;
@@ -510,12 +513,12 @@ namespace System
                                uri = new Uri (s);
                        }
                        
-                       return ((this.scheme == uri.scheme) &&
-                               (this.userinfo == uri.userinfo) &&
-                               (this.host == uri.host) &&
-                               (this.port == uri.port) &&
-                               (this.path == uri.path) &&
-                               (this.query == uri.query));
+                       return ((this.scheme.ToLower () == uri.scheme.ToLower ()) &&
+                               (this.userinfo.ToLower () == uri.userinfo.ToLower ()) &&
+                               (this.host.ToLower () == uri.host.ToLower ()) &&
+                               (this.port == uri.port) &&
+                               (this.path == uri.path) &&
+                               (this.query.ToLower () == uri.query.ToLower ()));
                }               
                
                public override int GetHashCode () 
@@ -665,10 +668,7 @@ namespace System
                {
                        if (cachedToString != null) 
                                return cachedToString;
-                       if (IsFile && !IsUnc)
-                               cachedToString = Unescape (AbsoluteUri);
-                       else
-                               cachedToString = AbsoluteUri;
+                       cachedToString = Unescape (AbsoluteUri);
 
                        return cachedToString;
                }
@@ -697,10 +697,11 @@ namespace System
                        if (str == null)
                                return String.Empty;
                        
+                       byte [] data = Encoding.UTF8.GetBytes (str.ToCharArray ());
                        StringBuilder s = new StringBuilder ();
-                       int len = str.Length;   
+                       int len = data.Length;  
                        for (int i = 0; i < len; i++) {
-                               char c = str [i];
+                               char c = (char) data [i];
                                // reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
                                // mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
                                // control     = <US-ASCII coded characters 00-1F and 7F hexadecimal>
@@ -755,7 +756,7 @@ namespace System
                                        s.Append (HexUnescape (str, ref i));
                                        i--;
                                } else
-                                       s.Append (c);                                   
+                                       s.Append (c);
                        }
                        return s.ToString ();
                }
@@ -925,8 +926,50 @@ namespace System
                        } else if (scheme == UriSchemeFile) {
                                isUnc = true;
                        }
+
+                       if ((scheme != Uri.UriSchemeMailto) &&
+                                       (scheme != Uri.UriSchemeNews) &&
+                                       (scheme != Uri.UriSchemeFile))
+                       path = Reduce (path);
                }
 
+               private static string Reduce (string path)
+               {
+                       path = path.Replace ('\\','/');
+                       string [] parts = path.Split ('/');
+                       ArrayList result = new ArrayList ();
+
+                       int end = parts.Length;
+                       for (int i = 0; i < end; i++) {
+                               string current = parts [i];
+                               if (current == "" || current == "." )
+                                       continue;
+
+                               if (current == "..") {
+                                       if (result.Count == 0) {
+                                               if (i == 1) // see bug 52599
+                                                       continue;
+                                               throw new Exception ("Invalid path.");
+                                       }
+
+                                       result.RemoveAt (result.Count - 1);
+                                       continue;
+                               }
+
+                               result.Add (current);
+                       }
+
+                       if (result.Count == 0)
+                               return "/";
+
+                       result.Insert (0, "");
+
+                       string res = String.Join ("/", (string []) result.ToArray (typeof (string)));
+                       if (path.EndsWith ("/"))
+                               res += '/';
+                               
+                       return res;
+               }
                                
                private struct UriScheme 
                {