PageRenderTime 65ms CodeModel.GetById 40ms RepoModel.GetById 1ms app.codeStats 0ms

/src/NzbDrone.Common/Http/HttpUri.cs

https://github.com/NzbDrone/NzbDrone
C# | 270 lines | 222 code | 48 blank | 0 comment | 32 complexity | c9b885c3d3bb447fbb0ba79e217cfcae MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Text.RegularExpressions;
  5. using NzbDrone.Common.Extensions;
  6. namespace NzbDrone.Common.Http
  7. {
  8. public class HttpUri : IEquatable<HttpUri>
  9. {
  10. private static readonly Regex RegexUri = new Regex(@"^(?:(?<scheme>[a-z]+):)?(?://(?<host>[-_A-Z0-9.]+)(?::(?<port>[0-9]{1,5}))?)?(?<path>(?:(?:(?<=^)|/+)[^/?#\r\n]+)+/*|/+)?(?:\?(?<query>[^#\r\n]*))?(?:\#(?<fragment>.*))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
  11. private readonly string _uri;
  12. public string FullUri => _uri;
  13. public HttpUri(string uri)
  14. {
  15. _uri = uri ?? string.Empty;
  16. Parse();
  17. }
  18. public HttpUri(string scheme, string host, int? port, string path, string query, string fragment)
  19. {
  20. StringBuilder builder = new StringBuilder();
  21. if (scheme.IsNotNullOrWhiteSpace())
  22. {
  23. builder.Append(scheme);
  24. builder.Append(":");
  25. }
  26. if (host.IsNotNullOrWhiteSpace())
  27. {
  28. builder.Append("//");
  29. builder.Append(host);
  30. if (port.HasValue)
  31. {
  32. builder.Append(":");
  33. builder.Append(port);
  34. }
  35. }
  36. if (path.IsNotNullOrWhiteSpace())
  37. {
  38. if (host.IsNotNullOrWhiteSpace() || path.StartsWith("/"))
  39. {
  40. builder.Append('/');
  41. }
  42. builder.Append(path.TrimStart('/'));
  43. }
  44. if (query.IsNotNullOrWhiteSpace())
  45. {
  46. builder.Append('?');
  47. builder.Append(query);
  48. }
  49. if (fragment.IsNotNullOrWhiteSpace())
  50. {
  51. builder.Append('#');
  52. builder.Append(fragment);
  53. }
  54. _uri = builder.ToString();
  55. Parse();
  56. }
  57. private void Parse()
  58. {
  59. var match = RegexUri.Match(_uri);
  60. var scheme = match.Groups["scheme"];
  61. var host = match.Groups["host"];
  62. var port = match.Groups["port"];
  63. var path = match.Groups["path"];
  64. var query = match.Groups["query"];
  65. var fragment = match.Groups["fragment"];
  66. if (!match.Success || scheme.Success && !host.Success && path.Success)
  67. {
  68. throw new ArgumentException("Uri didn't match expected pattern: " + _uri);
  69. }
  70. Scheme = scheme.Value;
  71. Host = host.Value;
  72. Port = port.Success ? (int?)int.Parse(port.Value) : null;
  73. Path = path.Value;
  74. Query = query.Value;
  75. Fragment = fragment.Value;
  76. }
  77. public string Scheme { get; private set; }
  78. public string Host { get; private set; }
  79. public int? Port { get; private set; }
  80. public string Path { get; private set; }
  81. public string Query { get; private set; }
  82. public string Fragment { get; private set; }
  83. private IList<KeyValuePair<string, string>> _queryParams;
  84. private IList<KeyValuePair<string, string>> QueryParams
  85. {
  86. get
  87. {
  88. if (_queryParams == null)
  89. {
  90. var dict = new List<KeyValuePair<string, string>>();
  91. if (Query.IsNotNullOrWhiteSpace())
  92. {
  93. foreach (var pair in Query.Split('&'))
  94. {
  95. var split = pair.Split(new[] { '=' }, 2);
  96. if (split.Length == 1)
  97. {
  98. dict.Add(new KeyValuePair<string, string>(Uri.UnescapeDataString(split[0]), null));
  99. }
  100. else
  101. {
  102. dict.Add(new KeyValuePair<string, string>(Uri.UnescapeDataString(split[0]), Uri.UnescapeDataString(split[1])));
  103. }
  104. }
  105. }
  106. _queryParams = dict.AsReadOnly();
  107. }
  108. return _queryParams;
  109. }
  110. }
  111. public HttpUri CombinePath(string path)
  112. {
  113. return new HttpUri(Scheme, Host, Port, CombinePath(Path, path), Query, Fragment);
  114. }
  115. public static string CombinePath(string basePath, string relativePath)
  116. {
  117. if (relativePath.IsNullOrWhiteSpace())
  118. {
  119. return basePath;
  120. }
  121. if (basePath.IsNullOrWhiteSpace())
  122. {
  123. return relativePath;
  124. }
  125. return basePath.TrimEnd('/') + "/" + relativePath.TrimStart('/');
  126. }
  127. private static string CombineRelativePath(string basePath, string relativePath)
  128. {
  129. if (relativePath.IsNullOrWhiteSpace())
  130. {
  131. return basePath;
  132. }
  133. if (relativePath.StartsWith("/"))
  134. {
  135. return relativePath;
  136. }
  137. var baseSlashIndex = basePath.LastIndexOf('/');
  138. if (baseSlashIndex >= 0)
  139. {
  140. return basePath.Substring(0, baseSlashIndex) + "/" + relativePath;
  141. }
  142. return relativePath;
  143. }
  144. public HttpUri SetQuery(string query)
  145. {
  146. return new HttpUri(Scheme, Host, Port, Path, query, Fragment);
  147. }
  148. public HttpUri AddQueryParam(string key, object value)
  149. {
  150. var newQuery = string.Concat(Uri.EscapeDataString(key), "=", Uri.EscapeDataString(value.ToString()));
  151. if (Query.IsNotNullOrWhiteSpace())
  152. {
  153. newQuery = string.Concat(Query, "&", newQuery);
  154. }
  155. return SetQuery(newQuery);
  156. }
  157. public HttpUri AddQueryParams(IEnumerable<KeyValuePair<string, string>> queryParams)
  158. {
  159. var builder = new StringBuilder();
  160. builder.Append(Query);
  161. foreach (var pair in queryParams)
  162. {
  163. if (builder.Length != 0)
  164. {
  165. builder.Append("&");
  166. }
  167. builder.Append(Uri.EscapeDataString(pair.Key));
  168. builder.Append("=");
  169. builder.Append(Uri.EscapeDataString(pair.Value));
  170. }
  171. return SetQuery(builder.ToString());
  172. }
  173. public override int GetHashCode()
  174. {
  175. return _uri.GetHashCode();
  176. }
  177. public override string ToString()
  178. {
  179. return _uri;
  180. }
  181. public override bool Equals(object obj)
  182. {
  183. if (obj is string)
  184. {
  185. return _uri.Equals((string)obj);
  186. }
  187. else if (obj is Uri)
  188. {
  189. return _uri.Equals(((Uri)obj).OriginalString);
  190. }
  191. else
  192. {
  193. return Equals(obj as HttpUri);
  194. }
  195. }
  196. public bool Equals(HttpUri other)
  197. {
  198. if (object.ReferenceEquals(other, null)) return false;
  199. return _uri.Equals(other._uri);
  200. }
  201. public static explicit operator Uri(HttpUri url)
  202. {
  203. return new Uri(url.FullUri);
  204. }
  205. public static HttpUri operator +(HttpUri baseUrl, HttpUri relativeUrl)
  206. {
  207. if (relativeUrl.Scheme.IsNotNullOrWhiteSpace())
  208. {
  209. return relativeUrl;
  210. }
  211. if (relativeUrl.Host.IsNotNullOrWhiteSpace())
  212. {
  213. return new HttpUri(baseUrl.Scheme, relativeUrl.Host, relativeUrl.Port, relativeUrl.Path, relativeUrl.Query, relativeUrl.Fragment);
  214. }
  215. if (relativeUrl.Path.IsNotNullOrWhiteSpace())
  216. {
  217. return new HttpUri(baseUrl.Scheme, baseUrl.Host, baseUrl.Port, CombineRelativePath(baseUrl.Path, relativeUrl.Path), relativeUrl.Query, relativeUrl.Fragment);
  218. }
  219. return new HttpUri(baseUrl.Scheme, baseUrl.Host, baseUrl.Port, baseUrl.Path, relativeUrl.Query, relativeUrl.Fragment);
  220. }
  221. }
  222. }