PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/System/System/Uri.cs

https://bitbucket.org/cosi2/dotnetanywhere-wb
C# | 2543 lines | 2186 code | 167 blank | 190 comment | 459 complexity | 02dff9ea78601b7faea675060a1ee586 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. using System.ComponentModel;
  2. using System.IO;
  3. using System.Net;
  4. //using System.Runtime.Serialization;
  5. using System.Text;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Globalization;
  9. //
  10. // Disable warnings on Obsolete methods being used
  11. //
  12. #pragma warning disable 612
  13. namespace System
  14. {
  15. //[Serializable]
  16. // [TypeConverter(typeof(UriTypeConverter))]
  17. public class Uri //: ISerializable
  18. {
  19. // NOTES:
  20. // o scheme excludes the scheme delimiter
  21. // o port is -1 to indicate no port is defined
  22. // o path is empty or starts with / when scheme delimiter == "://"
  23. // o query is empty or starts with ? char, escaped.
  24. // o fragment is empty or starts with # char, unescaped.
  25. // o all class variables are in escaped format when they are escapable,
  26. // except cachedToString.
  27. // o UNC is supported, as starts with "\\" for windows,
  28. // or "//" with unix.
  29. private bool isUnixFilePath;
  30. private string source;
  31. private string scheme = String.Empty;
  32. private string host = String.Empty;
  33. private int port = -1;
  34. private string path = String.Empty;
  35. private string query = String.Empty;
  36. private string fragment = String.Empty;
  37. private string userinfo;
  38. private bool isUnc;
  39. private bool isOpaquePart;
  40. private bool isAbsoluteUri = true;
  41. private long scope_id;
  42. private List<string> segments;
  43. private bool userEscaped;
  44. private string cachedAbsoluteUri;
  45. private string cachedToString;
  46. private string cachedLocalPath;
  47. private int cachedHashCode;
  48. private static readonly string hexUpperChars = "0123456789ABCDEF";
  49. private static readonly string[] Empty = new string[0];
  50. private static bool isWin32 = (Path.DirectorySeparatorChar == '\\');
  51. // Fields
  52. public static readonly string SchemeDelimiter = "://";
  53. public static readonly string UriSchemeFile = "file";
  54. public static readonly string UriSchemeFtp = "ftp";
  55. public static readonly string UriSchemeGopher = "gopher";
  56. public static readonly string UriSchemeHttp = "http";
  57. public static readonly string UriSchemeHttps = "https";
  58. public static readonly string UriSchemeMailto = "mailto";
  59. public static readonly string UriSchemeNews = "news";
  60. public static readonly string UriSchemeNntp = "nntp";
  61. public static readonly string UriSchemeNetPipe = "net.pipe";
  62. public static readonly string UriSchemeNetTcp = "net.tcp";
  63. // Constructors
  64. #if MOONLIGHT
  65. public Uri (string uriString) : this (uriString, UriKind.Absolute)
  66. {
  67. }
  68. #else
  69. public Uri(string uriString)
  70. : this(uriString, false)
  71. {
  72. }
  73. #endif
  74. //protected Uri(SerializationInfo serializationInfo, StreamingContext streamingContext)
  75. //{
  76. // string uri = serializationInfo.GetString("AbsoluteUri");
  77. // if (uri.Length > 0)
  78. // {
  79. // source = uri;
  80. // ParseUri(UriKind.Absolute);
  81. // }
  82. // else
  83. // {
  84. // uri = serializationInfo.GetString("RelativeUri");
  85. // if (uri.Length > 0)
  86. // {
  87. // source = uri;
  88. // ParseUri(UriKind.Relative);
  89. // }
  90. // else
  91. // {
  92. // throw new ArgumentException("Uri string was null or empty.");
  93. // }
  94. // }
  95. //}
  96. public Uri(string uriString, UriKind uriKind)
  97. {
  98. source = uriString;
  99. ParseUri(uriKind);
  100. switch (uriKind)
  101. {
  102. case UriKind.Absolute:
  103. if (!IsAbsoluteUri)
  104. throw new UriFormatException("Invalid URI: The format of the URI could not be "
  105. + "determined.");
  106. break;
  107. case UriKind.Relative:
  108. if (IsAbsoluteUri)
  109. throw new UriFormatException("Invalid URI: The format of the URI could not be "
  110. + "determined because the parameter 'uriString' represents an absolute URI.");
  111. break;
  112. case UriKind.RelativeOrAbsolute:
  113. break;
  114. default:
  115. string msg = String.Format("Invalid UriKind value '{0}'.", uriKind);
  116. throw new ArgumentException(msg);
  117. }
  118. }
  119. //
  120. // An exception-less constructor, returns success
  121. // condition on the out parameter `success'.
  122. //
  123. Uri(string uriString, UriKind uriKind, out bool success)
  124. {
  125. if (uriString == null)
  126. {
  127. success = false;
  128. return;
  129. }
  130. if (uriKind != UriKind.RelativeOrAbsolute &&
  131. uriKind != UriKind.Absolute &&
  132. uriKind != UriKind.Relative)
  133. {
  134. string msg = String.Format("Invalid UriKind value '{0}'.", uriKind);
  135. throw new ArgumentException(msg);
  136. }
  137. source = uriString;
  138. if (ParseNoExceptions(uriKind, uriString) != null)
  139. success = false;
  140. else
  141. {
  142. success = true;
  143. switch (uriKind)
  144. {
  145. case UriKind.Absolute:
  146. if (!IsAbsoluteUri)
  147. success = false;
  148. break;
  149. case UriKind.Relative:
  150. if (IsAbsoluteUri)
  151. success = false;
  152. break;
  153. case UriKind.RelativeOrAbsolute:
  154. break;
  155. default:
  156. success = false;
  157. break;
  158. }
  159. }
  160. }
  161. public Uri(Uri baseUri, Uri relativeUri)
  162. {
  163. Merge(baseUri, relativeUri == null ? String.Empty : relativeUri.OriginalString);
  164. // FIXME: this should call UriParser.Resolve
  165. }
  166. // note: doc says that dontEscape is always false but tests show otherwise
  167. //[Obsolete]
  168. public Uri(string uriString, bool dontEscape)
  169. {
  170. userEscaped = dontEscape;
  171. source = uriString;
  172. ParseUri(UriKind.Absolute);
  173. if (!isAbsoluteUri)
  174. throw new UriFormatException("Invalid URI: The format of the URI could not be "
  175. + "determined: " + uriString);
  176. }
  177. public Uri(Uri baseUri, string relativeUri)
  178. {
  179. Merge(baseUri, relativeUri);
  180. // FIXME: this should call UriParser.Resolve
  181. }
  182. [Obsolete("dontEscape is always false")]
  183. public Uri(Uri baseUri, string relativeUri, bool dontEscape)
  184. {
  185. userEscaped = dontEscape;
  186. Merge(baseUri, relativeUri);
  187. }
  188. private void Merge(Uri baseUri, string relativeUri)
  189. {
  190. if (baseUri == null)
  191. throw new ArgumentNullException("baseUri");
  192. if (!baseUri.IsAbsoluteUri)
  193. throw new ArgumentOutOfRangeException("baseUri");
  194. if (relativeUri == null)
  195. relativeUri = String.Empty;
  196. // See RFC 2396 Par 5.2 and Appendix C
  197. // Check Windows UNC (for // it is scheme/host separator)
  198. if (relativeUri.Length >= 2 && relativeUri[0] == '\\' && relativeUri[1] == '\\')
  199. {
  200. source = relativeUri;
  201. ParseUri(UriKind.Absolute);
  202. return;
  203. }
  204. int pos = relativeUri.IndexOf(':');
  205. if (pos != -1)
  206. {
  207. int pos2 = relativeUri.IndexOfAny(new char[] { '/', '\\', '?' });
  208. // pos2 < 0 ... e.g. mailto
  209. // pos2 > pos ... to block ':' in query part
  210. if (pos2 > pos || pos2 < 0)
  211. {
  212. // in some cases, it is equivanent to new Uri (relativeUri, dontEscape):
  213. // 1) when the URI scheme in the
  214. // relative path is different from that
  215. // of the baseUri, or
  216. // 2) the URI scheme is non-standard
  217. // ones (non-standard URIs are always
  218. // treated as absolute here), or
  219. // 3) the relative URI path is absolute.
  220. if (String.CompareOrdinal(baseUri.Scheme, 0, relativeUri, 0, pos) != 0 ||
  221. !IsPredefinedScheme(baseUri.Scheme) ||
  222. (relativeUri.Length > pos + 1 && relativeUri[pos + 1] == '/'))
  223. {
  224. Uri tmp = null;
  225. if (Uri.TryCreate(relativeUri, UriKind.Absolute, out tmp))
  226. {
  227. source = relativeUri;
  228. ParseUri(UriKind.Absolute);
  229. return;
  230. }
  231. else if (pos == 1)
  232. {
  233. // special case as this looks like a windows path
  234. string msg = ParseAsWindowsAbsoluteFilePath(relativeUri);
  235. if (msg != null)
  236. throw new UriFormatException(msg);
  237. }
  238. // otherwise continue with 'full' relativeUri
  239. }
  240. else
  241. relativeUri = relativeUri.Substring(pos + 1);
  242. }
  243. }
  244. this.scheme = baseUri.scheme;
  245. this.host = baseUri.host;
  246. this.port = baseUri.port;
  247. this.userinfo = baseUri.userinfo;
  248. this.isUnc = baseUri.isUnc;
  249. this.isUnixFilePath = baseUri.isUnixFilePath;
  250. this.isOpaquePart = baseUri.isOpaquePart;
  251. if (relativeUri.Length == 0)
  252. {
  253. this.path = baseUri.path;
  254. this.query = baseUri.query;
  255. this.fragment = baseUri.fragment;
  256. return;
  257. }
  258. // 8 fragment
  259. // Note that in relative constructor, file URI cannot handle '#' as a filename character, but just regarded as a fragment identifier.
  260. string original_fragment = String.Empty;
  261. pos = relativeUri.IndexOf('#');
  262. if (pos != -1)
  263. {
  264. original_fragment = relativeUri.Substring(pos);
  265. if (userEscaped)
  266. fragment = original_fragment;
  267. else
  268. fragment = "#" + EscapeString(relativeUri.Substring(pos + 1));
  269. relativeUri = pos == 0 ? String.Empty : relativeUri.Substring(0, pos);
  270. }
  271. bool consider_query = false;
  272. // 6 query
  273. pos = relativeUri.IndexOf('?');
  274. if (pos != -1)
  275. {
  276. query = relativeUri.Substring(pos);
  277. if (!userEscaped)
  278. query = EscapeString(query);
  279. #if !NET_4_0 && !MOONLIGHT && !MOBILE
  280. consider_query = query.Length > 0;
  281. #endif
  282. relativeUri = pos == 0 ? String.Empty : relativeUri.Substring(0, pos);
  283. }
  284. else if (relativeUri.Length == 0)
  285. {
  286. // if there is no relative path then we keep the Query and Fragment from the absolute
  287. query = baseUri.query;
  288. }
  289. if (relativeUri.Length > 0 && relativeUri[0] == '/')
  290. {
  291. if (relativeUri.Length > 1 && relativeUri[1] == '/')
  292. {
  293. source = scheme + ':' + relativeUri;
  294. ParseUri(UriKind.Absolute);
  295. return;
  296. }
  297. else
  298. {
  299. path = relativeUri;
  300. if (!userEscaped)
  301. path = EscapeString(path);
  302. return;
  303. }
  304. }
  305. // par 5.2 step 6 a)
  306. path = baseUri.path;
  307. if ((relativeUri.Length > 0) || consider_query)
  308. {
  309. pos = path.LastIndexOf('/');
  310. if (pos >= 0)
  311. path = path.Substring(0, pos + 1);
  312. }
  313. if (relativeUri.Length == 0)
  314. {
  315. // when merging URI the OriginalString is not quite original
  316. source = GetLeftPart(UriPartial.Authority) + query + original_fragment;
  317. return;
  318. }
  319. // 6 b)
  320. path += relativeUri;
  321. // 6 c)
  322. int startIndex = 0;
  323. while (true)
  324. {
  325. pos = path.IndexOf("./", startIndex);
  326. if (pos == -1)
  327. break;
  328. if (pos == 0)
  329. path = path.Remove(0, 2);
  330. else if (path[pos - 1] != '.')
  331. path = path.Remove(pos, 2);
  332. else
  333. startIndex = pos + 1;
  334. }
  335. // 6 d)
  336. if (path.Length > 1 &&
  337. path[path.Length - 1] == '.' &&
  338. path[path.Length - 2] == '/')
  339. path = path.Remove(path.Length - 1, 1);
  340. // 6 e)
  341. startIndex = 0;
  342. while (true)
  343. {
  344. pos = path.IndexOf("/../", startIndex);
  345. if (pos == -1)
  346. break;
  347. if (pos == 0)
  348. {
  349. startIndex = 3;
  350. continue;
  351. }
  352. int pos2 = path.LastIndexOf('/', pos - 1);
  353. if (pos2 == -1)
  354. {
  355. startIndex = pos + 1;
  356. }
  357. else
  358. {
  359. if (path.Substring(pos2 + 1, pos - pos2 - 1) != "..")
  360. path = path.Remove(pos2 + 1, pos - pos2 + 3);
  361. else
  362. startIndex = pos + 1;
  363. }
  364. }
  365. // 6 f)
  366. if (path.Length > 3 && path.EndsWith("/.."))
  367. {
  368. pos = path.LastIndexOf('/', path.Length - 4);
  369. if (pos != -1)
  370. if (path.Substring(pos + 1, path.Length - pos - 4) != "..")
  371. path = path.Remove(pos + 1, path.Length - pos - 1);
  372. }
  373. // 6 g)
  374. while (path.StartsWith("/../"/*, StringComparison.Ordinal*/))
  375. path = path.Substring(3);
  376. if (!userEscaped)
  377. path = EscapeString(path);
  378. // when merging URI the OriginalString is not quite original
  379. source = GetLeftPart(UriPartial.Authority) + path + query + original_fragment;
  380. }
  381. // Properties
  382. public string AbsolutePath
  383. {
  384. get
  385. {
  386. EnsureAbsoluteUri();
  387. if (scheme == "mailto" || scheme == "file")
  388. // faster (mailto) and special (file) cases
  389. return path;
  390. if (path.Length == 0)
  391. {
  392. string start = scheme + SchemeDelimiter;
  393. if (path.StartsWith(start/*, StringComparison.Ordinal*/))
  394. return "/";
  395. else
  396. return String.Empty;
  397. }
  398. return path;
  399. }
  400. }
  401. public string AbsoluteUri
  402. {
  403. get
  404. {
  405. EnsureAbsoluteUri();
  406. if (cachedAbsoluteUri == null)
  407. {
  408. cachedAbsoluteUri = GetLeftPart(UriPartial.Path);
  409. if (query.Length > 0)
  410. cachedAbsoluteUri += query;
  411. if (fragment.Length > 0)
  412. cachedAbsoluteUri += fragment;
  413. }
  414. return cachedAbsoluteUri;
  415. }
  416. }
  417. public string Authority
  418. {
  419. get
  420. {
  421. EnsureAbsoluteUri();
  422. return (GetDefaultPort(Scheme) == port)
  423. ? host : host + ":" + port;
  424. }
  425. }
  426. public string Fragment
  427. {
  428. get
  429. {
  430. EnsureAbsoluteUri();
  431. return fragment;
  432. }
  433. }
  434. public string Host
  435. {
  436. get
  437. {
  438. EnsureAbsoluteUri();
  439. return host;
  440. }
  441. }
  442. public UriHostNameType HostNameType
  443. {
  444. get
  445. {
  446. EnsureAbsoluteUri();
  447. UriHostNameType ret = CheckHostName(Host);
  448. if (ret != UriHostNameType.Unknown)
  449. return ret;
  450. if (scheme == "mailto")
  451. return UriHostNameType.Basic;
  452. return (IsFile) ? UriHostNameType.Basic : ret;
  453. }
  454. }
  455. public bool IsDefaultPort
  456. {
  457. get
  458. {
  459. EnsureAbsoluteUri();
  460. return GetDefaultPort(Scheme) == port;
  461. }
  462. }
  463. public bool IsFile
  464. {
  465. get
  466. {
  467. EnsureAbsoluteUri();
  468. return (Scheme == UriSchemeFile);
  469. }
  470. }
  471. public bool IsLoopback
  472. {
  473. get
  474. {
  475. EnsureAbsoluteUri();
  476. if (Host.Length == 0)
  477. {
  478. return IsFile;
  479. }
  480. if (host == "loopback" || host == "localhost")
  481. return true;
  482. IPAddress result;
  483. if (IPAddress.TryParse(host, out result))
  484. if (IPAddress.Loopback.Equals(result))
  485. return true;
  486. /*IPv6Address result6;
  487. if (IPv6Address.TryParse(host, out result6))
  488. {
  489. if (IPv6Address.IsLoopback(result6))
  490. return true;
  491. }*/
  492. return false;
  493. }
  494. }
  495. public bool IsUnc
  496. {
  497. // rule: This should be true only if
  498. // - uri string starts from "\\", or
  499. // - uri string starts from "//" (Samba way)
  500. get
  501. {
  502. EnsureAbsoluteUri();
  503. return isUnc;
  504. }
  505. }
  506. private bool IsLocalIdenticalToAbsolutePath()
  507. {
  508. if (IsFile)
  509. return false;
  510. if ((scheme == Uri.UriSchemeNews) || (scheme == Uri.UriSchemeNntp) || (scheme == Uri.UriSchemeFtp))
  511. return false;
  512. return IsWellFormedOriginalString();
  513. }
  514. public string LocalPath
  515. {
  516. get
  517. {
  518. EnsureAbsoluteUri();
  519. if (cachedLocalPath != null)
  520. return cachedLocalPath;
  521. if (IsLocalIdenticalToAbsolutePath())
  522. {
  523. cachedLocalPath = Unescape(AbsolutePath);
  524. return cachedLocalPath;
  525. }
  526. if (!IsUnc)
  527. {
  528. string p = Unescape(path);
  529. bool windows = (path.Length > 3 && path[1] == ':' &&
  530. (path[2] == '\\' || path[2] == '/'));
  531. if (windows)
  532. cachedLocalPath = p.Replace('/', '\\');
  533. else
  534. cachedLocalPath = p;
  535. }
  536. else
  537. {
  538. // support *nix and W32 styles
  539. if (path.Length > 1 && path[1] == ':')
  540. cachedLocalPath = Unescape(path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
  541. // LAMESPEC: ok, now we cannot determine
  542. // if such URI like "file://foo/bar" is
  543. // Windows UNC or unix file path, so
  544. // they should be handled differently.
  545. else if (System.IO.Path.DirectorySeparatorChar == '\\')
  546. {
  547. string h = host;
  548. if (path.Length > 0)
  549. {
  550. if ((path.Length > 1) || (path[0] != '/'))
  551. {
  552. h += path.Replace('/', '\\');
  553. }
  554. }
  555. cachedLocalPath = "\\\\" + Unescape(h);
  556. }
  557. else
  558. cachedLocalPath = Unescape(path);
  559. }
  560. if (cachedLocalPath.Length == 0)
  561. cachedLocalPath = Path.DirectorySeparatorChar.ToString();
  562. return cachedLocalPath;
  563. }
  564. }
  565. public string PathAndQuery
  566. {
  567. get
  568. {
  569. EnsureAbsoluteUri();
  570. return path + Query;
  571. }
  572. }
  573. public int Port
  574. {
  575. get
  576. {
  577. EnsureAbsoluteUri();
  578. return port;
  579. }
  580. }
  581. public string Query
  582. {
  583. get
  584. {
  585. EnsureAbsoluteUri();
  586. return query;
  587. }
  588. }
  589. public string Scheme
  590. {
  591. get
  592. {
  593. EnsureAbsoluteUri();
  594. return scheme;
  595. }
  596. }
  597. public string[] Segments
  598. {
  599. get
  600. {
  601. EnsureAbsoluteUri();
  602. // return a (pre-allocated) empty array
  603. if (path.Length == 0)
  604. return Empty;
  605. // do not return the original array (since items can be changed)
  606. if (segments != null)
  607. return segments.ToArray();
  608. List<string> list = new List<string>();
  609. StringBuilder current = new StringBuilder();
  610. for (int i = 0; i < path.Length; i++)
  611. {
  612. switch (path[i])
  613. {
  614. case '/':
  615. case '\\':
  616. current.Append(path[i]);
  617. list.Add(current.ToString());
  618. current.Length = 0;
  619. break;
  620. case '%':
  621. if ((i < path.Length - 2) && (path[i + 1] == '5' && path[i + 2] == 'C'))
  622. {
  623. current.Append("%5C");
  624. list.Add(current.ToString());
  625. current.Length = 0;
  626. i += 2;
  627. }
  628. else
  629. {
  630. current.Append('%');
  631. }
  632. break;
  633. default:
  634. current.Append(path[i]);
  635. break;
  636. }
  637. }
  638. if (current.Length > 0)
  639. list.Add(current.ToString());
  640. if (IsFile && (list.Count > 0))
  641. {
  642. string first = list[0];
  643. if ((first.Length > 1) && (first[1] == ':'))
  644. {
  645. list.Insert(0, "/");
  646. }
  647. }
  648. segments = list;
  649. return segments.ToArray();
  650. }
  651. }
  652. public bool UserEscaped
  653. {
  654. get { return userEscaped; }
  655. }
  656. public string UserInfo
  657. {
  658. get
  659. {
  660. EnsureAbsoluteUri();
  661. return userinfo == null ? String.Empty : userinfo;
  662. }
  663. }
  664. public string DnsSafeHost
  665. {
  666. get
  667. {
  668. EnsureAbsoluteUri();
  669. string host = Host;
  670. /*if (HostNameType == UriHostNameType.IPv6)
  671. {
  672. host = Host.Substring(1, Host.Length - 2);
  673. if (scope_id != 0)
  674. host += "%" + scope_id.ToString();
  675. }*/
  676. return Unescape(host);
  677. }
  678. }
  679. #if NET_2_0
  680. public
  681. #else
  682. internal
  683. #endif
  684. bool IsAbsoluteUri
  685. {
  686. get { return isAbsoluteUri; }
  687. }
  688. // LAMESPEC: source field is supplied in such case that this
  689. // property makes sense. For such case that source field is
  690. // not supplied (i.e. .ctor(Uri, string), this property
  691. // makes no sense. To avoid silly regression it just returns
  692. // ToString() value now. See bug #78374.
  693. public string OriginalString
  694. {
  695. get { return source != null ? source : ToString(); }
  696. }
  697. // Methods
  698. public static UriHostNameType CheckHostName(string name)
  699. {
  700. if (name == null || name.Length == 0)
  701. return UriHostNameType.Unknown;
  702. if (IsIPv4Address(name))
  703. return UriHostNameType.IPv4;
  704. if (IsDomainAddress(name))
  705. return UriHostNameType.Dns;
  706. //IPv6Address addr;
  707. //if (IPv6Address.TryParse(name, out addr))
  708. // return UriHostNameType.IPv6;
  709. return UriHostNameType.Unknown;
  710. }
  711. internal static bool IsIPv4Address(string name)
  712. {
  713. string[] captures = name.Split(new char[] { '.' });
  714. if (captures.Length != 4)
  715. return false;
  716. for (int i = 0; i < 4; i++)
  717. {
  718. int length;
  719. length = captures[i].Length;
  720. if (length == 0)
  721. return false;
  722. uint number;
  723. if (!UInt32.TryParse(captures[i], out number))
  724. return false;
  725. if (number > 255)
  726. return false;
  727. }
  728. return true;
  729. }
  730. internal static bool IsDomainAddress(string name)
  731. {
  732. int len = name.Length;
  733. int count = 0;
  734. for (int i = 0; i < len; i++)
  735. {
  736. char c = name[i];
  737. if (count == 0)
  738. {
  739. if (!Char.IsLetterOrDigit(c))
  740. return false;
  741. }
  742. else if (c == '.')
  743. {
  744. // www..host.com is bad
  745. if (i + 1 < len && name[i + 1] == '.')
  746. return false;
  747. count = 0;
  748. }
  749. else if (!Char.IsLetterOrDigit(c) && c != '-' && c != '_')
  750. {
  751. return false;
  752. }
  753. if (++count == 64)
  754. return false;
  755. }
  756. return true;
  757. }
  758. #if !NET_2_1
  759. // [Obsolete("This method does nothing, it has been obsoleted")]
  760. protected virtual void Canonicalize()
  761. {
  762. //
  763. // This is flagged in the Microsoft documentation as used
  764. // internally, no longer in use, and Obsolete.
  765. //
  766. }
  767. // [MonoTODO("Find out what this should do")]
  768. //[Obsolete]
  769. protected virtual void CheckSecurity()
  770. {
  771. }
  772. #endif // NET_2_1
  773. // defined in RFC3986 as = ALPHA *( ALPHA / DIGIT / "+" / "-" / ".")
  774. public static bool CheckSchemeName(string schemeName)
  775. {
  776. if (schemeName == null || schemeName.Length == 0)
  777. return false;
  778. if (!IsAlpha(schemeName[0]))
  779. return false;
  780. int len = schemeName.Length;
  781. for (int i = 1; i < len; i++)
  782. {
  783. char c = schemeName[i];
  784. if (!Char.IsDigit(c) && !IsAlpha(c) && c != '.' && c != '+' && c != '-')
  785. return false;
  786. }
  787. return true;
  788. }
  789. private static bool IsAlpha(char c)
  790. {
  791. // as defined in rfc2234
  792. // %x41-5A / %x61-7A (A-Z / a-z)
  793. int i = (int)c;
  794. return (((i >= 0x41) && (i <= 0x5A)) || ((i >= 0x61) && (i <= 0x7A)));
  795. }
  796. public override bool Equals(object comparant)
  797. {
  798. if (comparant == null)
  799. return false;
  800. Uri uri = comparant as Uri;
  801. if ((object)uri == null)
  802. {
  803. string s = comparant as String;
  804. if (s == null)
  805. return false;
  806. uri = new Uri(s);
  807. }
  808. return InternalEquals(uri);
  809. }
  810. // Assumes: uri != null
  811. bool InternalEquals(Uri uri)
  812. {
  813. if (this.isAbsoluteUri != uri.isAbsoluteUri)
  814. return false;
  815. if (!this.isAbsoluteUri)
  816. return this.source == uri.source;
  817. CultureInfo inv = CultureInfo.InvariantCulture;
  818. return this.scheme.ToLower(inv) == uri.scheme.ToLower(inv)
  819. && this.host.ToLower(inv) == uri.host.ToLower(inv)
  820. && this.port == uri.port
  821. && this.query == uri.query
  822. && this.path == uri.path;
  823. }
  824. public static bool operator ==(Uri u1, Uri u2)
  825. {
  826. return object.Equals(u1, u2);
  827. }
  828. public static bool operator !=(Uri u1, Uri u2)
  829. {
  830. return !(u1 == u2);
  831. }
  832. public override int GetHashCode()
  833. {
  834. if (cachedHashCode == 0)
  835. {
  836. CultureInfo inv = CultureInfo.InvariantCulture;
  837. if (isAbsoluteUri)
  838. {
  839. cachedHashCode = scheme.ToLower(inv).GetHashCode()
  840. ^ host.ToLower(inv).GetHashCode()
  841. ^ port
  842. ^ query.GetHashCode()
  843. ^ path.GetHashCode();
  844. }
  845. else
  846. {
  847. cachedHashCode = source.GetHashCode();
  848. }
  849. }
  850. return cachedHashCode;
  851. }
  852. public string GetLeftPart(UriPartial part)
  853. {
  854. EnsureAbsoluteUri();
  855. int defaultPort;
  856. switch (part)
  857. {
  858. case UriPartial.Scheme:
  859. return scheme + GetOpaqueWiseSchemeDelimiter();
  860. case UriPartial.Authority:
  861. if ((scheme == Uri.UriSchemeMailto) || (scheme == Uri.UriSchemeNews))
  862. return String.Empty;
  863. StringBuilder s = new StringBuilder();
  864. s.Append(scheme);
  865. s.Append(GetOpaqueWiseSchemeDelimiter());
  866. if (path.Length > 1 && path[1] == ':' && (Uri.UriSchemeFile == scheme))
  867. s.Append('/'); // win32 file
  868. if (userinfo != null)
  869. s.Append(userinfo).Append('@');
  870. s.Append(host);
  871. defaultPort = GetDefaultPort(scheme);
  872. if ((port != -1) && (port != defaultPort))
  873. s.Append(':').Append(port);
  874. return s.ToString();
  875. case UriPartial.Path:
  876. StringBuilder sb = new StringBuilder();
  877. sb.Append(scheme);
  878. sb.Append(GetOpaqueWiseSchemeDelimiter());
  879. if (path.Length > 1 && path[1] == ':' && (Uri.UriSchemeFile == scheme))
  880. sb.Append('/'); // win32 file
  881. if (userinfo != null)
  882. sb.Append(userinfo).Append('@');
  883. sb.Append(host);
  884. defaultPort = GetDefaultPort(scheme);
  885. if ((port != -1) && (port != defaultPort))
  886. sb.Append(':').Append(port);
  887. if (path.Length > 0)
  888. {
  889. if (scheme == "mailto" || scheme == "news")
  890. sb.Append(path);
  891. else
  892. sb.Append(Reduce(path, CompactEscaped(scheme)));
  893. }
  894. return sb.ToString();
  895. }
  896. return null;
  897. }
  898. public static int FromHex(char digit)
  899. {
  900. if ('0' <= digit && digit <= '9')
  901. {
  902. return (int)(digit - '0');
  903. }
  904. if ('a' <= digit && digit <= 'f')
  905. return (int)(digit - 'a' + 10);
  906. if ('A' <= digit && digit <= 'F')
  907. return (int)(digit - 'A' + 10);
  908. throw new ArgumentException("digit");
  909. }
  910. public static string HexEscape(char character)
  911. {
  912. if (character > 255)
  913. {
  914. throw new ArgumentOutOfRangeException("character");
  915. }
  916. return "%" + hexUpperChars[((character & 0xf0) >> 4)]
  917. + hexUpperChars[((character & 0x0f))];
  918. }
  919. public static char HexUnescape(string pattern, ref int index)
  920. {
  921. if (pattern == null)
  922. throw new ArgumentException("pattern");
  923. if (index < 0 || index >= pattern.Length)
  924. throw new ArgumentOutOfRangeException("index");
  925. if (!IsHexEncoding(pattern, index))
  926. return pattern[index++];
  927. index++;
  928. int msb = FromHex(pattern[index++]);
  929. int lsb = FromHex(pattern[index++]);
  930. return (char)((msb << 4) | lsb);
  931. }
  932. public static bool IsHexDigit(char digit)
  933. {
  934. return (('0' <= digit && digit <= '9') ||
  935. ('a' <= digit && digit <= 'f') ||
  936. ('A' <= digit && digit <= 'F'));
  937. }
  938. public static bool IsHexEncoding(string pattern, int index)
  939. {
  940. if ((index + 3) > pattern.Length)
  941. return false;
  942. return ((pattern[index++] == '%') &&
  943. IsHexDigit(pattern[index++]) &&
  944. IsHexDigit(pattern[index]));
  945. }
  946. //
  947. // Implemented by copying most of the MakeRelative code
  948. //
  949. public Uri MakeRelativeUri(Uri uri)
  950. {
  951. #if NET_4_0 || MOONLIGHT || MOBILE
  952. if (uri == null)
  953. throw new ArgumentNullException ("uri");
  954. #endif
  955. if (Host != uri.Host || Scheme != uri.Scheme)
  956. return uri;
  957. string result = String.Empty;
  958. if (this.path != uri.path)
  959. {
  960. string[] segments = this.Segments;
  961. string[] segments2 = uri.Segments;
  962. int k = 0;
  963. int max = Math.Min(segments.Length, segments2.Length);
  964. for (; k < max; k++)
  965. if (segments[k] != segments2[k])
  966. break;
  967. for (int i = k + 1; i < segments.Length; i++)
  968. result += "../";
  969. for (int i = k; i < segments2.Length; i++)
  970. result += segments2[i];
  971. }
  972. uri.AppendQueryAndFragment(ref result);
  973. return new Uri(result, UriKind.Relative);
  974. }
  975. [Obsolete("Use MakeRelativeUri(Uri uri) instead.")]
  976. public string MakeRelative(Uri toUri)
  977. {
  978. if ((this.Scheme != toUri.Scheme) ||
  979. (this.Authority != toUri.Authority))
  980. return toUri.ToString();
  981. string result = String.Empty;
  982. if (this.path != toUri.path)
  983. {
  984. string[] segments = this.Segments;
  985. string[] segments2 = toUri.Segments;
  986. int k = 0;
  987. int max = Math.Min(segments.Length, segments2.Length);
  988. for (; k < max; k++)
  989. if (segments[k] != segments2[k])
  990. break;
  991. for (int i = k + 1; i < segments.Length; i++)
  992. result += "../";
  993. for (int i = k; i < segments2.Length; i++)
  994. result += segments2[i];
  995. }
  996. // Important: MakeRelative does not append fragment or query.
  997. return result;
  998. }
  999. void AppendQueryAndFragment(ref string result)
  1000. {
  1001. if (query.Length > 0)
  1002. {
  1003. string q = query[0] == '?' ? '?' + Unescape(query.Substring(1), true, false) : Unescape(query, false);
  1004. result += q;
  1005. }
  1006. if (fragment.Length > 0)
  1007. result += Unescape(fragment, true, false);
  1008. }
  1009. public override string ToString()
  1010. {
  1011. if (cachedToString != null)
  1012. return cachedToString;
  1013. if (isAbsoluteUri)
  1014. {
  1015. cachedToString = Unescape(GetLeftPart(UriPartial.Path), true);
  1016. AppendQueryAndFragment(ref cachedToString);
  1017. }
  1018. else
  1019. {
  1020. // Everything is contained in path in this case.
  1021. cachedToString = path;
  1022. }
  1023. return cachedToString;
  1024. }
  1025. //protected void GetObjectData(SerializationInfo info, StreamingContext context)
  1026. //{
  1027. // if (this.isAbsoluteUri)
  1028. // {
  1029. // info.AddValue("AbsoluteUri", this.AbsoluteUri);
  1030. // }
  1031. // else
  1032. // {
  1033. // info.AddValue("AbsoluteUri", String.Empty);
  1034. // info.AddValue("RelativeUri", this.OriginalString);
  1035. // }
  1036. //}
  1037. //void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
  1038. //{
  1039. // GetObjectData(info, context);
  1040. //}
  1041. // Internal Methods
  1042. //[Obsolete]
  1043. protected virtual void Escape()
  1044. {
  1045. path = EscapeString(path);
  1046. }
  1047. #if MOONLIGHT
  1048. static string EscapeString (string str)
  1049. #else
  1050. //[Obsolete]
  1051. protected static string EscapeString(string str)
  1052. #endif
  1053. {
  1054. return EscapeString(str, Uri.EscapeCommonHexBrackets);
  1055. }
  1056. private const string EscapeCommon = "<>%\"{}|\\^`";
  1057. private const string EscapeReserved = ";/?:@&=+$,";
  1058. private const string EscapeFragment = "#";
  1059. private const string EscapeBrackets = "[]";
  1060. private const string EscapeNews = EscapeCommon + EscapeBrackets + "?";
  1061. private const string EscapeCommonHex = EscapeCommon + EscapeFragment;
  1062. private const string EscapeCommonBrackets = EscapeCommon + EscapeBrackets;
  1063. internal const string EscapeCommonHexBrackets = EscapeCommon + EscapeFragment + EscapeBrackets;
  1064. internal const string EscapeCommonHexBracketsQuery = EscapeCommonHexBrackets + "?";
  1065. internal static string EscapeString(string str, string escape)
  1066. {
  1067. return EscapeString(str, escape, true);
  1068. }
  1069. internal static string EscapeString(string str, string escape, bool nonAsciiEscape)
  1070. {
  1071. if (String.IsNullOrEmpty(str))
  1072. return String.Empty;
  1073. StringBuilder s = new StringBuilder();
  1074. int len = str.Length;
  1075. for (int i = 0; i < len; i++)
  1076. {
  1077. // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
  1078. // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
  1079. // control = <US-ASCII coded characters 00-1F and 7F hexadecimal>
  1080. // space = <US-ASCII coded character 20 hexadecimal>
  1081. // delims = "<" | ">" | "#" | "%" | <">
  1082. // unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
  1083. // check for escape code already placed in str,
  1084. // i.e. for encoding that follows the pattern
  1085. // "%hexhex" in a string, where "hex" is a digit from 0-9
  1086. // or a letter from A-F (case-insensitive).
  1087. if (IsHexEncoding(str, i))
  1088. {
  1089. // if ,yes , copy it as is
  1090. s.Append(str.Substring(i, 3));
  1091. i += 2;
  1092. continue;
  1093. }
  1094. char c = str[i];
  1095. bool outside_limited_ascii = ((c <= 0x20) || (c >= 0x7f));
  1096. bool needs_escape = (escape.IndexOf(c) != -1);
  1097. if (nonAsciiEscape && outside_limited_ascii)
  1098. {
  1099. byte[] data = Encoding.UTF8.GetBytes(new char[] { c });
  1100. int length = data.Length;
  1101. for (int j = 0; j < length; j++)
  1102. {
  1103. c = (char)data[j];
  1104. if (needs_escape || nonAsciiEscape)
  1105. s.Append(HexEscape(c));
  1106. else
  1107. s.Append(c);
  1108. }
  1109. }
  1110. else if (needs_escape)
  1111. {
  1112. s.Append(HexEscape(c));
  1113. }
  1114. else
  1115. {
  1116. s.Append(c);
  1117. }
  1118. }
  1119. return s.ToString();
  1120. }
  1121. // On .NET 1.x, this method is called from .ctor(). When overriden, we
  1122. // can avoid the "absolute uri" constraints of the .ctor() by
  1123. // overriding with custom code.
  1124. [Obsolete("The method has been deprecated. It is not used by the system.")]
  1125. protected virtual void Parse()
  1126. {
  1127. }
  1128. private void ParseUri(UriKind kind)
  1129. {
  1130. Parse(kind, source);
  1131. if (userEscaped)
  1132. return;
  1133. // non-ascii characters are not escaped for the host name
  1134. host = EscapeString(host, EscapeCommonHex, false);
  1135. if (host.Length > 1 && host[0] != '[' && host[host.Length - 1] != ']')
  1136. {
  1137. // host name present (but not an IPv6 address)
  1138. host = host.ToLower(CultureInfo.InvariantCulture);
  1139. }
  1140. if (isAbsoluteUri && (path.Length > 0))
  1141. path = EscapeString(path);
  1142. }
  1143. #if MOONLIGHT
  1144. string Unescape (string str)
  1145. #else
  1146. //[Obsolete]
  1147. protected virtual string Unescape(string str)
  1148. #endif
  1149. {
  1150. return Unescape(str, false, false);
  1151. }
  1152. internal static string Unescape(string str, bool excludeSpecial)
  1153. {
  1154. return Unescape(str, excludeSpecial, excludeSpecial);
  1155. }
  1156. internal static string Unescape(string str, bool excludeSpecial, bool excludeBackslash)
  1157. {
  1158. if (String.IsNullOrEmpty(str))
  1159. return String.Empty;
  1160. StringBuilder s = new StringBuilder();
  1161. int len = str.Length;
  1162. for (int i = 0; i < len; i++)
  1163. {
  1164. char c = str[i];
  1165. if (c == '%')
  1166. {
  1167. char surrogate;
  1168. char x = HexUnescapeMultiByte(str, ref i, out surrogate);
  1169. if (excludeSpecial && x == '#')
  1170. s.Append("%23");
  1171. else if (excludeSpecial && x == '%')
  1172. s.Append("%25");
  1173. else if (excludeSpecial && x == '?')
  1174. s.Append("%3F");
  1175. else if (excludeBackslash && x == '\\')
  1176. s.Append("%5C");
  1177. else
  1178. {
  1179. s.Append(x);
  1180. if (surrogate != char.MinValue)
  1181. s.Append(surrogate);
  1182. }
  1183. i--;
  1184. }
  1185. else
  1186. s.Append(c);
  1187. }
  1188. return s.ToString();
  1189. }
  1190. // Private Methods
  1191. private void ParseAsWindowsUNC(string uriString)
  1192. {
  1193. scheme = UriSchemeFile;
  1194. port = -1;
  1195. fragment = String.Empty;
  1196. query = String.Empty;
  1197. isUnc = true;
  1198. uriString = uriString.TrimStart(new char[] { '\\' });
  1199. int pos = uriString.IndexOf('\\');
  1200. if (pos > 0)
  1201. {
  1202. path = uriString.Substring(pos);
  1203. host = uriString.Substring(0, pos);
  1204. }
  1205. else
  1206. { // "\\\\server"
  1207. host = uriString;
  1208. path = String.Empty;
  1209. }
  1210. path = path.Replace("\\", "/");
  1211. }
  1212. //
  1213. // Returns null on success, string with error on failure
  1214. //
  1215. private string ParseAsWindowsAbsoluteFilePath(string uriString)
  1216. {
  1217. if (uriString.Length > 2 && uriString[2] != '\\' && uriString[2] != '/')
  1218. return "Relative file path is not allowed.";
  1219. scheme = UriSchemeFile;
  1220. host = String.Empty;
  1221. port = -1;
  1222. path = uriString.Replace("\\", "/");
  1223. fragment = String.Empty;
  1224. query = String.Empty;
  1225. return null;
  1226. }
  1227. private void ParseAsUnixAbsoluteFilePath(string uriString)
  1228. {
  1229. isUnixFilePath = true;
  1230. scheme = UriSchemeFile;
  1231. port = -1;
  1232. fragment = String.Empty;
  1233. query = String.Empty;
  1234. host = String.Empty;
  1235. path = null;
  1236. if (uriString.Length >= 2 && uriString[0] == '/' && uriString[1] == '/')
  1237. {
  1238. uriString = uriString.TrimStart(new char[] { '/' });
  1239. // Now we don't regard //foo/bar as "foo" host.
  1240. /*
  1241. int pos = uriString.IndexOf ('/');
  1242. if (pos > 0) {
  1243. path = '/' + uriString.Substring (pos + 1);
  1244. host = uriString.Substring (0, pos);
  1245. } else { // "///server"
  1246. host = uriString;
  1247. path = String.Empty;
  1248. }
  1249. */
  1250. path = '/' + uriString;
  1251. }
  1252. if (path == null)
  1253. path = uriString;
  1254. }
  1255. //
  1256. // This parse method will throw exceptions on failure
  1257. //
  1258. private void Parse(UriKind kind, string uriString)
  1259. {
  1260. if (uriString == null)
  1261. throw new ArgumentNullException("uriString");
  1262. string s = ParseNoExceptions(kind, uriString);
  1263. if (s != null)
  1264. throw new UriFormatException(s);
  1265. }
  1266. private bool SupportsQuery()
  1267. {
  1268. return ((scheme != Uri.UriSchemeNntp) && (scheme != Uri.UriSchemeFtp) && (scheme != Uri.UriSchemeFile));
  1269. }
  1270. //
  1271. // This parse method will not throw exceptions on failure
  1272. //
  1273. // Returns null on success, or a description of the error in the parsing
  1274. //
  1275. private string ParseNoExceptions(UriKind kind, string uriString)
  1276. {
  1277. //
  1278. // From RFC 2396 :
  1279. //
  1280. // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
  1281. // 12 3 4 5 6 7 8 9
  1282. //
  1283. uriString = uriString.Trim();
  1284. int len = uriString.Length;
  1285. if (len == 0)
  1286. {
  1287. if (kind == UriKind.Relative || kind == UriKind.RelativeOrAbsolute)
  1288. {
  1289. isAbsoluteUri = false;
  1290. return null;
  1291. }
  1292. }
  1293. if (len <= 1 && (kind == UriKind.Absolute))
  1294. return "Absolute URI is too short";
  1295. int pos = 0;
  1296. // 1, 2
  1297. // Identify Windows path, unix path, or standard URI.
  1298. if (uriString[0] == '/' && Path.DirectorySeparatorChar == '/')
  1299. {
  1300. //Unix Path
  1301. ParseAsUnixAbsoluteFilePath(uriString);
  1302. #if MOONLIGH

Large files files are truncated, but you can click here to view the full file