V0.5.0
parent
8012f01dde
commit
fda7d695d1
|
@ -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>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
|
@ -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>
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
0123456789
|
||||
ÄÖÜ
|
|
@ -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();
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,7 +29,6 @@ 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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using ln.http.router;
|
||||
|
||||
namespace ln.http
|
||||
{
|
||||
public class HttpRolePermission
|
||||
{
|
||||
public string RoleName { get; set; }
|
||||
public HttpAccessRights AccessRights { get; set; }
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
|
@ -2,8 +2,5 @@
|
|||
using ln.http.router;
|
||||
namespace ln.http
|
||||
{
|
||||
public interface IHttpRouter
|
||||
{
|
||||
HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,8 +32,18 @@ namespace ln.http.listener
|
|||
public virtual void AcceptMany(Action<Connection> handler)
|
||||
{
|
||||
while (IsOpen)
|
||||
{
|
||||
try
|
||||
{
|
||||
handler(Accept());
|
||||
}
|
||||
catch (SocketException soe)
|
||||
{
|
||||
if (IsOpen)
|
||||
Logging.Log(soe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void Open();
|
||||
public abstract void Close();
|
||||
|
|
|
@ -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-*" />
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|||
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
|
@ -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
|
||||
// {
|
||||
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
Loading…
Reference in New Issue