123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Net;
- using System.Security.Cryptography.X509Certificates;
- using MediaBrowser.Common.Net;
- using MediaBrowser.Model.Cryptography;
- using MediaBrowser.Model.IO;
- using MediaBrowser.Model.Net;
- using MediaBrowser.Model.System;
- using Microsoft.Extensions.Logging;
- namespace SocketHttpListener.Net
- {
- public sealed class HttpListener : IDisposable
- {
- internal ICryptoProvider CryptoProvider { get; private set; }
- internal ISocketFactory SocketFactory { get; private set; }
- internal IFileSystem FileSystem { get; private set; }
- internal IStreamHelper StreamHelper { get; private set; }
- internal INetworkManager NetworkManager { get; private set; }
- internal IEnvironmentInfo EnvironmentInfo { get; private set; }
- public bool EnableDualMode { get; set; }
- AuthenticationSchemes auth_schemes;
- HttpListenerPrefixCollection prefixes;
- AuthenticationSchemeSelector auth_selector;
- string realm;
- bool unsafe_ntlm_auth;
- bool listening;
- bool disposed;
- Dictionary<HttpListenerContext, HttpListenerContext> registry; // Dictionary<HttpListenerContext,HttpListenerContext>
- Dictionary<HttpConnection, HttpConnection> connections;
- private ILogger _logger;
- private X509Certificate _certificate;
- public Action<HttpListenerContext> OnContext { get; set; }
- public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory,
- INetworkManager networkManager, IStreamHelper streamHelper, IFileSystem fileSystem,
- IEnvironmentInfo environmentInfo)
- {
- _logger = logger;
- CryptoProvider = cryptoProvider;
- SocketFactory = socketFactory;
- NetworkManager = networkManager;
- StreamHelper = streamHelper;
- FileSystem = fileSystem;
- EnvironmentInfo = environmentInfo;
- prefixes = new HttpListenerPrefixCollection(logger, this);
- registry = new Dictionary<HttpListenerContext, HttpListenerContext>();
- connections = new Dictionary<HttpConnection, HttpConnection>();
- auth_schemes = AuthenticationSchemes.Anonymous;
- }
- public HttpListener(ILogger logger, X509Certificate certificate, ICryptoProvider cryptoProvider,
- ISocketFactory socketFactory, INetworkManager networkManager, IStreamHelper streamHelper,
- IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
- : this(logger, cryptoProvider, socketFactory, networkManager, streamHelper, fileSystem, environmentInfo)
- {
- _certificate = certificate;
- }
- public void LoadCert(X509Certificate cert)
- {
- _certificate = cert;
- }
- // TODO: Digest, NTLM and Negotiate require ControlPrincipal
- public AuthenticationSchemes AuthenticationSchemes
- {
- get => auth_schemes;
- set
- {
- CheckDisposed();
- auth_schemes = value;
- }
- }
- public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate
- {
- get => auth_selector;
- set
- {
- CheckDisposed();
- auth_selector = value;
- }
- }
- public bool IsListening => listening;
- public static bool IsSupported => true;
- public HttpListenerPrefixCollection Prefixes
- {
- get
- {
- CheckDisposed();
- return prefixes;
- }
- }
- // TODO: use this
- public string Realm
- {
- get => realm;
- set
- {
- CheckDisposed();
- realm = value;
- }
- }
- public bool UnsafeConnectionNtlmAuthentication
- {
- get => unsafe_ntlm_auth;
- set
- {
- CheckDisposed();
- unsafe_ntlm_auth = value;
- }
- }
- //internal IMonoSslStream CreateSslStream(Stream innerStream, bool ownsStream, MSI.MonoRemoteCertificateValidationCallback callback)
- //{
- // lock (registry)
- // {
- // if (tlsProvider == null)
- // tlsProvider = MonoTlsProviderFactory.GetProviderInternal();
- // if (tlsSettings == null)
- // tlsSettings = MSI.MonoTlsSettings.CopyDefaultSettings();
- // if (tlsSettings.RemoteCertificateValidationCallback == null)
- // tlsSettings.RemoteCertificateValidationCallback = callback;
- // return tlsProvider.CreateSslStream(innerStream, ownsStream, tlsSettings);
- // }
- //}
- internal X509Certificate Certificate => _certificate;
- public void Abort()
- {
- if (disposed)
- return;
- if (!listening)
- {
- return;
- }
- Close(true);
- }
- public void Close()
- {
- if (disposed)
- return;
- if (!listening)
- {
- disposed = true;
- return;
- }
- Close(true);
- disposed = true;
- }
- void Close(bool force)
- {
- CheckDisposed();
- HttpEndPointManager.RemoveListener(_logger, this);
- Cleanup(force);
- }
- void Cleanup(bool close_existing)
- {
- lock (registry)
- {
- if (close_existing)
- {
- // Need to copy this since closing will call UnregisterContext
- ICollection keys = registry.Keys;
- var all = new HttpListenerContext[keys.Count];
- keys.CopyTo(all, 0);
- registry.Clear();
- for (int i = all.Length - 1; i >= 0; i--)
- all[i].Connection.Close(true);
- }
- lock (connections)
- {
- ICollection keys = connections.Keys;
- var conns = new HttpConnection[keys.Count];
- keys.CopyTo(conns, 0);
- connections.Clear();
- for (int i = conns.Length - 1; i >= 0; i--)
- conns[i].Close(true);
- }
- }
- }
- internal AuthenticationSchemes SelectAuthenticationScheme(HttpListenerContext context)
- {
- if (AuthenticationSchemeSelectorDelegate != null)
- return AuthenticationSchemeSelectorDelegate(context.Request);
- else
- return auth_schemes;
- }
- public void Start()
- {
- CheckDisposed();
- if (listening)
- return;
- HttpEndPointManager.AddListener(_logger, this);
- listening = true;
- }
- public void Stop()
- {
- CheckDisposed();
- listening = false;
- Close(false);
- }
- void IDisposable.Dispose()
- {
- if (disposed)
- return;
- Close(true); //TODO: Should we force here or not?
- disposed = true;
- }
- internal void CheckDisposed()
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().Name);
- }
- internal void RegisterContext(HttpListenerContext context)
- {
- if (OnContext != null && IsListening)
- {
- OnContext(context);
- }
- lock (registry)
- registry[context] = context;
- }
- internal void UnregisterContext(HttpListenerContext context)
- {
- lock (registry)
- registry.Remove(context);
- }
- internal void AddConnection(HttpConnection cnc)
- {
- lock (connections)
- {
- connections[cnc] = cnc;
- }
- }
- internal void RemoveConnection(HttpConnection cnc)
- {
- lock (connections)
- {
- connections.Remove(cnc);
- }
- }
- }
- }
|