using System; using System.Collections.Generic; using System.Collections.Concurrent; using System.IO; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; namespace OSHttpServer { /// /// Used to create and reuse contexts. /// public class HttpContextFactory : IHttpContextFactory { private readonly ConcurrentDictionary m_activeContexts = new(); private readonly ILogWriter m_logWriter; /// /// A request have been received from one of the contexts. /// public event EventHandler RequestReceived; /// /// Initializes a new instance of the class. /// /// The writer. /// Amount of bytes to read from the incoming socket stream. /// Used to create a request parser. public HttpContextFactory(ILogWriter writer) { m_logWriter = writer; ContextTimeoutManager.Start(); } /// /// Create a new context. /// /// true if socket is running HTTPS. /// Client that connected /// Network/SSL stream. /// A context. protected HttpClientContext CreateContext(bool isSecured, IPEndPoint endPoint, Stream stream, Socket sock) { var context = new HttpClientContext(isSecured, endPoint, stream, m_logWriter, sock); context.Disconnected += OnFreeContext; context.RequestReceived += OnRequestReceived; ContextTimeoutManager.StartMonitoringContext(context); m_activeContexts[context.contextID] = context; context.Start(); return context; } private void OnRequestReceived(object sender, RequestEventArgs e) { RequestReceived?.Invoke(sender, e); } private void OnFreeContext(object sender, DisconnectedEventArgs e) { var imp = sender as HttpClientContext; if (imp == null || imp.contextID < 0) return; m_activeContexts.TryRemove(imp.contextID, out HttpClientContext dummy); imp.Close(); } #region IHttpContextFactory Members /// /// Create a secure . /// /// Client socket (accepted by the ). /// HTTPS certificate to use. /// Kind of HTTPS protocol. Usually TLS or SSL. /// /// A created . /// public IHttpClientContext CreateSecureContext(Socket socket, X509Certificate certificate, SslProtocols protocol, RemoteCertificateValidationCallback _clientCallback = null) { var networkStream = new NetworkStream(socket, true); var remoteEndPoint = (IPEndPoint)socket.RemoteEndPoint; SslStream sslStream = null; try { if (_clientCallback == null) { sslStream = new SslStream(networkStream, false); sslStream.AuthenticateAsServer(certificate, false, protocol, false); } else { sslStream = new SslStream(networkStream, false, new RemoteCertificateValidationCallback(_clientCallback)); sslStream.AuthenticateAsServer(certificate, true, protocol, false); } } catch (Exception e) { m_logWriter.Write(this, LogPrio.Error, e.Message); sslStream.Close(); return null; } return CreateContext(true, remoteEndPoint, sslStream, socket); } /// /// Creates a that handles a connected client. /// /// Client socket (accepted by the ). /// /// A creates . /// public IHttpClientContext CreateContext(Socket socket) { var networkStream = new NetworkStream(socket, true); var remoteEndPoint = (IPEndPoint)socket.RemoteEndPoint; return CreateContext(false, remoteEndPoint, networkStream, socket); } #endregion /// /// Server is shutting down so shut down the factory /// public void Shutdown() { ContextTimeoutManager.Stop(); } } /// /// Used to create es. /// public interface IHttpContextFactory { /// /// Creates a that handles a connected client. /// /// Client socket (accepted by the ). /// A creates . IHttpClientContext CreateContext(Socket socket); /// /// Create a secure . /// /// Client socket (accepted by the ). /// HTTPS certificate to use. /// Kind of HTTPS protocol. Usually TLS or SSL. /// A created . IHttpClientContext CreateSecureContext(Socket socket, X509Certificate certificate, SslProtocols protocol, RemoteCertificateValidationCallback _clientCallback = null); /// /// A request have been received from one of the contexts. /// event EventHandler RequestReceived; /// /// Server is shutting down so shut down the factory /// void Shutdown(); } }