jellyfin/SocketHttpListener/Net/HttpListener.cs

277 lines
8.3 KiB
C#
Raw Normal View History

2016-11-11 19:55:12 +00:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
2017-09-03 02:42:13 +00:00
using System.Security.Cryptography.X509Certificates;
2016-11-11 19:55:12 +00:00
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
2017-05-09 18:51:26 +00:00
using MediaBrowser.Model.System;
2016-11-11 19:55:12 +00:00
using MediaBrowser.Model.Text;
using Microsoft.Extensions.Logging;
2016-11-11 19:55:12 +00:00
namespace SocketHttpListener.Net
{
public sealed class HttpListener : IDisposable
{
internal ICryptoProvider CryptoProvider { get; private set; }
internal ISocketFactory SocketFactory { get; private set; }
2017-03-12 19:27:26 +00:00
internal IFileSystem FileSystem { get; private set; }
2016-11-11 19:55:12 +00:00
internal ITextEncoding TextEncoding { get; private set; }
2018-09-12 17:26:21 +00:00
internal IStreamHelper StreamHelper { get; private set; }
2016-11-11 19:55:12 +00:00
internal INetworkManager NetworkManager { get; private set; }
2017-05-09 18:51:26 +00:00
internal IEnvironmentInfo EnvironmentInfo { get; private set; }
2016-11-11 19:55:12 +00:00
public bool EnableDualMode { get; set; }
AuthenticationSchemes auth_schemes;
HttpListenerPrefixCollection prefixes;
AuthenticationSchemeSelector auth_selector;
string realm;
bool unsafe_ntlm_auth;
bool listening;
bool disposed;
2019-01-07 23:27:46 +00:00
Dictionary<HttpListenerContext, HttpListenerContext> registry; // Dictionary<HttpListenerContext,HttpListenerContext>
2016-11-11 19:55:12 +00:00
Dictionary<HttpConnection, HttpConnection> connections;
private ILogger _logger;
2017-09-03 02:42:13 +00:00
private X509Certificate _certificate;
2016-11-11 19:55:12 +00:00
public Action<HttpListenerContext> OnContext { get; set; }
2018-09-12 17:26:21 +00:00
public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IStreamHelper streamHelper, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
2016-11-11 19:55:12 +00:00
{
_logger = logger;
CryptoProvider = cryptoProvider;
SocketFactory = socketFactory;
NetworkManager = networkManager;
TextEncoding = textEncoding;
2018-09-12 17:26:21 +00:00
StreamHelper = streamHelper;
2017-03-12 19:27:26 +00:00
FileSystem = fileSystem;
2017-05-09 18:51:26 +00:00
EnvironmentInfo = environmentInfo;
2016-11-11 19:55:12 +00:00
prefixes = new HttpListenerPrefixCollection(logger, this);
registry = new Dictionary<HttpListenerContext, HttpListenerContext>();
connections = new Dictionary<HttpConnection, HttpConnection>();
auth_schemes = AuthenticationSchemes.Anonymous;
}
2018-09-12 17:26:21 +00:00
public HttpListener(ILogger logger, X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IStreamHelper streamHelper, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
: this(logger, cryptoProvider, socketFactory, networkManager, textEncoding, streamHelper, fileSystem, environmentInfo)
2016-11-11 19:55:12 +00:00
{
_certificate = certificate;
}
2017-09-03 02:42:13 +00:00
public void LoadCert(X509Certificate cert)
2016-11-11 19:55:12 +00:00
{
_certificate = cert;
}
// TODO: Digest, NTLM and Negotiate require ControlPrincipal
public AuthenticationSchemes AuthenticationSchemes
{
get => auth_schemes;
2016-11-11 19:55:12 +00:00
set
{
CheckDisposed();
auth_schemes = value;
}
}
public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate
{
get => auth_selector;
2016-11-11 19:55:12 +00:00
set
{
CheckDisposed();
auth_selector = value;
}
}
public bool IsListening => listening;
2016-11-11 19:55:12 +00:00
public static bool IsSupported => true;
2016-11-11 19:55:12 +00:00
public HttpListenerPrefixCollection Prefixes
{
get
{
CheckDisposed();
return prefixes;
}
}
// TODO: use this
public string Realm
{
get => realm;
2016-11-11 19:55:12 +00:00
set
{
CheckDisposed();
realm = value;
}
}
public bool UnsafeConnectionNtlmAuthentication
{
get => unsafe_ntlm_auth;
2016-11-11 19:55:12 +00:00
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;
2016-11-11 19:55:12 +00:00
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();
2018-09-12 17:26:21 +00:00
HttpEndPointManager.RemoveListener(_logger, this);
2016-11-11 19:55:12 +00:00
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;
2018-09-12 17:26:21 +00:00
HttpEndPointManager.AddListener(_logger, this);
2016-11-11 19:55:12 +00:00
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);
2016-11-11 19:55:12 +00:00
}
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);
}
}
}
}