diff --git a/ln.http.service/Program.cs b/ln.http.service/Program.cs
index 41c8b75..f260492 100644
--- a/ln.http.service/Program.cs
+++ b/ln.http.service/Program.cs
@@ -1,7 +1,5 @@
-using System;
-using System.Threading;
-using ln.http;
-using ln.http.listener;
+using System.Threading;
+using ln.bootstrap;
using ln.http.router;
namespace ln.http.service
@@ -10,13 +8,7 @@ namespace ln.http.service
{
static void Main(string[] args)
{
- StaticRouter staticRouter = new StaticRouter(".");
- HTTPServer httpServer = new HTTPServer(new HttpListener(8888), new LoggingRouter(staticRouter.Route).Route);
-
- httpServer.Start();
-
- lock (httpServer)
- Monitor.Wait(httpServer);
+ Bootstrap.Start();
}
}
}
diff --git a/ln.http.service/bootstrap.json b/ln.http.service/bootstrap.json
new file mode 100644
index 0000000..f7d302a
--- /dev/null
+++ b/ln.http.service/bootstrap.json
@@ -0,0 +1,24 @@
+{
+ "ln.http.HTTPServer, ln.http": {
+ "services": [
+ ],
+ "properties": {
+ }
+ },
+ "ln.http.HttpListener, ln.http": {
+ "services": [
+
+ ],
+ "properties": {
+ "DefaultPort": 8180
+ }
+ },
+ "ln.http.HttpsListener, ln.http": {
+ "services": [
+
+ ],
+ "properties": {
+ "DefaultPort": 8443
+ }
+ }
+}
\ No newline at end of file
diff --git a/ln.http.service/ln.http.service.csproj b/ln.http.service/ln.http.service.csproj
index 602adda..c7696ba 100644
--- a/ln.http.service/ln.http.service.csproj
+++ b/ln.http.service/ln.http.service.csproj
@@ -10,4 +10,14 @@
+
+
+
+
+
+
+ Always
+
+
+
diff --git a/ln.http.tests/UnitTest1.cs b/ln.http.tests/UnitTest1.cs
index 629cac4..d3765d1 100644
--- a/ln.http.tests/UnitTest1.cs
+++ b/ln.http.tests/UnitTest1.cs
@@ -21,18 +21,18 @@ namespace ln.http.tests
if (server != null)
return;
- HttpRouter testRouter = new HttpRouter();
+ server = new HTTPServer();
+
+ HttpRouter testRouter = new HttpRouter(server);
testRouter.Map(HttpMethod.ANY, "/controller/*", HttpRoutePriority.NORMAL, new TestApiController().Route);
StaticRouter staticRouter = new StaticRouter(AppContext.BaseDirectory);
testRouter.Map(HttpMethod.ANY, "/static/*", staticRouter.Route);
+
+ HttpListener.DefaultPort = 0;
+ HttpListener httpListener = new HttpListener(server);
- server = new HTTPServer(testRouter.Route);
- server.AddEndpoint(new Endpoint(IPv6.ANY,0));
-
- server.Start();
-
- testPort = server.Listeners[0].LocalEndpoint.Port;
+ testPort = httpListener.LocalEndpoint.Port;
TestContext.Error.WriteLine("Using Port {0}", testPort);
}
diff --git a/ln.http/HTTPServer.cs b/ln.http/HTTPServer.cs
index 873a40c..c1c2fe8 100644
--- a/ln.http/HTTPServer.cs
+++ b/ln.http/HTTPServer.cs
@@ -1,259 +1,136 @@
using System;
using System.Collections.Generic;
using ln.logging;
-using ln.threading;
-using ln.http.listener;
-using ln.http.connections;
using ln.http.exceptions;
-using System.Threading;
-using ln.type;
-using ln.http.router;
using System.IO;
+using System.Text;
+using ln.protocols.helper;
namespace ln.http
{
public class HTTPServer
{
- public static int backlog = 5;
- public static int defaultPort = 8080;
- public static bool exclusivePortListener = false;
-
public static bool DefaultRouteAuthentication { get; set; } = false;
-
- public HttpRouterDelegate Router { get; set; }
- public bool IsRunning => !shutdown;
- public Logger Logger { get; set; }
+ private HashSet _routerDelegates = new HashSet();
+ public IEnumerable Routers => _routerDelegates;
- bool shutdown = false;
+ public TextWriter LoggingWriter { get; set; }
- List listeners = new List();
- public Listener[] Listeners => listeners.ToArray();
-
- HashSet currentConnections = new HashSet();
- public IEnumerable CurrentConnections => currentConnections;
-
- public HTTPServer()
+ public HTTPServer() : this(Console.Out)
{
- Logger = Logger.Default;
+ }
+ public HTTPServer(TextWriter loggingWriter)
+ {
+ LoggingWriter = loggingWriter;
}
public HTTPServer(HttpRouterDelegate router)
: this()
{
- Router = router;
- }
- public HTTPServer(Listener listener, HttpRouterDelegate router)
- : this(router)
- {
- AddListener(listener);
- }
- public HTTPServer(Endpoint endpoint, HttpRouterDelegate router)
- : this(new HttpListener(endpoint), router) { }
-
- public void AddListener(Listener listener)
- {
- listeners.Add(listener);
- if (IsRunning)
- StartListener(listener);
+ AddRouter(router);
}
- public void StartListener(Listener listener)
+ public void AddRouter(HttpRouter httpRouter) => AddRouter(httpRouter.Route);
+ public void AddRouter(HttpRouterDelegate routerDelegate) => _routerDelegates.Add(routerDelegate);
+
+ public void RemoveRouter(HttpRouter httpRouter) => RemoveRouter(httpRouter.Route);
+ public void RemoveRouter(HttpRouterDelegate routerDelegate) => _routerDelegates.Remove(routerDelegate);
+
+ public void Connection(HttpConnection httpConnection)
{
- if (listener.IsOpen)
- return;
-
- listener.Open();
-
- DynamicThreadPool.DefaultPool.Enqueue(
- () => listener.AcceptMany(
- (connection) => this.HandleConnection(connection))
- );
- }
-
- public void StopListener(Listener listener)
- {
- listener.Close();
- }
-
-
- public void AddEndpoint(Endpoint endpoint)
- {
- AddListener(new HttpListener(endpoint));
- }
-
- public void Start()
- {
- foreach (Listener listener in listeners)
- if (!listener.IsOpen) StartListener(listener);
- }
-
- public void Stop()
- {
- lock (this)
+ try
{
- this.shutdown = true;
- }
- foreach (Listener listener in listeners)
- StopListener(listener);
-
- for (int n = 0; n < 150; n++)
- {
- lock (currentConnections)
+ bool keepalive = false;
+ do
{
- if (currentConnections.Count == 0)
- break;
- if ((n % 20) == 0)
- {
- Logging.Log(LogLevel.INFO, "HTTPServer: still waiting for {0} connections to close", currentConnections.Count);
- }
- }
- Thread.Sleep(100);
- }
-
- lock (currentConnections)
- {
- foreach (Connection connection in currentConnections)
- {
- connection.Close();
- }
- }
- }
-
- private void HandleConnection(Connection connection, bool dontClose = false)
- {
- lock (this.currentConnections)
- currentConnections.Add(connection);
-
- bool keepalive = false;
-
- do
- {
- using (HttpRequest httpRequest = connection.ReadRequest(this))
- {
- if (httpRequest == null)
- break;
-
- HttpContext httpContext = new HttpContext()
- { Request = httpRequest, RoutableUri = httpRequest.RequestUri.AbsolutePath };
+ DateTime start = DateTime.Now;
- try
+ using (HttpRequest httpRequest = ReadRequest(httpConnection))
{
- if (!Router(httpContext) && httpContext.Response is null)
- httpContext.Response = HttpResponse.NotFound();
- }
- catch (Exception exception)
- {
- Logging.Log(exception);
- if ((exception is HttpException httpException) && (httpException.HttpResponse != null))
- httpContext.Response = httpException.HttpResponse;
- else
- httpContext.Response = HttpResponse.InternalServerError()
- .Content(String.Format("An internal error occured ({0})", exception.ToString()));
- }
+ if (httpRequest == null)
+ break;
- try
- {
- httpContext.Response.WriteTo(connection.GetStream());
- httpContext.Response?.ContentStream?.Dispose();
- }
- catch (IOException ioexception)
- {
- break;
- }
+ HttpContext httpContext = new HttpContext()
+ { Request = httpRequest, RoutableUri = httpRequest.RequestUri.AbsolutePath };
- keepalive = httpContext.Response.GetHeader("connection", "keep-alive").Equals("keep-alive") && httpRequest
- .GetRequestHeader("connection",
- httpRequest.Protocol.Equals("HTTP/1.1") ? "keep-alive" : "close").Contains("keep-alive",
- StringComparison.InvariantCultureIgnoreCase);
- }
- } while (keepalive && false);
-
- lock (this.currentConnections)
- currentConnections.Remove(connection);
- connection.Close();
-
- // new threading.Promise((resolve, reject)=>{
- // resolve(connection.ReadRequest(this));
- // })
- // .Then((httpRequest)=>
- // {
- // if (httpRequest == null)
- // return null;
- // return Router.Route(new HttpRoutingContext(httpRequest),httpRequest);
- // })
- // // .Then((httpResponse)=>{
- // // if (httpResponse == null)
- // // throw new Exception("no response returned");
- // // return httpResponse;
- // // })
- // .Catch((exception)=>{
- // Logging.Log(exception);
- // if ((exception is HttpException httpException) && (httpException.HttpResponse != null))
- // return httpException.HttpResponse;
- // return HttpResponse
- // .InternalServerError()
- // .Content(String.Format("An internal error occured ({0})", exception.ToString()));
- // })
- // .Then((httpResponse)=>
- // {
- // if (httpResponse == null)
- // return false;
- //
- // httpResponse.SendResponse(connection.GetStream());
- // httpResponse?.ContentStream?.Dispose();
- // return httpResponse.GetHeader("connection", "keep-alive").Equals("keep-alive");
- // })
- // .Then((keepalive)=>{
- // if (keepalive)
- // HandleConnection(connection, true);
- // })
- // .Finally(()=>{
- // lock (this.currentConnections)
- // currentConnections.Remove(connection);
- // connection.Close();
- // })
- // ;
+ try
+ {
+ foreach (var routerDelegate in _routerDelegates)
+ {
+ if (!routerDelegate(httpContext) && httpContext.Response is not null)
+ break;
+ }
+
+ if (httpContext.Response is null)
+ httpContext.Response = HttpResponse.NotFound();
+ }
+ catch (Exception exception)
+ {
+ Logging.Log(exception);
+ if ((exception is HttpException httpException) && (httpException.HttpResponse != null))
+ httpContext.Response = httpException.HttpResponse;
+ else
+ httpContext.Response = HttpResponse.InternalServerError()
+ .Content(String.Format("An internal error occured ({0})", exception.ToString()));
+ }
+
+ try
+ {
+ httpContext.Response.WriteTo(httpConnection.ClientStream);
+ httpContext.Response?.ContentStream?.Dispose();
+ }
+ catch (IOException ioexception)
+ {
+ break;
+ }
+
+ DateTime end = DateTime.Now;
+ TimeSpan duration = end - start;
+
+ LoggingWriter.WriteLine("{0} {1} {2} {3} {4} {5} {6}",
+ start,
+ end,
+ duration,
+ httpContext.Response?.StatusCode.ToString() ?? "-",
+ httpContext.AuthenticatedPrincipal?.ToString() ?? "-",
+ httpContext.Request.Method,
+ httpContext.Request.RequestUri
+ );
+
+ keepalive = httpContext.Response.GetHeader("connection", "keep-alive").Equals("keep-alive") &&
+ httpRequest
+ .GetRequestHeader("connection",
+ httpRequest.Protocol.Equals("HTTP/1.1") ? "keep-alive" : "close").Contains(
+ "keep-alive",
+ StringComparison.InvariantCultureIgnoreCase);
+ }
+ } while (keepalive);
+ }
+ finally
+ {
+ httpConnection.ClientStream.Close();
+ httpConnection.ClientStream.Dispose();
+ }
}
- /*
- public static void StartSimpleServer(string[] arguments)
+ private HttpRequest ReadRequest(HttpConnection httpConnection)
{
- ArgumentContainer argumentContainer = new ArgumentContainer(new Argument[]
+ try
{
- new Argument('p',"port",8080),
- new Argument('l',"listen","127.0.0.1"),
- new Argument('c', "catch",null)
- });
-
- argumentContainer.Parse(ref arguments);
-
- HttpRouter router = new HttpRouter();
- router.AddSimpleRoute("/*", new RouterTarget((request) =>
+ if (HttpLikeProtocolReader.ReadRequest(httpConnection.ClientStream, Encoding.UTF8, out Request request))
+ return new HttpRequest(this, request);
+ return null;
+ } catch (IOException)
{
- HttpResponse response = new HttpResponse(request);
- response.StatusCode = 404;
- response.SetHeader("content-type", "text/plain");
- response.ContentWriter.WriteLine("404 Not Found");
- response.ContentWriter.Flush();
- return response;
- }), -100);
-
- foreach (String path in arguments)
+ return null;
+ } catch (ConnectionClosedException)
{
- StaticRouter staticRouter = new StaticRouter(path);
- staticRouter.AddIndex("index.html");
- staticRouter.AddIndex("index.htm");
- router.AddSimpleRoute("/*", staticRouter);
+ return null;
+ } catch (Exception e)
+ {
+ Logging.Log(e);
+ return null;
}
-
- if (argumentContainer['c'].Value != null)
- router.AddSimpleRoute("/*", new RouterTarget((request) => router.Route(new HttpRoutingContext(request, argumentContainer['c'].Value), request)), 0);
-
- HTTPServer server = new HTTPServer(new Endpoint(IPv6.Parse(argumentContainer['l'].Value),int.Parse(argumentContainer['p'].Value)),
- new LoggingRouter(router));
- server.Start();
}
- */
-
}
}
diff --git a/ln.http/HttpConnection.cs b/ln.http/HttpConnection.cs
new file mode 100644
index 0000000..937d8ed
--- /dev/null
+++ b/ln.http/HttpConnection.cs
@@ -0,0 +1,26 @@
+using System.IO;
+using System.Net;
+
+namespace ln.http
+{
+ public class HttpConnection
+ {
+ public Stream ClientStream { get; }
+ public IPEndPoint RemoteEndPoint { get; }
+ public IPEndPoint LocalEndPoint { get; }
+
+ public bool IsEncrypted { get; }
+
+ public HttpConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, Stream clientStream)
+ :this(localEndPoint, remoteEndPoint, clientStream, false)
+ {}
+
+ public HttpConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, Stream clientStream, bool isEncrypted)
+ {
+ ClientStream = clientStream;
+ LocalEndPoint = localEndPoint;
+ RemoteEndPoint = remoteEndPoint;
+ IsEncrypted = isEncrypted;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ln.http/HttpListener.cs b/ln.http/HttpListener.cs
new file mode 100644
index 0000000..69b99ac
--- /dev/null
+++ b/ln.http/HttpListener.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+
+namespace ln.http
+{
+ public class HttpListener : IDisposable
+ {
+ public static int DefaultPort = 80;
+
+
+ private IPEndPoint _localEndPoint;
+ private Socket _socket;
+ private HTTPServer _httpServer;
+
+ public IPEndPoint LocalEndpoint => _localEndPoint;
+
+ public HttpListener(HTTPServer httpServer) : this(httpServer, DefaultPort)
+ {
+ }
+
+ public HttpListener(HTTPServer httpServer, int port)
+ {
+ _httpServer = httpServer;
+ _localEndPoint = new IPEndPoint(IPAddress.IPv6Any, port);
+
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ _socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
+ _socket.ExclusiveAddressUse = false;
+ _socket.Bind(_localEndPoint);
+ _localEndPoint = (IPEndPoint)_socket.LocalEndPoint;
+ _socket.Listen();
+
+ ThreadPool.QueueUserWorkItem((state )=> ListenerThread());
+ }
+
+ private void ListenerThread()
+ {
+ while (_socket?.IsBound ?? false)
+ {
+ try
+ {
+ Socket clientSocket = _socket.Accept();
+ _httpServer.Connection(
+ new HttpConnection(
+ _localEndPoint,
+ (IPEndPoint)clientSocket.RemoteEndPoint,
+ new NetworkStream(clientSocket)
+ )
+ );
+ }
+ catch
+ {
+ throw;
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ _socket?.Close();
+ _socket?.Dispose();
+ _socket = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ln.http/HttpRouter.cs b/ln.http/HttpRouter.cs
index a58ca7b..2591e57 100644
--- a/ln.http/HttpRouter.cs
+++ b/ln.http/HttpRouter.cs
@@ -13,19 +13,27 @@ namespace ln.http
public enum HttpRoutePriority : int { HIGHEST = 0, HIGH = 1, NORMAL = 2, LOW = 3, LOWEST = 4 }
- public class HttpRouter
+ public class HttpRouter : IDisposable
{
public event HttpFilterDelegate HttpFilters;
public event HttpAuthenticationDelegate AuthenticationDelegates;
private List[] _mappings = new List[5];
-
+ private HTTPServer _httpServer;
+
public HttpRouter()
{
for (int n = 0; n < 5; n++)
_mappings[n] = new List();
}
+ public HttpRouter(HTTPServer httpServer)
+ : this()
+ {
+ _httpServer = httpServer;
+ httpServer.AddRouter(this);
+ }
+
public HttpMapping Map(HttpMethod httpMethod, string uri, HttpRouterDelegate routerDelegate) =>
Map(httpMethod, uri, HttpRoutePriority.NORMAL, routerDelegate);
@@ -165,107 +173,9 @@ namespace ln.http
}
}
-
- /*
- List routes = new List();
- public SimpleRoute[] Routes => routes.ToArray();
- */
-
-
-
-
- /*
- public void AddSimpleRoute(string simpleRoute, Func target) => AddSimpleRoute(simpleRoute, new RouterTarget(target));
- public void AddSimpleRoute(string simpleRoute, Func target) => AddSimpleRoute(simpleRoute, new RouterTarget(target));
- public void AddSimpleRoute(string simpleRoute, Func target) => AddSimpleRoute(simpleRoute, new RouterTarget(target));
- public void AddSimpleRoute(string simpleRoute, IHttpRouter target) => AddSimpleRoute(simpleRoute, target, simpleRoute.Split('/').Length);
- public void AddSimpleRoute(string simpleRoute, IHttpRouter target, int priority)
+ public void Dispose()
{
- string[] parts = simpleRoute.Split(new char[] { '/' });
- string[] reparts = parts.Select((part) =>
- {
- if (part.StartsWith(":", StringComparison.InvariantCulture))
- if (part.EndsWith("*", StringComparison.InvariantCulture))
- return string.Format("(?<{0}>[^/]+)(?<_>/.*)?", part.Substring(1, part.Length - 2));
- else
- return string.Format("(?<{0}>[^/]+)", part.Substring(1));
- else if (part.Equals("*"))
- return string.Format("(?<_>.*)");
- else
- return string.Format("{0}", part);
- }).ToArray();
-
- string reroute = string.Format("{0}\\/?$", string.Join("/", reparts));
-
- AddRoute(reroute, target, priority);
+ _httpServer?.RemoveRouter(this);
}
-
- public void AddRoute(String route, IHttpRouter target) => AddRoute(route, target, 0);
- public void AddRoute(String route, IHttpRouter target,int priority)
- {
- lock (this)
- {
- routes.Add(new SimpleRoute(route, target, priority));
- routes.Sort((SimpleRoute a, SimpleRoute b) => b.Priority - a.Priority);
- }
- }
- public void Remove(SimpleRoute simpleRoute) => routes.Remove(simpleRoute);
-
- public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
- {
- HttpResponse httpResponse;
-
- if (OnRoute != null)
- {
- foreach (RouterFilterDelegate filterDelegate in OnRoute.GetInvocationList())
- {
- if (filterDelegate(this, ref routingContext, httpRequest, out httpResponse))
- return httpResponse;
- }
- }
-
- foreach (SimpleRoute simpleRoute in routes.ToArray())
- {
- Match match = simpleRoute.Route.Match(routingContext.Path);
- if (match.Success)
- {
- string residual = "";
-
- foreach (Group group in match.Groups)
- {
- httpRequest?.SetParameter(group.Name, group.Value);
- if (group.Name.Equals("_"))
- if (group.Value.StartsWith("/", StringComparison.InvariantCulture))
- residual = group.Value;
- else
- residual = "/" + group.Value;
- }
-
- httpResponse = simpleRoute.Target.Route(routingContext.Routed(residual), httpRequest);
- if (httpResponse != null)
- return httpResponse;
- }
- }
- return null;
- }
-
-
- public class SimpleRoute
- {
- public int Priority { get; }
-
- public Regex Route { get; }
- public IHttpRouter Target { get; }
-
- public SimpleRoute(string regex, IHttpRouter target) : this(regex, target, 0) { }
- public SimpleRoute(string regex, IHttpRouter target,int priority)
- {
- Route = new Regex(regex);
- Target = target;
- Priority = priority;
- }
- }
- */
-
}
}
diff --git a/ln.http/HttpsListener.cs b/ln.http/HttpsListener.cs
new file mode 100644
index 0000000..6bf3c28
--- /dev/null
+++ b/ln.http/HttpsListener.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+
+namespace ln.http
+{
+ public class HttpsListener : IDisposable
+ {
+ public static int DefaultPort = 443;
+ public string CertificateStore = Path.Combine(AppContext.BaseDirectory, "certs");
+
+
+ private IPEndPoint _localEndPoint;
+ private Socket _socket;
+ private HTTPServer _httpServer;
+
+ private X509Certificate _defaultCertificate;
+ private Dictionary _certificateCache = new Dictionary();
+
+ public HttpsListener(HTTPServer httpServer) : this(httpServer, DefaultPort)
+ {
+ }
+
+ public HttpsListener(HTTPServer httpServer, int port)
+ {
+ _httpServer = httpServer;
+ _localEndPoint = new IPEndPoint(IPAddress.IPv6Any, port);
+
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ _socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
+ _socket.ExclusiveAddressUse = false;
+ _socket.Bind(_localEndPoint);
+ _socket.Listen();
+
+ if (File.Exists("localhost.crt"))
+ _defaultCertificate = X509Certificate.CreateFromCertFile("localhost.crt");
+ else
+ _defaultCertificate = buildSelfSignedServerCertificate();
+
+ ThreadPool.QueueUserWorkItem((state )=> ListenerThread());
+ }
+
+ private void ListenerThread()
+ {
+ while (_socket?.IsBound ?? false)
+ {
+ try
+ {
+ Socket clientSocket = _socket.Accept();
+ InitializeTLS(clientSocket);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+ }
+
+ private void InitializeTLS(Socket clientSocket)
+ {
+ SslStream sslStream = new SslStream(new NetworkStream(clientSocket), false, null, CertificateSelectionCallback);
+ sslStream.AuthenticateAsServer(_defaultCertificate, false, false);
+
+ _httpServer.Connection(
+ new HttpConnection(
+ _localEndPoint,
+ (IPEndPoint)clientSocket.RemoteEndPoint,
+ sslStream
+ )
+ );
+
+ }
+
+ private X509Certificate CertificateSelectionCallback(object sender, string targethost,
+ X509CertificateCollection localcertificates, X509Certificate? remotecertificate, string[] acceptableissuers)
+ {
+ Console.Error.WriteLine("Certificate Selection for: {0}", targethost);
+ if (_certificateCache.TryGetValue(targethost, out X509Certificate localCertificate))
+ {
+ return localCertificate;
+ }
+ else if (File.Exists(Path.Combine(CertificateStore ?? ".", String.Format("{0}.crt", targethost))))
+ {
+ localCertificate = X509Certificate.CreateFromCertFile(
+ Path.Combine(CertificateStore ?? ".", String.Format("{0}.crt", targethost))
+ );
+ _certificateCache.Add(targethost, localCertificate);
+ return localCertificate;
+ }
+
+ return _defaultCertificate;
+ }
+
+ private X509Certificate2 buildSelfSignedServerCertificate()
+ {
+ SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
+ sanBuilder.AddIpAddress(IPAddress.Loopback);
+ sanBuilder.AddIpAddress(IPAddress.IPv6Loopback);
+ sanBuilder.AddDnsName("localhost");
+ sanBuilder.AddDnsName(Environment.MachineName);
+
+ X500DistinguishedName distinguishedName = new X500DistinguishedName($"CN=localhost");
+
+ using (RSA rsa = RSA.Create(4096))
+ {
+ var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1);
+ request.CertificateExtensions.Add(
+ new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature , false));
+ request.CertificateExtensions.Add(
+ new X509EnhancedKeyUsageExtension(
+ new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false));
+ request.CertificateExtensions.Add(sanBuilder.Build());
+
+ var certificate= request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(3650)));
+ //certificate.FriendlyName = "localhost";
+ using (FileStream fs = new FileStream("localhost.crt", FileMode.Create, FileAccess.Write))
+ fs.Write(certificate.Export(X509ContentType.Pfx));
+
+ return certificate;
+ }
+ }
+
+ public void Dispose()
+ {
+ _socket?.Close();
+ _socket?.Dispose();
+ _socket = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ln.http/connections/Connection.cs b/ln.http/connections/Connection.cs
deleted file mode 100644
index 51395f1..0000000
--- a/ln.http/connections/Connection.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-// /**
-// * File: Connection.cs
-// * Author: haraldwolff
-// *
-// * This file and it's content is copyrighted by the Author and / or copyright holder.
-// * Any use wihtout proper permission is illegal and may lead to legal actions.
-// *
-// *
-// **/
-using System;
-using ln.type;
-using System.IO;
-using System.Text;
-using ln.logging;
-using ln.http.listener;
-using ln.http.exceptions;
-using ln.protocols.helper;
-
-namespace ln.http.connections
-{
- public abstract class Connection : IDisposable
- {
- public Listener Listener { get; private set; }
-
- public abstract IPv6 RemoteHost { get; }
- public abstract int RemotePort { get; }
-
- public abstract Stream GetStream();
-
- public Connection(Listener listener)
- {
- Listener = listener;
- }
-
- public virtual HttpRequest ReadRequest(HTTPServer httpServer)
- {
- try
- {
- if (HttpLikeProtocolReader.ReadRequest(GetStream(), Encoding.UTF8, out Request request))
- return new HttpRequest(httpServer, request);
- return null;
- } catch (IOException)
- {
- return null;
- } catch (ConnectionClosedException)
- {
- return null;
- } catch (Exception e)
- {
- Logging.Log(e);
- return null;
- }
- }
-
- public abstract void Close();
- public virtual void Dispose()
- {
- Close();
- Listener = null;
- }
-
- }
-}
diff --git a/ln.http/connections/HttpConnection.cs b/ln.http/connections/HttpConnection.cs
deleted file mode 100644
index bd4c692..0000000
--- a/ln.http/connections/HttpConnection.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// /**
-// * File: HttpConnection.cs
-// * Author: haraldwolff
-// *
-// * This file and it's content is copyrighted by the Author and / or copyright holder.
-// * Any use wihtout proper permission is illegal and may lead to legal actions.
-// *
-// *
-// **/
-using System;
-using System.IO;
-using ln.type;
-using System.Net.Sockets;
-using ln.http.listener;
-
-namespace ln.http.connections
-{
- public class HttpConnection : Connection
- {
- public TcpClient TcpClient { get; }
- public Endpoint RemoteEndpoint { get; }
-
- public HttpConnection(Listener listener, TcpClient tcpClient)
- :base(listener)
- {
- TcpClient = tcpClient;
- RemoteEndpoint = new Endpoint(TcpClient.Client.RemoteEndPoint);
- }
-
- public override IPv6 RemoteHost => RemoteEndpoint.Address;
- public override int RemotePort => RemoteEndpoint.Port;
-
- public override Stream GetStream() => TcpClient.GetStream();
-
- public override void Close()
- {
- TcpClient.Close();
- }
-
- }
-}
diff --git a/ln.http/connections/HttpsConnection.cs b/ln.http/connections/HttpsConnection.cs
deleted file mode 100644
index aaa581a..0000000
--- a/ln.http/connections/HttpsConnection.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-// /**
-// * File: HttpsConnection.cs
-// * Author: haraldwolff
-// *
-// * This file and it's content is copyrighted by the Author and / or copyright holder.
-// * Any use wihtout proper permission is illegal and may lead to legal actions.
-// *
-// *
-// **/
-using System;
-using System.IO;
-using ln.type;
-using System.Net.Security;
-using ln.http.listener;
-
-namespace ln.http.connections
-{
- public class HttpsConnection : Connection
- {
- Connection Connection { get; }
- SslStream sslStream { get; }
-
- public override IPv6 RemoteHost => Connection.RemoteHost;
- public override int RemotePort => Connection.RemotePort;
-
- public HttpsConnection(Listener listener,Connection connection,LocalCertificateSelectionCallback localCertificateSelectionCallback)
- :base(listener)
- {
- Connection = connection;
- sslStream = new SslStream(connection.GetStream(),false, null, localCertificateSelectionCallback);
- sslStream.AuthenticateAsServer(new System.Security.Cryptography.X509Certificates.X509Certificate());
- }
-
- public override HttpRequest ReadRequest(HTTPServer server)
- {
- throw new NotImplementedException();
- }
-
- public override Stream GetStream() => sslStream;
-
- public override void Close()
- {
- sslStream.Close();
- }
- }
-}
diff --git a/ln.http/listener/HttpListener.cs b/ln.http/listener/HttpListener.cs
deleted file mode 100644
index 4c505b5..0000000
--- a/ln.http/listener/HttpListener.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-// /**
-// * File: HttpListener.cs
-// * Author: haraldwolff
-// *
-// * This file and it's content is copyrighted by the Author and / or copyright holder.
-// * Any use wihtout proper permission is illegal and may lead to legal actions.
-// *
-// *
-// **/
-using System.Net.Sockets;
-using ln.type;
-using ln.http.connections;
-
-namespace ln.http.listener
-{
- public class HttpListener : Listener
- {
-
- protected TcpListener tcpListener;
-
- public HttpListener(int port) :this(IPv6.ANY,port){}
- public HttpListener(Endpoint endpoint) : this(endpoint.Address, endpoint.Port) {}
- public HttpListener(IPv6 listen, int port)
- : base(listen, port)
- {
- }
-
- public override Endpoint LocalEndpoint => new Endpoint(tcpListener.LocalEndpoint);
-
- public override Connection Accept()
- {
- return new HttpConnection(this,tcpListener.AcceptTcpClient());
- }
-
- public override bool IsOpen => (tcpListener != null);
-
- public override void Open()
- {
- tcpListener = new TcpListener(Listen, Port);
- tcpListener.Start();
- }
- public override void Close()
- {
- if (tcpListener != null)
- {
- tcpListener.Stop();
- tcpListener = null;
- }
- }
-
- public override void Dispose()
- {
- if (IsOpen)
- Close();
- }
-
- }
-}
diff --git a/ln.http/listener/HttpsListener.cs b/ln.http/listener/HttpsListener.cs
deleted file mode 100644
index 20b2f30..0000000
--- a/ln.http/listener/HttpsListener.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// /**
-// * File: HttpsListener.cs
-// * Author: haraldwolff
-// *
-// * This file and it's content is copyrighted by the Author and / or copyright holder.
-// * Any use wihtout proper permission is illegal and may lead to legal actions.
-// *
-// *
-// **/
-using ln.type;
-using ln.http.connections;
-using ln.http.cert;
-namespace ln.http.listener
-{
- public class HttpsListener : HttpListener
- {
- public HttpsListener(int port) : this(IPv6.ANY, port) { }
- public HttpsListener(IPv6 listen, int port) : base(listen, port) { }
-
- public CertContainer CertContainer { get; set; } = new CertContainer();
-
- public override Connection Accept()
- {
- return new HttpsConnection(this, base.Accept(),CertContainer.SelectCertificate);
- }
- }
-}
diff --git a/ln.http/listener/Listener.cs b/ln.http/listener/Listener.cs
deleted file mode 100644
index e1691a1..0000000
--- a/ln.http/listener/Listener.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// /**
-// * File: Listener.cs
-// * Author: haraldwolff
-// *
-// * This file and it's content is copyrighted by the Author and / or copyright holder.
-// * Any use wihtout proper permission is illegal and may lead to legal actions.
-// *
-// *
-// **/
-using System;
-using System.Net.Sockets;
-using ln.http.connections;
-using ln.logging;
-using ln.type;
-namespace ln.http.listener
-{
- public abstract class Listener : IDisposable
- {
- public IPv6 Listen { get; }
- public int Port { get; }
-
- public virtual Endpoint LocalEndpoint => new Endpoint(Listen, Port);
-
- public abstract bool IsOpen { get; }
-
- protected Listener(IPv6 listen, int port)
- {
- Listen = listen;
- Port = port;
- }
-
- public virtual void AcceptMany(Action handler)
- {
- while (IsOpen)
- {
- try
- {
- handler(Accept());
- }
- catch (SocketException soe)
- {
- if (IsOpen)
- Logging.Log(soe);
- }
- }
- }
-
- public abstract void Open();
- public abstract void Close();
-
- public abstract Connection Accept();
-
- public abstract void Dispose();
- }
-}
diff --git a/ln.http/ln.http.csproj b/ln.http/ln.http.csproj
index 9fd1d76..60ef035 100644
--- a/ln.http/ln.http.csproj
+++ b/ln.http/ln.http.csproj
@@ -10,7 +10,7 @@
(c) 2020 Harald Wolff-Thobaben
http server
9
- 0.5.2
+ 0.6.0
diff --git a/ln.http/router/StaticRouter.cs b/ln.http/router/StaticRouter.cs
index 6010938..fd41830 100644
--- a/ln.http/router/StaticRouter.cs
+++ b/ln.http/router/StaticRouter.cs
@@ -14,19 +14,42 @@ using ln.http.mime;
namespace ln.http.router
{
- public class StaticRouter
+ public class StaticRouter : IDisposable
{
- public String RootPath { get; }
+ private string _rootPath;
+ public String RootPath
+ {
+ get => _rootPath;
+ private set
+ {
+ _rootPath = Path.GetFullPath(value);
+ }
+ }
List indexNames = new List();
public String[] IndexNames => indexNames.ToArray();
+ private HTTPServer _httpServer;
+
+
+ public StaticRouter(HTTPServer httpServer)
+ {
+ _httpServer = httpServer;
+ httpServer.AddRouter(this.Route);
+ }
+
+ public StaticRouter(HTTPServer httpServer, string path)
+ :this(path)
+ {
+ _httpServer = httpServer;
+ httpServer.AddRouter(this.Route);
+ }
public StaticRouter(string path)
{
if (!Directory.Exists(path))
throw new FileNotFoundException();
- RootPath = Path.GetFullPath(path);
+ RootPath = path;
AddIndex("index.html");
AddIndex("index.htm");
@@ -63,6 +86,12 @@ namespace ln.http.router
}
return false;
}
+
+ public void Dispose()
+ {
+ _httpServer?.RemoveRouter(this.Route);
+ _httpServer = null;
+ }
}
}
diff --git a/ln.http/websocket/WebSocket.cs b/ln.http/websocket/WebSocket.cs
index 1823d72..aa2219d 100644
--- a/ln.http/websocket/WebSocket.cs
+++ b/ln.http/websocket/WebSocket.cs
@@ -1,12 +1,10 @@
using System;
using System.IO;
-using System.Threading;
using ln.logging;
using ln.http.exceptions;
using System.Security.Cryptography;
using System.Text;
using ln.type;
-using ln.http.connections;
namespace ln.http.websocket
{