185 lines
7.3 KiB
C#
185 lines
7.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using ln.logging;
|
|
using ln.http.exceptions;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading;
|
|
|
|
namespace ln.http
|
|
{
|
|
|
|
/*
|
|
public class HttpServer
|
|
{
|
|
public static bool DefaultRouteAuthentication { get; set; } = false;
|
|
|
|
private HashSet<HttpRouterDelegate> _routerDelegates = new HashSet<HttpRouterDelegate>();
|
|
public IEnumerable<HttpRouterDelegate> Routers => _routerDelegates;
|
|
|
|
public TextWriter AccessLogWriter { get; set; }
|
|
private ILogWriter _logWriter;
|
|
|
|
|
|
private HashSet<IHttpAuthenticationSource> _authenticationSources = new HashSet<IHttpAuthenticationSource>();
|
|
public IEnumerable<IHttpAuthenticationSource> AuthenticationSources => _authenticationSources;
|
|
|
|
|
|
public HttpServer() : this(Console.Out, new LogWriter(new ConsoleLogSink()))
|
|
{
|
|
}
|
|
|
|
public HttpServer(TextWriter accessLogWriter, ILogWriter logWriter)
|
|
{
|
|
AccessLogWriter = accessLogWriter;
|
|
_logWriter = logWriter;
|
|
}
|
|
public HttpServer(HttpRouterDelegate router)
|
|
: this()
|
|
{
|
|
AddRouter(router);
|
|
}
|
|
|
|
public void RegisterAuthenticationSource(IHttpAuthenticationSource authenticationSource) =>
|
|
_authenticationSources.Add(authenticationSource);
|
|
public void UnregisterAuthenticationSource(IHttpAuthenticationSource authenticationSource) =>
|
|
_authenticationSources.Remove(authenticationSource);
|
|
|
|
public void AddRouter(HttpRouter httpRouter) => AddRouter(httpRouter.RouteRequest);
|
|
public void AddRouter(HttpRouterDelegate routerDelegate) => _routerDelegates.Add(routerDelegate);
|
|
|
|
public void RemoveRouter(HttpRouter httpRouter) => RemoveRouter(httpRouter.RouteRequest);
|
|
public void RemoveRouter(HttpRouterDelegate routerDelegate) => _routerDelegates.Remove(routerDelegate);
|
|
|
|
public void Connection(HttpConnection httpConnection) =>
|
|
ThreadPool.QueueUserWorkItem((state => ConnectionWorker(httpConnection)));
|
|
|
|
public void ConnectionWorker(HttpConnection httpConnection)
|
|
{
|
|
try
|
|
{
|
|
bool keepalive = false;
|
|
do
|
|
{
|
|
DateTime start = DateTime.Now;
|
|
|
|
using (HttpRequest httpRequest = ReadRequest(httpConnection))
|
|
{
|
|
if (httpRequest == null)
|
|
break;
|
|
|
|
HttpContext httpContext = new HttpContext(this, httpRequest);
|
|
|
|
try
|
|
{
|
|
if (!RouteRequest(httpContext))
|
|
throw new HttpException(HttpStatusCode.NotFound);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
_logWriter?.Log(exception);
|
|
|
|
if (exception is HttpException httpException)
|
|
{
|
|
try
|
|
{
|
|
HttpContext errorContext = new HttpContext(httpContext, httpException);
|
|
if (!RouteRequest(errorContext))
|
|
{
|
|
errorContext.ResetRoutingStack(String.Format("/_err.html",
|
|
(int)httpException.HttpStatusCode));
|
|
RouteRequest(errorContext);
|
|
}
|
|
httpContext.Response = errorContext.Response;
|
|
}
|
|
finally
|
|
{
|
|
if (httpContext.Response is null)
|
|
httpContext.Response = HttpResponse
|
|
.InternalServerError()
|
|
.Content(
|
|
String.Format("An internal error occured ({0})", exception.ToString()));
|
|
}
|
|
}
|
|
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;
|
|
|
|
AccessLogWriter?.WriteLine("{0} {1} {2} {3} {4} {5} {6} {7}",
|
|
start,
|
|
end,
|
|
duration,
|
|
httpConnection.RemoteEndPoint?.ToString(),
|
|
httpContext.Response?.StatusCode.ToString() ?? "-",
|
|
httpContext.AuthenticatedPrincipal?.ToString() ?? "-",
|
|
httpContext.Request.Method,
|
|
httpContext.Request.RequestUri
|
|
);
|
|
AccessLogWriter?.Flush();
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
private bool RouteRequest(HttpContext httpContext)
|
|
{
|
|
foreach (var routerDelegate in _routerDelegates)
|
|
{
|
|
if (routerDelegate(httpContext))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private HttpRequest ReadRequest(HttpConnection httpConnection)
|
|
{
|
|
try
|
|
{
|
|
if (HttpLikeProtocolReader.ReadRequest(httpConnection.ClientStream, Encoding.UTF8, out Request request))
|
|
return new HttpRequest(this, request);
|
|
return null;
|
|
} catch (IOException)
|
|
{
|
|
return null;
|
|
} catch (ConnectionClosedException)
|
|
{
|
|
return null;
|
|
} catch (Exception e)
|
|
{
|
|
_logWriter?.Log(e);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
}
|