Hey,

In .NET 2.0, Uri parsing has been moved to designated classes all derived
from UriParser. This makes it possible to have custom parsers for new Uri
schemes. Currently mono doesn't support this properly.

What I think would be the best thing to do would be to change parsing under
all profiles to use this new API. In the .NET 1.1 profile, we'd just mark
these classes as internal, so this gives one codepath to maintain.

In .NET 1.1 Uri.Parse () would would be replaced by calls to the new parser
classes so that existing behaviour isn't changed. Under .NET 2.0, I believe
an approach similar to what I've prototyped in the attached patch should be
what is implemented. Basically each of the properties of Uri will call into
the parser to get the required component. The results of this call could be
cached locally for increased performance.

The other benefit is that it should also reduce the shotgun approach to
parsing, i.e. the special casing in the parse logic for different schemes.
This might make things more maintainable.

An example parser is also attached in Test.cs and is implemented as a
console app. If you apply the above patch to mono, you can parse the "pack"
schema. Note, the patch *will* break all other Uri parsing as i hardcoded a
"pack" parser.

Does anyone have any thoughts on this?

Alan.
Index: System/Uri.cs
===================================================================
--- System/Uri.cs	(revision 117256)
+++ System/Uri.cs	(working copy)
@@ -116,6 +116,7 @@
 
 		public Uri (string uriString) : this (uriString, false) 
 		{
+				Parser = UriParser.GetParser ("pack");
 		}
 
 		protected Uri (SerializationInfo serializationInfo, 
@@ -405,22 +406,7 @@
 		public string AbsolutePath { 
 			get {
 #if NET_2_0
-				EnsureAbsoluteUri ();
-				switch (Scheme) {
-				case "mailto":
-				case "file":
-					// faster (mailto) and special (file) cases
-					return path;
-				default:
-					if (path.Length == 0) {
-						string start = Scheme + SchemeDelimiter;
-						if (path.StartsWith (start))
-							return "/";
-						else
-							return String.Empty;
-					}
-					return path;
-				}
+				return GetComponents (UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.Unescaped);
 #else
 				return path;
 #endif
@@ -428,7 +414,10 @@
 		}
 
 		public string AbsoluteUri { 
-			get { 
+			get {
+#if NET_2_0
+				return GetComponents (UriComponents.AbsoluteUri, UriFormat.Unescaped);
+#else
 				EnsureAbsoluteUri ();
 				if (cachedAbsoluteUri == null) {
 					cachedAbsoluteUri = GetLeftPart (UriPartial.Path);
@@ -438,28 +427,42 @@
 						cachedAbsoluteUri += fragment;
 				}
 				return cachedAbsoluteUri;
+#endif
 			} 
 		}
 
 		public string Authority { 
-			get { 
+			get {
+#if NET_2_0
+				return GetComponents (UriComponents.HostAndPort, UriFormat.Unescaped);
+#else
 				EnsureAbsoluteUri ();
 				return (GetDefaultPort (Scheme) == port)
 				     ? host : host + ":" + port;
-			} 
+#endif
+			}
+
 		}
 
 		public string Fragment { 
-			get { 
+			get {
+#if NET_2_0
+				return GetComponents (UriComponents.Fragment | UriComponents.KeepDelimiter, UriFormat.Unescaped);
+#else
 				EnsureAbsoluteUri ();
-				return fragment; 
+				return fragment;
+#endif
 			} 
 		}
 
 		public string Host { 
-			get { 
+			get {
+#if NET_2_0
+				return GetComponents (UriComponents.Host, UriFormat.Unescaped);
+#else
 				EnsureAbsoluteUri ();
-				return host; 
+				return host;
+#endif
 			} 
 		}
 
@@ -485,8 +488,13 @@
 
 		public bool IsDefaultPort { 
 			get {
+#if NET_2_0
+				string s = GetComponents (UriComponents.Port, UriFormat.Unescaped);
+				return s == "" ? true : int.Parse (s) == Parser.DefaultPort;
+#else
 				EnsureAbsoluteUri ();
 				return GetDefaultPort (Scheme) == port;
+#endif
 			}
 		}
 
@@ -590,29 +598,46 @@
 
 		public string PathAndQuery { 
 			get {
+#if NET_2_0
+				return GetComponents (UriComponents.PathAndQuery, UriFormat.Unescaped);
+#else
 				EnsureAbsoluteUri ();
 				return path + Query;
+#endif
 			} 
 		}
 
 		public int Port { 
-			get { 
+			get {
+#if NET_2_0
+				string s = GetComponents (UriComponents.Port, UriFormat.Unescaped);
+				return s == "" ? Parser.DefaultPort : int.Parse (s);
+#else
 				EnsureAbsoluteUri ();
-				return port; 
+				return port;
+#endif
 			} 
 		}
 
 		public string Query { 
-			get { 
+			get {
+#if NET_2_0
+				return GetComponents (UriComponents.Query | UriComponents.KeepDelimiter, UriFormat.Unescaped);
+#else
 				EnsureAbsoluteUri ();
-				return query; 
+				return query;
+#endif
 			}
 		}
 
 		public string Scheme { 
-			get { 
+			get {
+#if NET_2_0
+				return GetComponents (UriComponents.Scheme, UriFormat.Unescaped);
+#else
 				EnsureAbsoluteUri ();
-				return scheme; 
+				return scheme;
+#endif
 			} 
 		}
 
@@ -1295,13 +1320,21 @@
 		// This parse method will throw exceptions on failure
 		//  
 		private void Parse (UriKind kind, string uriString)
-		{			
+		{
+#if NET_2_0
+			if (Parser == null)
+			{
+				if (UriParser.IsKnownScheme (uriString.Substring(0, uriString.IndexOf (':'))))
+					Parser = UriParser.GetParser (uriString.Substring(0, uriString.IndexOf (':')));
+			}
+#else
 			if (uriString == null)
 				throw new ArgumentNullException ("uriString");
 
 			string s = ParseNoExceptions (kind, uriString);
 			if (s != null)
 				throw new UriFormatException (s);
+#endif
 		}
 
 		//
@@ -1838,8 +1871,6 @@
 
 		private UriParser Parser {
 			get {
-				if (parser == null)
-					parser = UriParser.GetParser (Scheme);
 				return parser;
 			}
 			set { parser = value; }
using System;
using System.Collections.Generic;
using System.Text;


namespace UriTests
{

    class PackUriParser : System.GenericUriParser
    {
        const string SchemaName = "pack";

        StringBuilder builder = new StringBuilder();

        public PackUriParser ()
            : base (GenericUriParserOptions.Default)
        {
        }
        
        protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
        {
            string s = uri.OriginalString;
            builder.Remove(0, builder.Length);

            if ((components & UriComponents.Scheme) == UriComponents.Scheme)
            {
                int start = 0;
                int end = s.IndexOf(':');
                builder.Append(s, start, end - start);
            }

            if ((components & UriComponents.Host) == UriComponents.Host)
            {
                // Skip past pack://
                int start = 7;
                int end = s.IndexOf('/', start);
                if (end == -1)
                    end = s.Length;

                if (builder.Length > 0)
                    builder.Append("://");

                builder.Append(s, start, end - start);
            }

            // Port is always -1, so i think i can ignore both Port and StrongPort
            // Normally they'd get parsed here

            if ((components & UriComponents.Path) == UriComponents.Path)
            {
                // Skip past pack://
                int start = s.IndexOf('/', 7);
                int end = s.IndexOf('?');
                if (end == -1)
                    end = s.IndexOf('#');
                if (end == -1)
                    end = s.Length;

                if ((components & UriComponents.KeepDelimiter) != UriComponents.KeepDelimiter &&
                    builder.Length == 0)
                    start++;

                builder.Append(s, start, end - start);
            }

            if ((components & UriComponents.Query) == UriComponents.Query)
            {
                int index = s.IndexOf('?');
                if (index == -1)
                    return null;

                if ((components & UriComponents.KeepDelimiter) != UriComponents.KeepDelimiter &&
                    builder.Length == 0)
                    index++;

                int fragIndex = s.IndexOf('#');
                int end = fragIndex == -1 ? s.Length : fragIndex;
                builder.Append(s, index, end - index);
            }

            if ((components & UriComponents.Fragment) == UriComponents.Fragment)
            {
                int index = s.IndexOf('#');
                if (index == -1)
                    return null;

                if ((components & UriComponents.KeepDelimiter) != UriComponents.KeepDelimiter &&
                    builder.Length == 0)
                    index++;

                builder.Append(s, index, s.Length - index);
            }

            return builder.ToString();
        }
        
        protected override void InitializeAndValidate(Uri uri, out UriFormatException parsingError)
        {
            parsingError = null;
        }

        protected override UriParser OnNewUri()
        {
            return new PackUriParser();
        }
    }

	class MainClass
	{
		public static void Main(string[] args)
		{
			UriParser.Register (new PackUriParser (), "pack", -1);
			string s = "pack://http:,,original.com,blah,/path/tfile.tmp?query=blah#fragment";
        		Uri u = new Uri(s);
			Console.WriteLine ("Port: {0}", u.Port);
			Console.WriteLine ("AbsoluteUri: {0}", u.AbsoluteUri);
			Console.WriteLine ("PathAndQuery: {0}", u.PathAndQuery);
			Console.WriteLine ("Query: {0}", u.Query);
		}
	}
}
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to