| 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);            }        }    }}
 |