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