HttpEndPointManager.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. using System.Reflection;
  7. using System.Threading.Tasks;
  8. using MediaBrowser.Model.IO;
  9. using Microsoft.Extensions.Logging;
  10. using MediaBrowser.Model.Net;
  11. using SocketHttpListener.Primitives;
  12. namespace SocketHttpListener.Net
  13. {
  14. internal sealed class HttpEndPointManager
  15. {
  16. private static Dictionary<IPAddress, Dictionary<int, HttpEndPointListener>> s_ipEndPoints = new Dictionary<IPAddress, Dictionary<int, HttpEndPointListener>>();
  17. private HttpEndPointManager()
  18. {
  19. }
  20. public static void AddListener(ILogger logger, HttpListener listener)
  21. {
  22. List<string> added = new List<string>();
  23. try
  24. {
  25. lock ((s_ipEndPoints as ICollection).SyncRoot)
  26. {
  27. foreach (string prefix in listener.Prefixes)
  28. {
  29. AddPrefixInternal(logger, prefix, listener);
  30. added.Add(prefix);
  31. }
  32. }
  33. }
  34. catch
  35. {
  36. foreach (string prefix in added)
  37. {
  38. RemovePrefix(logger, prefix, listener);
  39. }
  40. throw;
  41. }
  42. }
  43. public static void AddPrefix(ILogger logger, string prefix, HttpListener listener)
  44. {
  45. lock ((s_ipEndPoints as ICollection).SyncRoot)
  46. {
  47. AddPrefixInternal(logger, prefix, listener);
  48. }
  49. }
  50. private static void AddPrefixInternal(ILogger logger, string p, HttpListener listener)
  51. {
  52. int start = p.IndexOf(':') + 3;
  53. int colon = p.IndexOf(':', start);
  54. if (colon != -1)
  55. {
  56. // root can't be -1 here, since we've already checked for ending '/' in ListenerPrefix.
  57. int root = p.IndexOf('/', colon, p.Length - colon);
  58. string portString = p.Substring(colon + 1, root - colon - 1);
  59. int port;
  60. if (!int.TryParse(portString, out port) || port <= 0 || port >= 65536)
  61. {
  62. throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_invalid_port");
  63. }
  64. }
  65. ListenerPrefix lp = new ListenerPrefix(p);
  66. if (lp.Host != "*" && lp.Host != "+" && Uri.CheckHostName(lp.Host) == UriHostNameType.Unknown)
  67. throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_listener_host");
  68. if (lp.Path.IndexOf('%') != -1)
  69. throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_invalid_path");
  70. if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1)
  71. throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_invalid_path");
  72. // listens on all the interfaces if host name cannot be parsed by IPAddress.
  73. HttpEndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure);
  74. epl.AddPrefix(lp, listener);
  75. }
  76. private static IPAddress GetIpAnyAddress(HttpListener listener)
  77. {
  78. return listener.EnableDualMode ? IPAddress.IPv6Any : IPAddress.Any;
  79. }
  80. private static HttpEndPointListener GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure)
  81. {
  82. IPAddress addr;
  83. if (host == "*" || host == "+")
  84. {
  85. addr = GetIpAnyAddress(listener);
  86. }
  87. else
  88. {
  89. const int NotSupportedErrorCode = 50;
  90. try
  91. {
  92. addr = Dns.GetHostAddresses(host)[0];
  93. }
  94. catch
  95. {
  96. // Throw same error code as windows, request is not supported.
  97. throw new HttpListenerException(NotSupportedErrorCode, "net_listener_not_supported");
  98. }
  99. if (IPAddress.Any.Equals(addr))
  100. {
  101. // Don't support listening to 0.0.0.0, match windows behavior.
  102. throw new HttpListenerException(NotSupportedErrorCode, "net_listener_not_supported");
  103. }
  104. }
  105. Dictionary<int, HttpEndPointListener> p = null;
  106. if (s_ipEndPoints.ContainsKey(addr))
  107. {
  108. p = s_ipEndPoints[addr];
  109. }
  110. else
  111. {
  112. p = new Dictionary<int, HttpEndPointListener>();
  113. s_ipEndPoints[addr] = p;
  114. }
  115. HttpEndPointListener epl = null;
  116. if (p.ContainsKey(port))
  117. {
  118. epl = p[port];
  119. }
  120. else
  121. {
  122. try
  123. {
  124. epl = new HttpEndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.SocketFactory, listener.StreamHelper, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo);
  125. }
  126. catch (SocketException ex)
  127. {
  128. throw new HttpListenerException(ex.ErrorCode, ex.Message);
  129. }
  130. p[port] = epl;
  131. }
  132. return epl;
  133. }
  134. public static void RemoveEndPoint(HttpEndPointListener epl, IPEndPoint ep)
  135. {
  136. lock ((s_ipEndPoints as ICollection).SyncRoot)
  137. {
  138. Dictionary<int, HttpEndPointListener> p = null;
  139. p = s_ipEndPoints[ep.Address];
  140. p.Remove(ep.Port);
  141. if (p.Count == 0)
  142. {
  143. s_ipEndPoints.Remove(ep.Address);
  144. }
  145. epl.Close();
  146. }
  147. }
  148. public static void RemoveListener(ILogger logger, HttpListener listener)
  149. {
  150. lock ((s_ipEndPoints as ICollection).SyncRoot)
  151. {
  152. foreach (string prefix in listener.Prefixes)
  153. {
  154. RemovePrefixInternal(logger, prefix, listener);
  155. }
  156. }
  157. }
  158. public static void RemovePrefix(ILogger logger, string prefix, HttpListener listener)
  159. {
  160. lock ((s_ipEndPoints as ICollection).SyncRoot)
  161. {
  162. RemovePrefixInternal(logger, prefix, listener);
  163. }
  164. }
  165. private static void RemovePrefixInternal(ILogger logger, string prefix, HttpListener listener)
  166. {
  167. ListenerPrefix lp = new ListenerPrefix(prefix);
  168. if (lp.Path.IndexOf('%') != -1)
  169. return;
  170. if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1)
  171. return;
  172. HttpEndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure);
  173. epl.RemovePrefix(lp, listener);
  174. }
  175. }
  176. }