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 ConcurrentDictionary(); private readonly IRequestParserFactory m_parserfactory; 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, IRequestParserFactory factory) { m_logWriter = writer; m_parserfactory = factory; 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) { HttpClientContext context; context = CreateNewContext(isSecured, endPoint, stream, sock); context.Disconnected += OnFreeContext; context.RequestReceived += OnRequestReceived; context.Stream = stream; context.IsSecured = isSecured; context.RemotePort = endPoint.Port.ToString(); context.RemoteAddress = endPoint.Address.ToString(); ContextTimeoutManager.StartMonitoringContext(context); m_activeContexts[context.contextID] = context; context.Start(); return context; } /// /// Create a new context. /// /// true if HTTPS is used. /// Remote client /// Network stream, /// A new context (always). protected virtual HttpClientContext CreateNewContext(bool isSecured, IPEndPoint endPoint, Stream stream, Socket sock) { return new HttpClientContext(isSecured, endPoint, stream, m_parserfactory, sock); } 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) { socket.NoDelay = true; 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) { socket.NoDelay = true; 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(); } }