master
Harald Wolff 2020-03-03 17:13:31 +01:00
parent 3601ea1520
commit 15b822d3c3
14 changed files with 2409 additions and 36 deletions

View File

@ -147,7 +147,7 @@ namespace ln.http
HttpResponse response; HttpResponse response;
try try
{ {
response = Router.Route(httpRequest.URI.AbsolutePath,httpRequest); response = Router.Route(new HttpRoutingContext(httpRequest),httpRequest);
} }
catch (HttpException httpExc) catch (HttpException httpExc)
{ {
@ -234,7 +234,7 @@ namespace ln.http
} }
if (argumentContainer['c'].IsSet) if (argumentContainer['c'].IsSet)
router.AddSimpleRoute("/*", new RouterTarget((request) => router.Route(argumentContainer['c'].Value,request)),0); router.AddSimpleRoute("/*", new RouterTarget((request) => router.Route(new HttpRoutingContext(request, argumentContainer['c'].Value), request)), 0);
HTTPServer server = new HTTPServer(new Endpoint(IPv6.Parse(argumentContainer['l'].Value),argumentContainer['p'].IntegerValue), HTTPServer server = new HTTPServer(new Endpoint(IPv6.Parse(argumentContainer['l'].Value),argumentContainer['p'].IntegerValue),
new LoggingRouter(router)); new LoggingRouter(router));

View File

@ -232,6 +232,7 @@ namespace ln.http
return requestCookies[name]; return requestCookies[name];
} }
public bool ContainsParameter(string parameterName) => requestParameters.ContainsKey(parameterName);
public String GetParameter(String parameterName) => GetParameter(parameterName, null); public String GetParameter(String parameterName) => GetParameter(parameterName, null);
public String GetParameter(String parameterName,String defaultValue) public String GetParameter(String parameterName,String defaultValue)
{ {
@ -249,15 +250,16 @@ namespace ln.http
} }
public HttpResponse Redirect(string location, params object[] p) => Redirect(303, location, p);
public HttpResponse Redirect(string location,int status = 307) public HttpResponse Redirect(int status, string location, params object[] p)
{ {
HttpResponse httpResponse = new HttpResponse(this); location = string.Format(location, p);
httpResponse.AddHeader("location", location);
httpResponse.StatusCode = status; HttpResponse response = new HttpResponse(this);
httpResponse.AddHeader("content-type", "text/plain"); response.StatusCode = status;
httpResponse.ContentWriter.WriteLine("Redirect: {0}", location); response.SetHeader("location", location);
return httpResponse; return response;
} }
public void Dispose() public void Dispose()

View File

@ -1,5 +1,6 @@
using System; using System;
using ln.logging; using ln.logging;
using ln.http.router;
namespace ln.http namespace ln.http
{ {
public abstract class HttpRouter : IHttpRouter public abstract class HttpRouter : IHttpRouter
@ -10,7 +11,7 @@ namespace ln.http
public abstract IHTTPResource FindResource(HttpRequest httpRequest); public abstract IHTTPResource FindResource(HttpRequest httpRequest);
public virtual HttpResponse Route(string path,HttpRequest httpRequest) public virtual HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
{ {
try try
{ {

View File

@ -1,8 +1,9 @@
using System; using System;
using ln.http.router;
namespace ln.http namespace ln.http
{ {
public interface IHttpRouter public interface IHttpRouter
{ {
HttpResponse Route(string path, HttpRequest httpRequest); HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest);
} }
} }

View File

@ -0,0 +1,20 @@
// /**
// * File: UnsupportedMediaTypeException.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;
namespace ln.http.exceptions
{
public class UnsupportedMediaTypeException : HttpException
{
public UnsupportedMediaTypeException()
: base(415, "Unsupported Media Type")
{
}
}
}

View File

@ -85,6 +85,8 @@
<Compile Include="message\parser\MIME.cs" /> <Compile Include="message\parser\MIME.cs" />
<Compile Include="message\parser\HTTP.cs" /> <Compile Include="message\parser\HTTP.cs" />
<Compile Include="exceptions\BadRequestException.cs" /> <Compile Include="exceptions\BadRequestException.cs" />
<Compile Include="exceptions\UnsupportedMediaTypeException.cs" />
<Compile Include="router\HttpRoutingContext.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="exceptions\" /> <Folder Include="exceptions\" />

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@ namespace ln.http.router
FileName = filename; FileName = filename;
} }
public HttpResponse Route(string path, HttpRequest httpRequest) public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
{ {
HttpResponse httpResponse = new HttpResponse(httpRequest, new FileStream(FileName, FileMode.Open)); HttpResponse httpResponse = new HttpResponse(httpRequest, new FileStream(FileName, FileMode.Open));
httpResponse.SetHeader("content-type", MimeTypeMap.GetMimeType(Path.GetExtension(FileName))); httpResponse.SetHeader("content-type", MimeTypeMap.GetMimeType(Path.GetExtension(FileName)));

View File

@ -0,0 +1,31 @@
using System;
namespace ln.http.router
{
public class HttpRoutingContext
{
public HttpRequest HttpRequest { get; }
public string Path { get; set; }
public string RoutedPath { get; set; }
public HttpRoutingContext(HttpRequest httpRequest) : this(httpRequest, httpRequest.URI.AbsolutePath) { }
public HttpRoutingContext(HttpRequest httpRequest, string path)
{
HttpRequest = httpRequest;
Path = path;
RoutedPath = "";
}
HttpRoutingContext(HttpRequest httpRequest,string path,string routedPath)
{
HttpRequest = httpRequest;
Path = path;
RoutedPath = routedPath;
}
public HttpRoutingContext Routed(string residual)
{
return new HttpRoutingContext(HttpRequest, residual, RoutedPath + Path.Substring(0,Path.Length - residual.Length));
}
}
}

View File

@ -26,15 +26,20 @@ namespace ln.http.router
Logger = logger; Logger = logger;
} }
public HttpResponse Route(string path, HttpRequest httpRequest) public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
{ {
DateTime start = DateTime.Now; DateTime start = DateTime.Now;
HttpResponse response = null; HttpResponse response = null;
try try
{ {
response = Next.Route(path, httpRequest); response = Next.Route(routingContext, httpRequest);
} finally }
catch (Exception e)
{
throw;
}
finally
{ {
DateTime end = DateTime.Now; DateTime end = DateTime.Now;
TimeSpan duration = end - start; TimeSpan duration = end - start;

View File

@ -4,15 +4,19 @@ namespace ln.http.router
{ {
public class RouterTarget :IHttpRouter public class RouterTarget :IHttpRouter
{ {
public Func<string,HttpRequest, HttpResponse> Target { get; } public Func<HttpRoutingContext,HttpRequest, HttpResponse> Target { get; }
public RouterTarget(Func<string, HttpRequest, HttpResponse> target) public RouterTarget(Func<string, HttpRequest, HttpResponse> target)
{
Target = (HttpRoutingContext routingContext, HttpRequest httpRequest) => target(routingContext.Path, httpRequest);
}
public RouterTarget(Func<HttpRoutingContext, HttpRequest, HttpResponse> target)
{ {
Target = target; Target = target;
} }
public RouterTarget(Func<HttpRequest, HttpResponse> target) public RouterTarget(Func<HttpRequest, HttpResponse> target)
{ {
Target = (path,request) => target(request); Target = (context,request) => target(request);
} }
protected RouterTarget() protected RouterTarget()
{ {
@ -40,9 +44,9 @@ namespace ln.http.router
} }
} }
public HttpResponse Route(string path, HttpRequest httpRequest) public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
{ {
return Target(path, httpRequest); return Target(routingContext, httpRequest);
} }
public virtual HttpResponse HEAD(HttpRequest request) => throw new MethodNotAllowedException(); public virtual HttpResponse HEAD(HttpRequest request) => throw new MethodNotAllowedException();

View File

@ -2,6 +2,7 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Linq;
namespace ln.http.router namespace ln.http.router
{ {
public class SimpleRouter : IHttpRouter public class SimpleRouter : IHttpRouter
@ -13,23 +14,29 @@ namespace ln.http.router
{ {
} }
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) => AddSimpleRoute(simpleRoute, target, simpleRoute.Split('/').Length);
public void AddSimpleRoute(string simpleRoute, IHttpRouter target, int priority) public void AddSimpleRoute(string simpleRoute, IHttpRouter target, int priority)
{ {
string[] parts = simpleRoute.Split(new char[] { '/' },StringSplitOptions.RemoveEmptyEntries); string[] parts = simpleRoute.Split(new char[] { '/' });
StringBuilder stringBuilder = new StringBuilder("^"); string[] reparts = parts.Select((part) =>
foreach (string part in parts)
{ {
if (part.StartsWith(":", StringComparison.InvariantCulture)) if (part.StartsWith(":", StringComparison.InvariantCulture))
stringBuilder.AppendFormat("/(?<{0}>[^/]+)", part.Substring(1)); 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("*")) else if (part.Equals("*"))
stringBuilder.AppendFormat("/(?<_>.*)"); return string.Format("(?<_>.*)");
else else
stringBuilder.AppendFormat("/{0}", part); return string.Format("{0}", part);
} }).ToArray();
stringBuilder.Append("/?$");
AddRoute(stringBuilder.ToString(), target, priority); string reroute = 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) => AddRoute(route, target, 0);
@ -43,11 +50,11 @@ namespace ln.http.router
} }
public void Remove(SimpleRoute simpleRoute) => routes.Remove(simpleRoute); public void Remove(SimpleRoute simpleRoute) => routes.Remove(simpleRoute);
public HttpResponse Route(string path, HttpRequest httpRequest) public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
{ {
foreach (SimpleRoute simpleRoute in routes.ToArray()) foreach (SimpleRoute simpleRoute in routes.ToArray())
{ {
Match match = simpleRoute.Route.Match(path); Match match = simpleRoute.Route.Match(routingContext.Path);
if (match.Success) if (match.Success)
{ {
string residual = ""; string residual = "";
@ -56,9 +63,13 @@ namespace ln.http.router
{ {
httpRequest?.SetParameter(group.Name, group.Value); httpRequest?.SetParameter(group.Name, group.Value);
if (group.Name.Equals("_")) if (group.Name.Equals("_"))
residual = "/" + group.Value; if (group.Value.StartsWith("/", StringComparison.InvariantCulture))
residual = group.Value;
else
residual = "/" + group.Value;
} }
HttpResponse response = simpleRoute.Target.Route(residual, httpRequest);
HttpResponse response = simpleRoute.Target.Route(routingContext.Routed(residual), httpRequest);
if (response != null) if (response != null)
return response; return response;
} }

View File

@ -34,9 +34,9 @@ namespace ln.http.router
public void AddIndex(string indexName) => indexNames.Add(indexName); public void AddIndex(string indexName) => indexNames.Add(indexName);
public void RemoveIndex(string indexName) => indexNames.Remove(indexName); public void RemoveIndex(string indexName) => indexNames.Remove(indexName);
public HttpResponse Route(string path, HttpRequest httpRequest) public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
{ {
string finalPath = Path.Combine(RootPath, path.Substring(1)); string finalPath = Path.Combine(RootPath, routingContext.Path.Substring(1));
if (Directory.Exists(finalPath)) if (Directory.Exists(finalPath))
{ {

View File

@ -15,7 +15,7 @@ namespace ln.http.router
public WebSocket CreateWebSocket(HttpRequest request) => createWebsocket(request); public WebSocket CreateWebSocket(HttpRequest request) => createWebsocket(request);
public HttpResponse Route(string path, HttpRequest httpRequest) public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
{ {
WebSocket websocket = CreateWebSocket(httpRequest); WebSocket websocket = CreateWebSocket(httpRequest);
try try