master
Harald Wolff 2022-02-07 09:29:30 +01:00
parent 8012f01dde
commit fda7d695d1
40 changed files with 800 additions and 670 deletions

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -19,7 +19,7 @@ namespace ln.http.tests
if (server != null)
return;
SimpleRouter testRouter = new SimpleRouter();
HttpRouter testRouter = new HttpRouter();
StaticRouter staticRouter = new StaticRouter(AppContext.BaseDirectory);
testRouter.AddSimpleRoute("/static/*", staticRouter);

View File

@ -0,0 +1,3 @@
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
ÄÖÜ

View File

@ -2,7 +2,6 @@
using System.Collections.Generic;
using ln.logging;
using ln.threading;
using ln.application;
using ln.http.listener;
using ln.http.connections;
using ln.http.exceptions;
@ -19,7 +18,9 @@ namespace ln.http
public static int defaultPort = 8080;
public static bool exclusivePortListener = false;
public IHttpRouter Router { get; set; }
public static bool DefaultRouteAuthentication { get; set; } = false;
public HttpRouterDelegate Router { get; set; }
public bool IsRunning => !shutdown;
public Logger Logger { get; set; }
@ -36,17 +37,17 @@ namespace ln.http
{
Logger = Logger.Default;
}
public HTTPServer(IHttpRouter router)
public HTTPServer(HttpRouterDelegate router)
: this()
{
Router = router;
}
public HTTPServer(Listener listener, IHttpRouter router)
public HTTPServer(Listener listener, HttpRouterDelegate router)
: this(router)
{
AddListener(listener);
}
public HTTPServer(Endpoint endpoint, IHttpRouter router)
public HTTPServer(Endpoint endpoint, HttpRouterDelegate router)
: this(new HttpListener(endpoint), router) { }
public void AddListener(Listener listener)
@ -129,36 +130,36 @@ namespace ln.http
{
using (HttpRequest httpRequest = connection.ReadRequest(this))
{
HttpResponse httpResponse = null;
if (httpRequest == null)
break;
HttpContext httpContext = new HttpContext()
{ Request = httpRequest, RoutableUri = httpRequest.RequestUri.AbsolutePath };
try
{
httpResponse = Router.Route(new HttpRoutingContext(httpRequest), httpRequest);
if (httpResponse == null)
httpResponse = HttpResponse.NotFound();
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))
httpResponse = httpException.HttpResponse;
httpContext.Response = httpException.HttpResponse;
else
httpResponse = HttpResponse.InternalServerError()
httpContext.Response = HttpResponse.InternalServerError()
.Content(String.Format("An internal error occured ({0})", exception.ToString()));
}
httpResponse.WriteTo(connection.GetStream());
httpResponse?.ContentStream?.Dispose();
httpContext.Response.WriteTo(connection.GetStream());
httpContext.Response?.ContentStream?.Dispose();
keepalive = httpResponse.GetHeader("connection", "keep-alive").Equals("keep-alive") && httpRequest
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);
} while (keepalive && false);
lock (this.currentConnections)
currentConnections.Remove(connection);
@ -207,6 +208,7 @@ namespace ln.http
// ;
}
/*
public static void StartSimpleServer(string[] arguments)
{
ArgumentContainer argumentContainer = new ArgumentContainer(new Argument[]
@ -218,7 +220,7 @@ namespace ln.http
argumentContainer.Parse(ref arguments);
SimpleRouter router = new SimpleRouter();
HttpRouter router = new HttpRouter();
router.AddSimpleRoute("/*", new RouterTarget((request) =>
{
HttpResponse response = new HttpResponse(request);
@ -244,6 +246,7 @@ namespace ln.http
new LoggingRouter(router));
server.Start();
}
*/
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace ln.http
{
[Flags]
public enum HttpArgumentSource : int{
AUTO = -1,
CONTENT = (1<<0),
PARAMETER = (1<<1),
HEADER = (1<<2),
QUERY = (1<<3)
}
}

View File

@ -0,0 +1,18 @@
using System;
namespace ln.http
{
[AttributeUsage(AttributeTargets.Parameter)]
public class HttpArgumentSourceAttribute : Attribute
{
public HttpArgumentSource ArgumentSource { get; set; }
public string ArgumentName { get; set; }
public HttpArgumentSourceAttribute(){}
public HttpArgumentSourceAttribute(HttpArgumentSource argumentSource)
{
ArgumentSource = argumentSource;
}
}
}

View File

@ -0,0 +1,24 @@
using ln.http.router;
namespace ln.http
{
public class HttpContext
{
public HttpRequest Request { get; set; }
public HttpResponse Response { get; set; }
public HttpPrincipal AuthenticatedPrincipal { get; private set; }
public string RoutableUri { get; set; }
public bool Authenticate(HttpAuthenticationDelegate authenticationDelegate)
{
if (authenticationDelegate(this, out HttpPrincipal principal))
{
AuthenticatedPrincipal = principal;
return true;
}
return false;
}
public void DeAuthenticate() => AuthenticatedPrincipal = null;
}
}

View File

@ -0,0 +1,181 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using ln.json;
using ln.json.mapping;
using ln.protocols.helper;
using ln.type;
namespace ln.http
{
public abstract class HttpEndpointController : HttpRouter
{
public HttpEndpointController()
{
Initialize();
}
void Initialize()
{
foreach (MethodInfo methodInfo in GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
foreach (MapAttribute mapAttribute in methodInfo.GetCustomAttributes<MapAttribute>())
{
MappedEndpoint mappedEndpoint = CreateMapping(mapAttribute, methodInfo);
Map(mappedEndpoint.HttpMethod, mappedEndpoint.Path, mappedEndpoint.Route);
}
}
}
MappedEndpoint CreateMapping(MapAttribute mapAttribute, MethodInfo methodInfo)
{
if (methodInfo.ReturnType == typeof(void))
return new MappedEndpoint.VoidEndpoint(this, mapAttribute, methodInfo);
return new MappedEndpoint.NonVoidEndpoint(this, mapAttribute, methodInfo);
}
public abstract class MappedEndpoint
{
public HttpMethod HttpMethod { get; }
public string Path { get; }
private HttpEndpointController EndpointController;
public MethodInfo MethodInfo { get; }
private ParameterInfo[] _parameterInfos;
private HttpArgumentSourceAttribute[] _argumentSourceAttributes;
private Type _returnType;
public MappedEndpoint(HttpEndpointController endpointController, MapAttribute mapAttribute, MethodInfo methodInfo)
{
EndpointController = endpointController;
HttpMethod = mapAttribute.Method;
Path = mapAttribute.Path;
MethodInfo = methodInfo;
_parameterInfos = MethodInfo.GetParameters();
_returnType = MethodInfo.ReturnType;
_argumentSourceAttributes = _parameterInfos
.Select((pi) => pi.GetCustomAttribute<HttpArgumentSourceAttribute>()).ToArray();
}
public abstract bool Route(HttpContext httpContext);
bool TryApplyParameters(HttpContext httpContext, out object[] parameters)
{
parameters = new object[_parameterInfos.Length];
for (int n = 0; n < _parameterInfos.Length; n++)
{
ParameterInfo parameterInfo = _parameterInfos[n];
if (parameterInfo.ParameterType.Equals(typeof(HttpContext)))
parameters[n] = httpContext;
else if (parameterInfo.ParameterType.Equals(typeof(HttpRequest)))
parameters[n] = httpContext.Request;
else if (parameterInfo.ParameterType.Equals(typeof(HttpPrincipal)))
parameters[n] = httpContext.AuthenticatedPrincipal;
else if (TryFindArgumentByName(
httpContext,
_argumentSourceAttributes[n]?.ArgumentSource ?? HttpArgumentSource.AUTO,
_argumentSourceAttributes[n]?.ArgumentName ?? _parameterInfos[n].Name,
out string parameterValue
))
{
if (!Cast.To(parameterValue, _parameterInfos[n].ParameterType, out parameters[n]))
{
parameters[n] = TypeDescriptor
.GetConverter(parameterInfo.ParameterType)
.ConvertFromInvariantString(parameterValue);
}
}
else if (_argumentSourceAttributes[n].ArgumentSource == HttpArgumentSource.CONTENT)
{
if (httpContext.Request.Headers.TryGetValue("Content-Type", out string contentType) &&
contentType.Equals("application/json"))
{
using (TextReader reader = httpContext.Request.ContentStream.TextReader())
parameters[n] = JSONMapper.DefaultMapper.FromJson(JSONParser.Parse(reader), _parameterInfos[n].ParameterType);
}
}
else if (_parameterInfos[n].HasDefaultValue)
{
parameters[n] = _parameterInfos[n].DefaultValue;
}
else
return false;
}
return true;
}
bool TryFindArgumentByName(HttpContext httpContext, HttpArgumentSource argumentSource, string parameterName, out string parameterValue)
{
if (((argumentSource & HttpArgumentSource.PARAMETER) == HttpArgumentSource.PARAMETER) && httpContext.Request.TryGetParameter(parameterName, out parameterValue))
return true;
else if (((argumentSource & HttpArgumentSource.HEADER) == HttpArgumentSource.HEADER) &&
(httpContext.Request.Headers.TryGetValue(parameterName, out parameterValue)))
return true;
else if (((argumentSource & HttpArgumentSource.QUERY) == HttpArgumentSource.QUERY) &&
(httpContext.Request.Query.TryGetValue(parameterName, out parameterValue)))
return true;
parameterValue = null;
return false;
}
private object InvokeMethod(HttpContext httpContext)
{
if (!TryApplyParameters(httpContext, out object[] parameters))
return HttpResponse.InternalServerError().Content("could not apply parameters");
else
return MethodInfo.Invoke(EndpointController, parameters);
}
public class NonVoidEndpoint : MappedEndpoint
{
public NonVoidEndpoint(HttpEndpointController endpointController, MapAttribute mapAttribute, MethodInfo methodInfo)
: base(endpointController, mapAttribute, methodInfo)
{
}
public override bool Route(HttpContext httpContext)
{
object returnedValue = InvokeMethod(httpContext);
if (returnedValue is HttpResponse httpResponse)
httpContext.Response = httpResponse;
else if ((returnedValue is JSONValue jsonResult) || (JSONMapper.DefaultMapper.Serialize(returnedValue, out jsonResult)))
httpContext.Response = HttpResponse.Default(httpContext.Request.Method)
.Content(jsonResult);
else
httpContext.Response = HttpResponse.InternalServerError().Content("Method result could not be serialized");
return true;
}
}
public class VoidEndpoint : MappedEndpoint
{
public VoidEndpoint(HttpEndpointController endpointController, MapAttribute mapAttribute, MethodInfo methodInfo)
: base(endpointController, mapAttribute, methodInfo)
{
}
public override bool Route(HttpContext httpContext)
{
object returnedValue = InvokeMethod(httpContext);
if (returnedValue is HttpResponse httpResponse)
httpContext.Response = httpResponse;
else
httpContext.Response ??= HttpResponse.Default(httpContext.Request.Method);
return true;
}
}
}
}
}

View File

@ -1,8 +1,13 @@
using System;
namespace ln.http
{
[Flags]
public enum HttpMethod {
UNKOWN, HEAD, GET, POST, PUT, PATCH, DELETE, CONNECT, OPTIONS, TRACE, PROPFIND, MKCOL, LOCK, UNLOCK
NONE = 0,
HEAD, GET, POST, PUT, PATCH, DELETE, CONNECT, OPTIONS, TRACE, PROPFIND, MKCOL, LOCK, UNLOCK,
ANY = -1
}
}

View File

@ -0,0 +1,49 @@
using System.Collections.Generic;
using System.Text;
using ln.http.router;
namespace ln.http
{
public class HttpPrincipal
{
public string UniqueId { get; set; }
public string Username { get; set; }
public HttpPrincipal AuthenticatedPrincipal { get; set; }
private Dictionary<string, HttpAccessRights> permissions = new Dictionary<string, HttpAccessRights>();
public IEnumerable<KeyValuePair<string, HttpAccessRights>> Permissions => permissions;
public void AddPermission(string roleName, HttpAccessRights accessRights)
{
if (permissions.TryGetValue(roleName, out HttpAccessRights roleAccessFlags))
{
roleAccessFlags |= accessRights;
permissions[roleName] = roleAccessFlags;
}
else
{
permissions.Add(roleName, accessRights);
}
}
public void RemovePermission(string roleName, HttpAccessRights accessRights)
{
if (permissions.TryGetValue(roleName, out HttpAccessRights roleAccessFlags))
{
roleAccessFlags &= ~accessRights;
permissions[roleName] = roleAccessFlags;
}
}
public bool HasPermission(string roleName, HttpAccessRights accessRights) =>
permissions.TryGetValue(roleName, out HttpAccessRights roleAccessFlags) &&
((roleAccessFlags & accessRights) == accessRights);
public override string ToString()
{
if (AuthenticatedPrincipal is null)
return string.Format("{0}[{1}]", Username, UniqueId);
else
return string.Format("{2}=>{0}[{1}]", Username, UniqueId, AuthenticatedPrincipal.ToString());
}
}
}

View File

@ -28,8 +28,7 @@ namespace ln.http
public Uri BaseUri { get; }
public Uri RequestUri { get; }
Dictionary<String, String> requestCookies;
Dictionary<string, String> requestParameters;
@ -42,7 +41,7 @@ namespace ln.http
if (Enum.TryParse(BaseRequest.Method, out HttpMethod httpMethod))
Method = httpMethod;
else
Method = HttpMethod.UNKOWN;
Method = HttpMethod.NONE;
Headers.TryGetValue("Host", out string host);
@ -73,8 +72,13 @@ namespace ln.http
RequestUri = new Uri(BaseUri, BaseRequest.RequestUri);
Query = new QueryStringParameters(RequestUri.Query);
requestParameters = new Dictionary<string, string>();
requestCookies = new Dictionary<string, string>();
if (Headers.TryGetValue("Cookie", out string cookies))
SetupCookies(cookies);
}
private void SetupCookies(string cookies)
@ -129,6 +133,8 @@ namespace ln.http
return value;
}
public bool TryGetParameter(String parameterName, out string parameterValue) =>
requestParameters.TryGetValue(parameterName, out parameterValue);
public void SetParameter(String parameterName, String parameterValue) =>
requestParameters[parameterName] = parameterValue;

View File

@ -2,6 +2,8 @@
using System.IO;
using System.Collections.Generic;
using System.Linq;
using ln.json;
using ln.json.mapping;
namespace ln.http
{
@ -40,9 +42,7 @@ namespace ln.http
public HttpResponse(HttpRequest httpRequest, Stream contentStream) : this(contentStream) { }
public HttpResponse(Stream contentStream)
{
ContentStream = contentStream;
ContentWriter = null;
HasCustomContentStream = true;
Content(contentStream);
HttpStatusCode = HttpStatusCode.OK;
SetHeader("content-type", "text/html");
@ -153,6 +153,18 @@ namespace ln.http
public static HttpResponse ServiceUnavailable() => new HttpResponse(HttpStatusCode.ServiceUnavailable);
public static HttpResponse GatewayTimeout() => new HttpResponse(HttpStatusCode.GatewayTimeout);
public static HttpResponse Default(HttpMethod httpMethod)
{
switch (httpMethod)
{
case HttpMethod.DELETE:
return NoContent();
case HttpMethod.POST:
return Created();
default:
return OK();
}
}
public HttpResponse Content(Exception exception)
@ -171,6 +183,16 @@ namespace ln.http
return this;
}
public HttpResponse Content(JSONValue json) => ContentType("application/json").Content(json.ToString());
public HttpResponse Content(Stream contentStream)
{
ContentStream = contentStream;
ContentWriter = null;
HasCustomContentStream = true;
return this;
}
public virtual void WriteTo(Stream stream)
{
SetHeader("Content-Length", ContentStream.Length.ToString());

View File

@ -0,0 +1,10 @@
using ln.http.router;
namespace ln.http
{
public class HttpRolePermission
{
public string RoleName { get; set; }
public HttpAccessRights AccessRights { get; set; }
}
}

View File

@ -0,0 +1,271 @@
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Linq;
namespace ln.http
{
public delegate bool HttpRouterDelegate(HttpContext context);
public delegate bool HttpAuthenticationDelegate(HttpContext httpContext, out HttpPrincipal principal);
public delegate bool HttpAuthorizationDelegate(HttpContext httpContext);
public delegate void HttpFilterDelegate(HttpContext httpContext);
public enum HttpRoutePriority : int { HIGHEST = 0, HIGH = 1, NORMAL = 2, LOW = 3, LOWEST = 4 }
public class HttpRouter
{
public event HttpFilterDelegate HttpFilters;
public event HttpAuthenticationDelegate AuthenticationDelegates;
private List<HttpMapping>[] _mappings = new List<HttpMapping>[5];
public HttpRouter()
{
for (int n = 0; n < 5; n++)
_mappings[n] = new List<HttpMapping>();
}
public HttpMapping Map(HttpMethod httpMethod, string uri, HttpRouterDelegate routerDelegate) =>
Map(httpMethod, uri, HttpRoutePriority.NORMAL, routerDelegate);
public HttpMapping Map(HttpMethod httpMethod, string uri, HttpRoutePriority priority, HttpRouterDelegate routerDelegate)
{
HttpMapping httpMapping = new HttpMapping(httpMethod, RegexFromRoute(uri), routerDelegate);
_mappings[(int)priority].Add(httpMapping);
return httpMapping;
}
public bool Route(HttpContext httpContext)
{
string residual = "";
if (AuthenticationDelegates is not null)
{
foreach (HttpAuthenticationDelegate authenticationDelegate in AuthenticationDelegates.GetInvocationList())
{
if (httpContext.Authenticate(authenticationDelegate))
break;
}
}
HttpFilters?.Invoke(httpContext);
for (int n = 0; n < _mappings.Length; n++)
{
foreach (HttpMapping httpMapping in _mappings[n])
{
if ((httpMapping.Method == httpContext.Request.Method) || (httpMapping.Method == HttpMethod.ANY))
{
Match match = httpMapping.UriRegex.Match(httpContext.RoutableUri);
if (match.Success)
{
foreach (Group group in match.Groups)
{
httpContext.Request?.SetParameter(group.Name, group.Value);
if (group.Name.Equals("_"))
if (group.Value.StartsWith("/", StringComparison.InvariantCulture))
residual = group.Value;
else
residual = "/" + group.Value;
}
string saveRoutableUri = httpContext.RoutableUri;
httpContext.RoutableUri = residual;
if (httpMapping.Route(httpContext))
return true;
httpContext.RoutableUri = saveRoutableUri;
}
}
}
if (httpContext.Response is not null)
break;
}
return false;
}
private string RegexFromRoute(string route)
{
string[] parts = route.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();
return string.Format("^{0}/?$", string.Join("/", reparts));
}
public class HttpMapping
{
public HttpMethod Method { get; set; }
public Regex UriRegex { get; set; }
public HttpRouterDelegate RouterDelegate { get; set; }
public bool AuthenticationRequired { get; set; }
public HttpAuthorizationDelegate AuthorizationDelegate { get; set; }
public event HttpFilterDelegate HttpFilters;
public HttpMapping(HttpMethod httpMethod, string reUri, HttpRouterDelegate routerDelegate)
{
Method = httpMethod;
UriRegex = new Regex(reUri);
RouterDelegate = routerDelegate;
AuthenticationRequired = HTTPServer.DefaultRouteAuthentication;
}
public HttpMapping UseFilter(HttpFilterDelegate filterDelegate)
{
HttpFilters += filterDelegate;
return this;
}
public HttpMapping Authenticate()
{
AuthenticationRequired = true;
return this;
}
public HttpMapping Anonymous()
{
AuthenticationRequired = false;
return this;
}
public HttpMapping Authorize(HttpAuthorizationDelegate authorizationDelegate)
{
AuthorizationDelegate = authorizationDelegate;
return this;
}
public bool Route(HttpContext httpContext)
{
if (AuthenticationRequired && httpContext.AuthenticatedPrincipal is null)
return false;
if ((AuthorizationDelegate is not null) && (!AuthorizationDelegate(httpContext)))
return false;
HttpFilters?.Invoke(httpContext);
return RouterDelegate(httpContext);
}
}
/*
List<SimpleRoute> routes = new List<SimpleRoute>();
public SimpleRoute[] Routes => routes.ToArray();
*/
/*
public void AddSimpleRoute(string simpleRoute, Func<HttpRoutingContext, HttpRequest, HttpResponse> target) => AddSimpleRoute(simpleRoute, new RouterTarget(target));
public void AddSimpleRoute(string simpleRoute, Func<string, HttpRequest, HttpResponse> target) => AddSimpleRoute(simpleRoute, new RouterTarget(target));
public void AddSimpleRoute(string simpleRoute, Func<HttpRequest, HttpResponse> 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)
{
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);
}
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;
}
}
*/
}
}

View File

@ -2,8 +2,5 @@
using ln.http.router;
namespace ln.http
{
public interface IHttpRouter
{
HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest);
}
}

View File

@ -0,0 +1,18 @@
using System;
namespace ln.http
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class MapAttribute : Attribute
{
public string Path { get; set; }
public HttpMethod Method { get; set; }
public MapAttribute(){}
public MapAttribute(HttpMethod method, string path)
{
Method = method;
Path = path;
}
}
}

View File

@ -29,7 +29,8 @@ namespace ln.http
public string this[string key] {
get => parameters[key];
set => throw new NotImplementedException(); }
set => throw new NotSupportedException();
}
public ICollection<string> Keys => parameters.Keys;
public ICollection<string> Values => parameters.Values;

View File

@ -0,0 +1,38 @@
using System.Reflection;
using ln.http.router;
namespace ln.http
{
public static class RoleAuthorization
{
public static HttpAuthorizationDelegate Require(string roleName, HttpAccessRights accessRights)
{
return context => context.AuthenticatedPrincipal?.HasPermission(roleName, accessRights) ?? false;
}
public static HttpAuthorizationDelegate RequireAll(params HttpAuthorizationDelegate[] authorizationDelegates)
{
return context =>
{
foreach (HttpAuthorizationDelegate authorizationDelegate in authorizationDelegates)
{
if (!authorizationDelegate(context))
return false;
}
return true;
};
}
public static HttpAuthorizationDelegate RequireOneOf(params HttpAuthorizationDelegate[] authorizationDelegates)
{
return context =>
{
foreach (HttpAuthorizationDelegate authorizationDelegate in authorizationDelegates)
{
if (authorizationDelegate(context))
return true;
}
return false;
};
}
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace ln.http.exceptions
{
public class PayloadTooLargeException: HttpException
{
public PayloadTooLargeException(int payloadsize,int limit)
:base(513,"Payload too large")
{
HttpResponse = new HttpResponse(HttpStatusCode.PayloadTooLarge).Content(String.Format("Payload too large ({0} > {1})", payloadsize, limit));
}
}
}

View File

@ -1,70 +0,0 @@
// /**
// * File: UnbufferedStreamreader.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 System.Text;
namespace ln.http.io
{
public class UnbufferedStreamReader : TextReader
{
public Stream Stream { get; }
public UnbufferedStreamReader(Stream stream)
{
Stream = stream;
}
public override int Read() => Stream.ReadByte();
public override string ReadLine()
{
StringBuilder stringBuilder = new StringBuilder();
char ch;
int _ch = 0;
while ((_ch = Stream.ReadByte()) != -1)
{
ch = (char)_ch;
if (ch == '\r')
{
ch = (char)Stream.ReadByte();
if (ch == '\n')
return stringBuilder.ToString();
stringBuilder.Append('\r');
}
stringBuilder.Append(ch);
}
if ((_ch == -1) && (stringBuilder.Length == 0))
return null;
return stringBuilder.ToString();
}
public string ReadToken()
{
StringBuilder stringBuilder = new StringBuilder();
char ch = (char)Stream.ReadByte();
while (char.IsWhiteSpace(ch))
ch = (char)Stream.ReadByte();
while (!char.IsWhiteSpace(ch))
{
stringBuilder.Append(ch);
ch = (char)Stream.ReadByte();
}
return stringBuilder.ToString();
}
}
}

View File

@ -27,7 +27,10 @@ namespace ln.http.listener
public override Endpoint LocalEndpoint => new Endpoint(tcpListener.LocalEndpoint);
public override Connection Accept() => new HttpConnection(this,tcpListener.AcceptTcpClient());
public override Connection Accept()
{
return new HttpConnection(this,tcpListener.AcceptTcpClient());
}
public override bool IsOpen => (tcpListener != null);

View File

@ -8,7 +8,9 @@
// *
// **/
using System;
using System.Net.Sockets;
using ln.http.connections;
using ln.logging;
using ln.type;
namespace ln.http.listener
{
@ -30,7 +32,17 @@ namespace ln.http.listener
public virtual void AcceptMany(Action<Connection> handler)
{
while (IsOpen)
handler(Accept());
{
try
{
handler(Accept());
}
catch (SocketException soe)
{
if (IsOpen)
Logging.Log(soe);
}
}
}
public abstract void Open();

View File

@ -10,11 +10,12 @@
<Copyright>(c) 2020 Harald Wolff-Thobaben</Copyright>
<PackageTags>http server</PackageTags>
<LangVersion>9</LangVersion>
<PackageVersion>0.5.0</PackageVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ln.application" Version="0.1" />
<PackageReference Include="ln.collections" Version="0.1" />
<PackageReference Include="ln.json" Version="1.0.8-ci" />
<PackageReference Include="ln.logging" Version="1.0" />
<PackageReference Include="ln.threading" Version="0.2.1" />
<PackageReference Include="ln.type" Version="0.1-*" />

View File

@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
namespace ln.http.rest
{
public abstract partial class CRUDObjectContainer
{
class RegisteredType
{
public CRUDObjectContainer ObjectContainer { get; }
public Type ObjectType { get; }
Func<object,object> _idGetter;
Dictionary<object, object> objectCache = new Dictionary<object, object>();
public IEnumerable<FieldDescriptor> FieldDescriptors => fieldDescriptors;
List<FieldDescriptor> fieldDescriptors = new List<FieldDescriptor>();
public RegisteredType(CRUDObjectContainer objectContainer,Type objectType,Func<object,object> idGetter)
{
ObjectContainer = objectContainer;
ObjectType = objectType;
_idGetter = idGetter;
}
public bool TryGetObjectID(object objectInstance,out object objectIdentifier)
{
try
{
objectIdentifier = _idGetter(objectInstance);
} catch (Exception e)
{
objectIdentifier = null;
return false;
}
return true;
}
public void AddCachedObject(object objectInstance)
{
Type objectType = objectInstance.GetType();
if (!ObjectType.Equals(objectType))
throw new ArgumentException();
if (!TryGetObjectID(objectInstance, out object objectIdentifier))
throw new ArgumentOutOfRangeException();
objectCache.Add(objectIdentifier, objectInstance);
}
public void RemoveCachedObject(object objectInstance)
{
Type objectType = objectInstance.GetType();
if (!ObjectType.Equals(objectType))
throw new ArgumentException();
if (!TryGetObjectID(objectInstance, out object objectIdentifier))
throw new ArgumentOutOfRangeException();
objectCache.Remove(objectIdentifier);
}
}
}
}

View File

@ -1,98 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace ln.http.rest
{
public delegate void CRUDEvent(CRUDObjectContainer sender, CRUDEventArgs args);
public enum CRUDEventType { CREATE, READ, UPDATE, DELETE }
public class CRUDEventArgs : EventArgs
{
public CRUDEventType EventType { get; }
public Type ObjectType { get; }
public object ObjectIdentity { get; }
public object ObjectInstance { get; }
public FieldValueList FieldValues { get; }
public CRUDEventArgs(CRUDEventType eventType, Type objectType, object objectIdentity, object objectInstance, FieldValueList fieldValues)
{
EventType = eventType;
ObjectType = objectType;
ObjectIdentity = objectIdentity;
ObjectInstance = objectInstance;
FieldValues = fieldValues;
}
}
public abstract partial class CRUDObjectContainer
{
public event CRUDEvent OnCRUDEvent;
Dictionary<Type, RegisteredType> registeredTypes = new Dictionary<Type, RegisteredType>();
public CRUDObjectContainer()
{ }
public abstract bool TryGetObjectIdentifier(object objectInstance, out object objectIdentifier);
public abstract bool TryCreateObject(Type objectType, FieldValueList fieldValues, out object objectInstance);
public abstract bool TryLookupObject(Type objectType, object objectIdentifier, out object objectInstance);
public abstract bool TryUpdateObject(Type objectType, object objectIdentifier, FieldValueList fieldValues);
public abstract bool TryDeleteObject(Type objectType, object objectIdentifier);
public virtual bool TryUpdateObject(object objectInstance, FieldValueList fieldValues)
{
if (TryGetObjectIdentifier(objectInstance, out object objectIdentifier))
return TryUpdateObject(objectInstance.GetType(), objectIdentifier, fieldValues);
return false;
}
public virtual bool TryDeleteObject(object objectInstance)
{
if (TryGetObjectIdentifier(objectInstance, out object objectIdentifier))
return TryDeleteObject(objectInstance.GetType(), objectIdentifier);
return false;
}
protected void FireCRUDEvent(CRUDEventArgs args) => OnCRUDEvent?.Invoke(this, args);
protected void FireCRUDEVent(CRUDEventType EventType, Type ObjectType, object ObjectIdentity, object ObjectInstance, FieldValueList FieldValues)
=> FireCRUDEvent(new CRUDEventArgs(EventType, ObjectType, ObjectIdentity, ObjectInstance, FieldValues));
public virtual IEnumerable<Type> RegisteredTypes => registeredTypes.Keys;
public virtual bool ContainsRegisteredType(Type objectType) => registeredTypes.ContainsKey(objectType);
public virtual bool TryRegisterType(Type objectType) => TryRegisterType(objectType, null);
public virtual bool TryRegisterType(Type objectType, Func<object,object> idGetter)
{
if (ContainsRegisteredType(objectType))
throw new ArgumentException("objectType already registered", nameof(objectType));
RegisteredType registeredType = new RegisteredType(this, objectType, idGetter);
registeredTypes.Add(objectType, registeredType);
return true;
}
public virtual bool TryGetFieldDescriptors(Type objectType, out FieldDescriptor[] fieldDescriptors)
{
if (registeredTypes.TryGetValue(objectType, out RegisteredType registeredType))
{
fieldDescriptors = registeredType.FieldDescriptors.ToArray();
return true;
}
fieldDescriptors = null;
return false;
}
public virtual IEnumerable<object> EnumerateObjectInstances(Type objectType) => EnumerateObjectInstances(objectType, null);
public abstract IEnumerable<object> EnumerateObjectInstances(Type objectType, FieldValueList conditionalFieldValues);
public abstract bool AddForeignObjectInstance(object objectInstance);
}
}

View File

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace ln.http.rest
{
public class FieldDescriptor
{
Action<object, object> setter;
Func<object, object> getter;
public Type OwningType { get; }
public string FieldName { get; }
public Type FieldType { get; }
public bool CanWrite { get; }
public FieldDescriptor(FieldInfo fieldInfo)
{
OwningType = fieldInfo.DeclaringType;
FieldName = fieldInfo.Name;
FieldType = fieldInfo.FieldType;
CanWrite = !fieldInfo.IsInitOnly;
getter = fieldInfo.GetValue;
setter = fieldInfo.SetValue;
}
public FieldDescriptor(PropertyInfo propertyInfo)
{
OwningType = propertyInfo.DeclaringType;
FieldName = propertyInfo.Name;
FieldType = propertyInfo.PropertyType;
CanWrite = propertyInfo.CanWrite;
getter = propertyInfo.GetValue;
setter = propertyInfo.SetValue;
}
public void SetFieldValue(object objectInstance, object fieldValue) => setter(objectInstance, fieldValue);
public object GetFieldValue(object objectInstance) => getter(objectInstance);
}
}

View File

@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
namespace ln.http.rest
{
public class FieldValueList
{
public Type ObjectType { get; }
Dictionary<string, object> fieldValues = new Dictionary<string, object>();
public FieldValueList(Type objectType)
{
ObjectType = objectType;
}
public IEnumerable<string> FieldNames => fieldValues.Keys;
public object GetFieldValue(string fieldName) => fieldValues[fieldName];
public void SetFieldValue(string fieldName, object fieldValue) => fieldValues[fieldName] = fieldValue;
public void RemoveFieldValue(string fieldName) => fieldValues.Remove(fieldName);
}
}

View File

@ -1,22 +0,0 @@
using ln.http.router;
using System;
using System.Collections.Generic;
using System.Text;
namespace ln.http.rest
{
public class RestAPIAdapter : IHttpRouter
{
public CRUDObjectContainer ObjectContainer { get; }
public RestAPIAdapter(CRUDObjectContainer objectContainer)
{
ObjectContainer = objectContainer;
}
public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
{
throw new NotImplementedException();
}
}
}

View File

@ -12,7 +12,7 @@ using ln.http.mime;
namespace ln.http.router
{
public class FileRouter : IHttpRouter
public class FileRouter
{
public string FileName { get; set; }
@ -24,13 +24,11 @@ namespace ln.http.router
FileName = filename;
}
public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
public bool Route(HttpContext httpContext)
{
HttpResponse httpResponse = new HttpResponse(httpRequest, new FileStream(FileName, FileMode.Open));
httpResponse.SetHeader("content-type", MimeTypeMap.GetMimeType(Path.GetExtension(FileName)));
return httpResponse;
httpContext.Response = new HttpResponse(httpContext.Request, new FileStream(FileName, FileMode.Open));
httpContext.Response.SetHeader("content-type", MimeTypeMap.GetMimeType(Path.GetExtension(FileName)));
return true;
}
}

View File

@ -0,0 +1,13 @@
using System;
namespace ln.http.router
{
[Flags]
public enum HttpAccessRights
{
READ = (1<<0),
WRITE = (1<<1),
EXECUTE = (1<<2),
SPECIAL = (1<<3)
}
}

View File

@ -12,28 +12,28 @@ using ln.logging;
using System.Diagnostics;
namespace ln.http.router
{
public class LoggingRouter : IHttpRouter
public class LoggingRouter
{
IHttpRouter Next { get; set; }
HttpRouterDelegate Next { get; set; }
Logger Logger { get; }
public LoggingRouter(IHttpRouter next)
public LoggingRouter(HttpRouterDelegate next)
:this(next, Logger.Default)
{}
public LoggingRouter(IHttpRouter next,Logger logger)
public LoggingRouter(HttpRouterDelegate next,Logger logger)
{
Next = next;
Logger = logger;
}
public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
public bool Route(HttpContext httpContext)
{
DateTime start = DateTime.Now;
HttpResponse response = null;
bool success = false;
try
{
response = Next.Route(routingContext, httpRequest);
success = Next(httpContext);
}
catch (Exception e)
{
@ -44,16 +44,17 @@ namespace ln.http.router
DateTime end = DateTime.Now;
TimeSpan duration = end - start;
Logger.Log(LogLevel.INFO, "{0} {1} {2} {3} {4}",
Logger.Log(LogLevel.INFO, "{0} {1} {2} {3} {4} {5} {6}",
start,
end,
duration,
response?.StatusCode.ToString() ?? "-",
httpRequest?.Method,
httpRequest?.RequestUri
httpContext.Response?.StatusCode.ToString() ?? "-",
httpContext.AuthenticatedPrincipal?.ToString() ?? "-",
httpContext.Request.Method,
httpContext.Request.RequestUri
);
}
return response;
return success;
}
}
}

View File

@ -2,6 +2,7 @@
using ln.http.exceptions;
namespace ln.http.router
{
/*
public class RouterTarget :IHttpRouter
{
public Func<HttpRoutingContext,HttpRequest, HttpResponse> Target { get; }
@ -58,4 +59,5 @@ namespace ln.http.router
}
*/
}

View File

@ -1,113 +0,0 @@
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace ln.http.router
{
public delegate bool RouterFilterDelegate(SimpleRouter sender, ref HttpRoutingContext routingContext, HttpRequest httpRequest, out HttpResponse httpResponse);
public class SimpleRouter : IHttpRouter
{
public event RouterFilterDelegate OnRoute;
List<SimpleRoute> routes = new List<SimpleRoute>();
public SimpleRoute[] Routes => routes.ToArray();
public SimpleRouter()
{
}
public void AddSimpleRoute(string simpleRoute, Func<HttpRoutingContext, HttpRequest, HttpResponse> target) => AddSimpleRoute(simpleRoute, new RouterTarget(target));
public void AddSimpleRoute(string simpleRoute, Func<string, HttpRequest, HttpResponse> target) => AddSimpleRoute(simpleRoute, new RouterTarget(target));
public void AddSimpleRoute(string simpleRoute, Func<HttpRequest, HttpResponse> 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)
{
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);
}
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;
}
}
}
}

View File

@ -14,7 +14,7 @@ using ln.http.mime;
namespace ln.http.router
{
public class StaticRouter : IHttpRouter
public class StaticRouter
{
public String RootPath { get; }
@ -35,9 +35,9 @@ namespace ln.http.router
public void AddIndex(string indexName) => indexNames.Add(indexName);
public void RemoveIndex(string indexName) => indexNames.Remove(indexName);
public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
public bool Route(HttpContext httpContext)
{
string finalPath = routingContext.Path.Length > 0 ? Path.Combine(RootPath, routingContext.Path.Substring(1)) : ".";
string finalPath = httpContext.RoutableUri.Length > 0 ? Path.Combine(RootPath, httpContext.RoutableUri.Substring(1)) : ".";
if (Directory.Exists(finalPath))
{
@ -56,12 +56,12 @@ namespace ln.http.router
{
lock (this)
{
HttpResponse httpResponse = new HttpResponse(httpRequest, new FileStream(finalPath, FileMode.Open, FileAccess.Read));
httpResponse.SetHeader("content-type", MimeTypeMap.GetMimeType(Path.GetExtension(finalPath)));
return httpResponse;
httpContext.Response = new HttpResponse(httpContext.Request, new FileStream(finalPath, FileMode.Open, FileAccess.Read));
httpContext.Response.SetHeader("content-type", MimeTypeMap.GetMimeType(Path.GetExtension(finalPath)));
return true;
}
}
return null;
return false;
}
}

View File

@ -1,27 +1,28 @@
using ln.http.exceptions;
using System.Collections.Generic;
using System.Net.Http;
namespace ln.http.router
{
public class VirtualHostRouter : IHttpRouter
public class VirtualHostRouter
{
public IHttpRouter DefaultRoute { get; set; }
public HttpRouterDelegate DefaultRoute { get; set; }
Dictionary<string, IHttpRouter> virtualHosts = new Dictionary<string, IHttpRouter>();
Dictionary<string, HttpRouterDelegate> virtualHosts = new Dictionary<string, HttpRouterDelegate>();
public VirtualHostRouter()
{
}
public VirtualHostRouter(IHttpRouter defaultRoute)
public VirtualHostRouter(HttpRouterDelegate defaultRoute)
{
DefaultRoute = defaultRoute;
}
public VirtualHostRouter(IEnumerable<KeyValuePair<string, IHttpRouter>> routes)
public VirtualHostRouter(IEnumerable<KeyValuePair<string, HttpRouterDelegate>> routes)
{
foreach (KeyValuePair<string, IHttpRouter> route in routes)
foreach (KeyValuePair<string, HttpRouterDelegate> route in routes)
virtualHosts.Add(route.Key, route.Value);
}
public VirtualHostRouter(IHttpRouter defaultRoute,IEnumerable<KeyValuePair<string, IHttpRouter>> routes)
public VirtualHostRouter(HttpRouterDelegate defaultRoute,IEnumerable<KeyValuePair<string, HttpRouterDelegate>> routes)
:this(routes)
{
DefaultRoute = defaultRoute;
@ -29,20 +30,20 @@ namespace ln.http.router
public VirtualHostRouter(VirtualHostRouter source)
: this(source.virtualHosts) { }
public void Add(string hostname,IHttpRouter router) => virtualHosts.Add(hostname, router);
public void Add(string hostname,HttpRouterDelegate router) => virtualHosts.Add(hostname, router);
public void Remove(string hostname) => virtualHosts.Remove(hostname);
public bool Contains(string hostname) => virtualHosts.ContainsKey(hostname);
public bool TryGetValue(string hostname, out IHttpRouter router) => virtualHosts.TryGetValue(hostname, out router);
public bool TryGetValue(string hostname, out HttpRouterDelegate router) => virtualHosts.TryGetValue(hostname, out router);
public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
public bool Route(HttpContext httpContext)
{
if (virtualHosts.TryGetValue(httpRequest.Host, out IHttpRouter virtualHost))
return virtualHost.Route(routingContext, httpRequest);
if (virtualHosts.TryGetValue(httpContext.Request.Host, out HttpRouterDelegate virtualHost))
return virtualHost(httpContext);
if (DefaultRoute != null)
return DefaultRoute.Route(routingContext, httpRequest);
return DefaultRoute(httpContext);
throw new HttpException(410, string.Format("Gone. Hostname {0} not found on this server.", httpRequest.Host));
throw new HttpException(410, string.Format("Gone. Hostname {0} not found on this server.", httpContext.Request.Host));
}
}
}

View File

@ -4,7 +4,7 @@ using ln.http.exceptions;
using ln.logging;
namespace ln.http.router
{
public class WebsocketRouter : IHttpRouter
public class WebsocketRouter
{
Func<HttpRequest, WebSocket> createWebsocket;
@ -15,9 +15,9 @@ namespace ln.http.router
public WebSocket CreateWebSocket(HttpRequest request) => createWebsocket(request);
public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
public bool Route(HttpContext httpContext)
{
WebSocket websocket = CreateWebSocket(httpRequest);
WebSocket websocket = CreateWebSocket(httpContext.Request);
try
{
websocket.Run();

View File

@ -1,71 +0,0 @@
/*
using System;
using System.Collections.Generic;
using System.Linq;
namespace ln.http.session
{
public class Session : IDisposable
{
public Guid SessionID { get; private set; }
public long SessionAge => DateTimeOffset.Now.ToUnixTimeSeconds() - LastTouch;
public long LastTouch { get; private set; }
public HttpUser CurrentUser { get; set; }
private readonly Dictionary<string, object> elements = new Dictionary<string, object>();
public Session()
{
SessionID = Guid.NewGuid();
CurrentUser = new HttpUser();
}
public object this[string name]
{
get => this.elements[name];
set => this.elements[name] = value;
}
public T Get<T>(string name) where T:class
{
if (elements.ContainsKey(name))
return elements[name] as T;
return null;
}
public String[] ElementNames => this.elements.Keys.ToArray();
public void Touch()
{
LastTouch = DateTimeOffset.Now.ToUnixTimeSeconds();
}
public virtual void Authenticate(HttpRequest httpRequest)
{
}
public void Dispose()
{
foreach (object o in elements.Values)
{
// if (o is IDisposable disposable)
// {
// try
// {
// disposable.Dispose();
// }
//#pragma warning disable RECS0022 // catch-Klausel, die System.Exception abfängt und keinen Text aufweist
// catch (Exception)
//#pragma warning restore RECS0022 // catch-Klausel, die System.Exception abfängt und keinen Text aufweist
// {
// }
//}
}
}
}
}
*/

View File

@ -1,77 +0,0 @@
/*
using System;
using System.Collections.Generic;
namespace ln.http.session
{
public class SessionCache
{
Dictionary<Guid, Session> sessions = new Dictionary<Guid, Session>();
public SessionCache()
{
}
public bool Contains(Guid sessionID)
{
return this.sessions.ContainsKey(sessionID);
}
/*
* Create a new Session instance
*
#1#
public virtual Session CreateSession()
{
return new Session();
}
/*
* Find and return SessionID from given HttpRequest
*
#1#
public virtual Guid FindSessionID(HttpRequest httpRequest)
{
if (httpRequest.ContainsCookie("SID_LN"))
{
return Guid.Parse(httpRequest.GetCookie("SID_LN"));
}
return Guid.Empty;
}
/*
* Apply SessionID of the given Session to the given Response
*
#1#
public virtual void ApplySessionID(HttpResponse httpResponse,Session session)
{
HttpCookie sessionCookie = new HttpCookie("SID_LN",session.SessionID.ToString());
sessionCookie.Path = "/";
httpResponse.AddCookie(sessionCookie);
}
public Session GetSession(HttpRequest httpRequest)
{
Guid sessionID = FindSessionID(httpRequest);
if (!Guid.Empty.Equals(sessionID) && Contains(sessionID))
{
lock (sessions)
{
Session session = this.sessions[sessionID];
session.Touch();
return session;
}
}
else
{
Session session = CreateSession();
lock (this.sessions)
{
this.sessions.Add(session.SessionID, session);
}
return session;
}
}
}
}
*/