2
0

HttpListener.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Net;
  6. using System.Security.Cryptography.X509Certificates;
  7. using MediaBrowser.Common.Net;
  8. using MediaBrowser.Model.Cryptography;
  9. using MediaBrowser.Model.IO;
  10. using MediaBrowser.Model.Logging;
  11. using MediaBrowser.Model.Net;
  12. using MediaBrowser.Model.System;
  13. using MediaBrowser.Model.Text;
  14. using SocketHttpListener.Primitives;
  15. namespace SocketHttpListener.Net
  16. {
  17. public sealed class HttpListener : IDisposable
  18. {
  19. internal ICryptoProvider CryptoProvider { get; private set; }
  20. internal ISocketFactory SocketFactory { get; private set; }
  21. internal IFileSystem FileSystem { get; private set; }
  22. internal ITextEncoding TextEncoding { get; private set; }
  23. internal IStreamHelper StreamHelper { get; private set; }
  24. internal INetworkManager NetworkManager { get; private set; }
  25. internal IEnvironmentInfo EnvironmentInfo { get; private set; }
  26. public bool EnableDualMode { get; set; }
  27. AuthenticationSchemes auth_schemes;
  28. HttpListenerPrefixCollection prefixes;
  29. AuthenticationSchemeSelector auth_selector;
  30. string realm;
  31. bool unsafe_ntlm_auth;
  32. bool listening;
  33. bool disposed;
  34. Dictionary<HttpListenerContext, HttpListenerContext> registry; // Dictionary<HttpListenerContext,HttpListenerContext>
  35. Dictionary<HttpConnection, HttpConnection> connections;
  36. private ILogger _logger;
  37. private X509Certificate _certificate;
  38. public Action<HttpListenerContext> OnContext { get; set; }
  39. public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IStreamHelper streamHelper, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
  40. {
  41. _logger = logger;
  42. CryptoProvider = cryptoProvider;
  43. SocketFactory = socketFactory;
  44. NetworkManager = networkManager;
  45. TextEncoding = textEncoding;
  46. StreamHelper = streamHelper;
  47. FileSystem = fileSystem;
  48. EnvironmentInfo = environmentInfo;
  49. prefixes = new HttpListenerPrefixCollection(logger, this);
  50. registry = new Dictionary<HttpListenerContext, HttpListenerContext>();
  51. connections = new Dictionary<HttpConnection, HttpConnection>();
  52. auth_schemes = AuthenticationSchemes.Anonymous;
  53. }
  54. public HttpListener(X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IStreamHelper streamHelper, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
  55. :this(new NullLogger(), certificate, cryptoProvider, socketFactory, networkManager, textEncoding, streamHelper, fileSystem, environmentInfo)
  56. {
  57. }
  58. public HttpListener(ILogger logger, X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IStreamHelper streamHelper, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
  59. : this(logger, cryptoProvider, socketFactory, networkManager, textEncoding, streamHelper, fileSystem, environmentInfo)
  60. {
  61. _certificate = certificate;
  62. }
  63. public void LoadCert(X509Certificate cert)
  64. {
  65. _certificate = cert;
  66. }
  67. // TODO: Digest, NTLM and Negotiate require ControlPrincipal
  68. public AuthenticationSchemes AuthenticationSchemes
  69. {
  70. get { return auth_schemes; }
  71. set
  72. {
  73. CheckDisposed();
  74. auth_schemes = value;
  75. }
  76. }
  77. public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate
  78. {
  79. get { return auth_selector; }
  80. set
  81. {
  82. CheckDisposed();
  83. auth_selector = value;
  84. }
  85. }
  86. public bool IsListening
  87. {
  88. get { return listening; }
  89. }
  90. public static bool IsSupported
  91. {
  92. get { return true; }
  93. }
  94. public HttpListenerPrefixCollection Prefixes
  95. {
  96. get
  97. {
  98. CheckDisposed();
  99. return prefixes;
  100. }
  101. }
  102. // TODO: use this
  103. public string Realm
  104. {
  105. get { return realm; }
  106. set
  107. {
  108. CheckDisposed();
  109. realm = value;
  110. }
  111. }
  112. public bool UnsafeConnectionNtlmAuthentication
  113. {
  114. get { return unsafe_ntlm_auth; }
  115. set
  116. {
  117. CheckDisposed();
  118. unsafe_ntlm_auth = value;
  119. }
  120. }
  121. //internal IMonoSslStream CreateSslStream(Stream innerStream, bool ownsStream, MSI.MonoRemoteCertificateValidationCallback callback)
  122. //{
  123. // lock (registry)
  124. // {
  125. // if (tlsProvider == null)
  126. // tlsProvider = MonoTlsProviderFactory.GetProviderInternal();
  127. // if (tlsSettings == null)
  128. // tlsSettings = MSI.MonoTlsSettings.CopyDefaultSettings();
  129. // if (tlsSettings.RemoteCertificateValidationCallback == null)
  130. // tlsSettings.RemoteCertificateValidationCallback = callback;
  131. // return tlsProvider.CreateSslStream(innerStream, ownsStream, tlsSettings);
  132. // }
  133. //}
  134. internal X509Certificate Certificate
  135. {
  136. get { return _certificate; }
  137. }
  138. public void Abort()
  139. {
  140. if (disposed)
  141. return;
  142. if (!listening)
  143. {
  144. return;
  145. }
  146. Close(true);
  147. }
  148. public void Close()
  149. {
  150. if (disposed)
  151. return;
  152. if (!listening)
  153. {
  154. disposed = true;
  155. return;
  156. }
  157. Close(true);
  158. disposed = true;
  159. }
  160. void Close(bool force)
  161. {
  162. CheckDisposed();
  163. HttpEndPointManager.RemoveListener(_logger, this);
  164. Cleanup(force);
  165. }
  166. void Cleanup(bool close_existing)
  167. {
  168. lock (registry)
  169. {
  170. if (close_existing)
  171. {
  172. // Need to copy this since closing will call UnregisterContext
  173. ICollection keys = registry.Keys;
  174. var all = new HttpListenerContext[keys.Count];
  175. keys.CopyTo(all, 0);
  176. registry.Clear();
  177. for (int i = all.Length - 1; i >= 0; i--)
  178. all[i].Connection.Close(true);
  179. }
  180. lock (connections)
  181. {
  182. ICollection keys = connections.Keys;
  183. var conns = new HttpConnection[keys.Count];
  184. keys.CopyTo(conns, 0);
  185. connections.Clear();
  186. for (int i = conns.Length - 1; i >= 0; i--)
  187. conns[i].Close(true);
  188. }
  189. }
  190. }
  191. internal AuthenticationSchemes SelectAuthenticationScheme(HttpListenerContext context)
  192. {
  193. if (AuthenticationSchemeSelectorDelegate != null)
  194. return AuthenticationSchemeSelectorDelegate(context.Request);
  195. else
  196. return auth_schemes;
  197. }
  198. public void Start()
  199. {
  200. CheckDisposed();
  201. if (listening)
  202. return;
  203. HttpEndPointManager.AddListener(_logger, this);
  204. listening = true;
  205. }
  206. public void Stop()
  207. {
  208. CheckDisposed();
  209. listening = false;
  210. Close(false);
  211. }
  212. void IDisposable.Dispose()
  213. {
  214. if (disposed)
  215. return;
  216. Close(true); //TODO: Should we force here or not?
  217. disposed = true;
  218. }
  219. internal void CheckDisposed()
  220. {
  221. if (disposed)
  222. throw new ObjectDisposedException(GetType().ToString());
  223. }
  224. internal void RegisterContext(HttpListenerContext context)
  225. {
  226. if (OnContext != null && IsListening)
  227. {
  228. OnContext(context);
  229. }
  230. lock (registry)
  231. registry[context] = context;
  232. }
  233. internal void UnregisterContext(HttpListenerContext context)
  234. {
  235. lock (registry)
  236. registry.Remove(context);
  237. }
  238. internal void AddConnection(HttpConnection cnc)
  239. {
  240. lock (connections)
  241. {
  242. connections[cnc] = cnc;
  243. }
  244. }
  245. internal void RemoveConnection(HttpConnection cnc)
  246. {
  247. lock (connections)
  248. {
  249. connections.Remove(cnc);
  250. }
  251. }
  252. }
  253. }