PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/System/System/UriParser.cs

https://bitbucket.org/cosi2/dotnetanywhere-wb
C# | 365 lines | 281 code | 56 blank | 28 comment | 77 complexity | 02ae05780283ee77c28de187b1fd673c MD5 | raw file
  1. using System.Collections;
  2. using System.Globalization;
  3. //using System.Security.Permissions;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. using System.Collections.Generic;
  7. namespace System
  8. {
  9. public class UriFormatException : FormatException
  10. {
  11. public UriFormatException(): base(){}
  12. public UriFormatException(string m): base(m) {}
  13. }
  14. public enum UriHostNameType
  15. {
  16. Unknown,
  17. Basic,
  18. Dns,
  19. IPv4,
  20. IPv6
  21. }
  22. public enum UriPartial
  23. {
  24. Scheme,
  25. Authority,
  26. Path,
  27. Query
  28. }
  29. public abstract class UriParser
  30. {
  31. static object lock_object = new object();
  32. static Dictionary<String,UriParser> table;
  33. internal string scheme_name;
  34. private int default_port;
  35. // Regexp from RFC 2396
  36. #if NET_2_1
  37. readonly static Regex uri_regex = new Regex (@"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?");
  38. #else
  39. // Groups: 12 3 4 5 6 7 8 9
  40. readonly static Regex uri_regex = new Regex(@"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?", RegexOptions.Compiled);
  41. #endif
  42. // Groups: 12 3 4 5
  43. readonly static Regex auth_regex = new Regex(@"^(([^@]+)@)?(.*?)(:([0-9]+))?$");
  44. protected UriParser()
  45. {
  46. }
  47. static Match ParseAuthority(Group g)
  48. {
  49. return auth_regex.Match(g.Value);
  50. }
  51. // protected methods
  52. protected internal virtual string GetComponents(Uri uri, UriComponents components, UriFormat format)
  53. {
  54. if ((format < UriFormat.UriEscaped) || (format > UriFormat.SafeUnescaped))
  55. throw new ArgumentOutOfRangeException("format");
  56. Match m = uri_regex.Match(uri.OriginalString.Trim());
  57. string scheme = scheme_name;
  58. int dp = default_port;
  59. if ((scheme == null) || (scheme == "*"))
  60. {
  61. scheme = m.Groups[2].Value;
  62. dp = Uri.GetDefaultPort(scheme);
  63. }
  64. else if (String.Compare(scheme, m.Groups[2].Value, true) != 0)
  65. {
  66. throw new SystemException("URI Parser: scheme mismatch: " + scheme + " vs. " + m.Groups[2].Value);
  67. }
  68. // it's easier to answer some case directly (as the output isn't identical
  69. // when mixed with others components, e.g. leading slash, # ...)
  70. switch (components)
  71. {
  72. case UriComponents.Scheme:
  73. return scheme;
  74. case UriComponents.UserInfo:
  75. return ParseAuthority(m.Groups[4]).Groups[2].Value;
  76. case UriComponents.Host:
  77. return ParseAuthority(m.Groups[4]).Groups[3].Value;
  78. case UriComponents.Port:
  79. {
  80. string p = ParseAuthority(m.Groups[4]).Groups[5].Value;
  81. if (p != null && p != String.Empty && p != dp.ToString())
  82. return p;
  83. return String.Empty;
  84. }
  85. case UriComponents.Path:
  86. return Format(IgnoreFirstCharIf(m.Groups[5].Value, '/'), format);
  87. case UriComponents.Query:
  88. return Format(m.Groups[7].Value, format);
  89. case UriComponents.Fragment:
  90. return Format(m.Groups[9].Value, format);
  91. case UriComponents.StrongPort:
  92. {
  93. Group g = ParseAuthority(m.Groups[4]).Groups[5];
  94. return g.Success ? g.Value : dp.ToString();
  95. }
  96. case UriComponents.SerializationInfoString:
  97. components = UriComponents.AbsoluteUri;
  98. break;
  99. }
  100. Match am = ParseAuthority(m.Groups[4]);
  101. // now we deal with multiple flags...
  102. StringBuilder sb = new StringBuilder();
  103. if ((components & UriComponents.Scheme) != 0)
  104. {
  105. sb.Append(scheme);
  106. sb.Append(Uri.GetSchemeDelimiter(scheme));
  107. }
  108. if ((components & UriComponents.UserInfo) != 0)
  109. sb.Append(am.Groups[1].Value);
  110. if ((components & UriComponents.Host) != 0)
  111. sb.Append(am.Groups[3].Value);
  112. // for StrongPort always show port - even if -1
  113. // otherwise only display if ut's not the default port
  114. if ((components & UriComponents.StrongPort) != 0)
  115. {
  116. Group g = am.Groups[4];
  117. sb.Append(g.Success ? g.Value : ":" + dp);
  118. }
  119. if ((components & UriComponents.Port) != 0)
  120. {
  121. string p = am.Groups[5].Value;
  122. if (p != null && p != String.Empty && p != dp.ToString())
  123. sb.Append(am.Groups[4].Value);
  124. }
  125. if ((components & UriComponents.Path) != 0)
  126. {
  127. if ((components & UriComponents.PathAndQuery) != 0 &&
  128. (m.Groups[5].Value == null || !m.Groups[5].Value.StartsWith("/")))
  129. sb.Append("/");
  130. sb.Append(m.Groups[5]);
  131. }
  132. if ((components & UriComponents.Query) != 0)
  133. sb.Append(m.Groups[6]);
  134. string result = Format(sb.ToString(), format);
  135. if ((components & UriComponents.Fragment) != 0)
  136. {
  137. string f = m.Groups[8].Value;
  138. if (!String.IsNullOrEmpty(f))
  139. {
  140. // make sure the '#' does not get escaped by 'format'
  141. f = f.Substring(1);
  142. result += "#" + Format(f, format);
  143. }
  144. }
  145. return result;
  146. }
  147. protected internal virtual void InitializeAndValidate(Uri uri, out UriFormatException parsingError)
  148. {
  149. // bad boy, it should check null arguments.
  150. if ((uri.Scheme != scheme_name) && (scheme_name != "*"))
  151. // Here .NET seems to return "The Authority/Host could not be parsed", but it does not make sense.
  152. parsingError = new UriFormatException("The argument Uri's scheme does not match");
  153. else
  154. parsingError = null;
  155. }
  156. #if NET_2_0
  157. protected internal virtual bool IsBaseOf (Uri baseUri, Uri relativeUri)
  158. {
  159. // compare, not case sensitive, the scheme, host and port (+ user informations)
  160. if (Uri.Compare (baseUri, relativeUri, UriComponents.SchemeAndServer | UriComponents.UserInfo, UriFormat.Unescaped, StringComparison.InvariantCultureIgnoreCase) != 0)
  161. return false;
  162. string base_string = baseUri.LocalPath;
  163. int last_slash = base_string.LastIndexOf ('/') + 1; // keep the slash
  164. return (String.Compare (base_string, 0, relativeUri.LocalPath, 0, last_slash, StringComparison.InvariantCultureIgnoreCase) == 0);
  165. }
  166. protected internal virtual bool IsWellFormedOriginalString (Uri uri)
  167. {
  168. // well formed according to RFC2396 and RFC2732
  169. // see Uri.IsWellFormedOriginalString for some docs
  170. // Though this class does not seem to do anything. Even null arguments aren't checked :/
  171. return uri.IsWellFormedOriginalString ();
  172. }
  173. #endif
  174. protected internal virtual UriParser OnNewUri()
  175. {
  176. // nice time for init
  177. return this;
  178. }
  179. [NotImplemented]
  180. protected virtual void OnRegister(string schemeName, int defaultPort)
  181. {
  182. // unit tests shows that schemeName and defaultPort aren't usable from here
  183. }
  184. [NotImplemented]
  185. protected internal virtual string Resolve(Uri baseUri, Uri relativeUri, out UriFormatException parsingError)
  186. {
  187. // used by Uri.ctor and Uri.TryCreate
  188. throw new NotImplementedException();
  189. }
  190. // internal properties
  191. internal string SchemeName
  192. {
  193. get { return scheme_name; }
  194. set { scheme_name = value; }
  195. }
  196. internal int DefaultPort
  197. {
  198. get { return default_port; }
  199. set { default_port = value; }
  200. }
  201. // private stuff
  202. private string IgnoreFirstCharIf(string s, char c)
  203. {
  204. if (s.Length == 0)
  205. return String.Empty;
  206. if (s[0] == c)
  207. return s.Substring(1);
  208. return s;
  209. }
  210. private string Format(string s, UriFormat format)
  211. {
  212. if (s.Length == 0)
  213. return String.Empty;
  214. switch (format)
  215. {
  216. case UriFormat.UriEscaped:
  217. return Uri.EscapeString(s, Uri.EscapeCommonHexBrackets);
  218. case UriFormat.SafeUnescaped:
  219. return Uri.UnescapeDataString(s, true);
  220. case UriFormat.Unescaped:
  221. return Uri.Unescape(s, false);
  222. default:
  223. throw new ArgumentOutOfRangeException("format");
  224. }
  225. }
  226. // static methods
  227. private static void CreateDefaults()
  228. {
  229. if (table != null)
  230. return;
  231. var newtable = new Dictionary<string,UriParser>();
  232. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeFile, -1);
  233. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeFtp, 21);
  234. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeGopher, 70);
  235. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeHttp, 80);
  236. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeHttps, 443);
  237. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeMailto, 25);
  238. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeNetPipe, -1);
  239. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeNetTcp, -1);
  240. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeNews, -1);
  241. InternalRegister(newtable, new DefaultUriParser(), Uri.UriSchemeNntp, 119);
  242. // not defined in Uri.UriScheme* but a parser class exists
  243. InternalRegister(newtable, new DefaultUriParser(), "ldap", 389);
  244. lock (lock_object)
  245. {
  246. if (table == null)
  247. table = newtable;
  248. else
  249. newtable = null;
  250. }
  251. }
  252. public static bool IsKnownScheme(string schemeName)
  253. {
  254. if (schemeName == null)
  255. throw new ArgumentNullException("schemeName");
  256. if (schemeName.Length == 0)
  257. throw new ArgumentOutOfRangeException("schemeName");
  258. CreateDefaults();
  259. string lc = schemeName.ToLower(CultureInfo.InvariantCulture);
  260. return (table[lc] != null);
  261. }
  262. // *no* check version
  263. private static void InternalRegister(Dictionary<String,UriParser> table, UriParser uriParser, string schemeName, int defaultPort)
  264. {
  265. uriParser.SchemeName = schemeName;
  266. uriParser.DefaultPort = defaultPort;
  267. // FIXME: MS doesn't seems to call most inherited parsers
  268. if (uriParser is GenericUriParser)
  269. {
  270. table.Add(schemeName, uriParser);
  271. }
  272. else
  273. {
  274. DefaultUriParser parser = new DefaultUriParser();
  275. parser.SchemeName = schemeName;
  276. parser.DefaultPort = defaultPort;
  277. table.Add(schemeName, parser);
  278. }
  279. // note: we cannot set schemeName and defaultPort inside OnRegister
  280. uriParser.OnRegister(schemeName, defaultPort);
  281. }
  282. // [SecurityPermission(SecurityAction.Demand, Infrastructure = true)]
  283. public static void Register(UriParser uriParser, string schemeName, int defaultPort)
  284. {
  285. if (uriParser == null)
  286. throw new ArgumentNullException("uriParser");
  287. if (schemeName == null)
  288. throw new ArgumentNullException("schemeName");
  289. if ((defaultPort < -1) || (defaultPort >= UInt16.MaxValue))
  290. throw new ArgumentOutOfRangeException("defaultPort");
  291. CreateDefaults();
  292. string lc = schemeName.ToLower(CultureInfo.InvariantCulture);
  293. if (table[lc] != null)
  294. {
  295. string msg = String.Format("Scheme '{0}' is already registred.",schemeName);
  296. throw new InvalidOperationException(msg);
  297. }
  298. InternalRegister(table, uriParser, lc, defaultPort);
  299. }
  300. internal static UriParser GetParser(string schemeName)
  301. {
  302. if (schemeName == null)
  303. return null;
  304. CreateDefaults();
  305. string lc = schemeName.ToLower(CultureInfo.InvariantCulture);
  306. return (UriParser)table[lc];
  307. }
  308. }
  309. }