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;
try
{
response = Router.Route(httpRequest.URI.AbsolutePath,httpRequest);
response = Router.Route(new HttpRoutingContext(httpRequest),httpRequest);
}
catch (HttpException httpExc)
{
@ -234,7 +234,7 @@ namespace ln.http
}
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),
new LoggingRouter(router));

View File

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

View File

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

View File

@ -1,8 +1,9 @@
using System;
using ln.http.router;
namespace ln.http
{
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\HTTP.cs" />
<Compile Include="exceptions\BadRequestException.cs" />
<Compile Include="exceptions\UnsupportedMediaTypeException.cs" />
<Compile Include="router\HttpRoutingContext.cs" />
</ItemGroup>
<ItemGroup>
<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;
}
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.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;
}
public HttpResponse Route(string path, HttpRequest httpRequest)
public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest)
{
DateTime start = DateTime.Now;
HttpResponse response = null;
try
{
response = Next.Route(path, httpRequest);
} finally
response = Next.Route(routingContext, httpRequest);
}
catch (Exception e)
{
throw;
}
finally
{
DateTime end = DateTime.Now;
TimeSpan duration = end - start;

View File

@ -4,15 +4,19 @@ namespace ln.http.router
{
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)
{
Target = (HttpRoutingContext routingContext, HttpRequest httpRequest) => target(routingContext.Path, httpRequest);
}
public RouterTarget(Func<HttpRoutingContext, HttpRequest, HttpResponse> target)
{
Target = target;
}
public RouterTarget(Func<HttpRequest, HttpResponse> target)
{
Target = (path,request) => target(request);
Target = (context,request) => target(request);
}
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();

View File

@ -2,6 +2,7 @@
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace ln.http.router
{
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, int priority)
{
string[] parts = simpleRoute.Split(new char[] { '/' },StringSplitOptions.RemoveEmptyEntries);
StringBuilder stringBuilder = new StringBuilder("^");
foreach (string part in parts)
string[] parts = simpleRoute.Split(new char[] { '/' });
string[] reparts = parts.Select((part) =>
{
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("*"))
stringBuilder.AppendFormat("/(?<_>.*)");
return string.Format("(?<_>.*)");
else
stringBuilder.AppendFormat("/{0}", part);
}
stringBuilder.Append("/?$");
return string.Format("{0}", part);
}).ToArray();
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);
@ -43,11 +50,11 @@ namespace ln.http.router
}
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())
{
Match match = simpleRoute.Route.Match(path);
Match match = simpleRoute.Route.Match(routingContext.Path);
if (match.Success)
{
string residual = "";
@ -56,9 +63,13 @@ namespace ln.http.router
{
httpRequest?.SetParameter(group.Name, group.Value);
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)
return response;
}

View File

@ -34,9 +34,9 @@ namespace ln.http.router
public void AddIndex(string indexName) => indexNames.Add(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))
{

View File

@ -15,7 +15,7 @@ namespace ln.http.router
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);
try