From bf254489b8fc0a6d1c3ed0fc94aea7af286cdfcc Mon Sep 17 00:00:00 2001 From: MattMo Date: Sat, 19 Feb 2022 21:46:44 -0800 Subject: [PATCH] Fixed bug where root syntax wouldn't match in the RouteMatcher. Added WithHeader extension. Added preprocess and postprocess route events so we can control routes at a global level easier. --- .../HttpListenerResponseExtensions.cs | 14 +++++++++ Rest.Net/Rest.Net/Rest.Net.csproj | 2 +- Rest.Net/Rest.Net/RouteListener.cs | 30 ++++++++++++++++++- Rest.Net/Rest.Net/RouteMatcher.cs | 5 +++- Rest.Net/Rest.Net/RoutePostprocess.cs | 14 +++++++++ Rest.Net/Rest.Net/RoutePreprocess.cs | 16 ++++++++++ 6 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 Rest.Net/Rest.Net/RoutePostprocess.cs create mode 100644 Rest.Net/Rest.Net/RoutePreprocess.cs diff --git a/Rest.Net/Rest.Net/Extensions/HttpListenerResponseExtensions.cs b/Rest.Net/Rest.Net/Extensions/HttpListenerResponseExtensions.cs index 694ff4b..aa9dcc8 100644 --- a/Rest.Net/Rest.Net/Extensions/HttpListenerResponseExtensions.cs +++ b/Rest.Net/Rest.Net/Extensions/HttpListenerResponseExtensions.cs @@ -173,5 +173,19 @@ namespace MontoyaTech.Rest.Net return response; } + + /// + /// Sets a header for a given response. + /// + /// + /// + /// + /// This response. + public static HttpListenerResponse WithHeader(this HttpListenerResponse response, string name, string value) + { + response.AddHeader(name, value); + + return response; + } } } diff --git a/Rest.Net/Rest.Net/Rest.Net.csproj b/Rest.Net/Rest.Net/Rest.Net.csproj index 4ca6c3d..0377318 100644 --- a/Rest.Net/Rest.Net/Rest.Net.csproj +++ b/Rest.Net/Rest.Net/Rest.Net.csproj @@ -14,7 +14,7 @@ MontoyaTech.Rest.Net MontoyaTech.Rest.Net True - 1.0.3 + 1.0.5 diff --git a/Rest.Net/Rest.Net/RouteListener.cs b/Rest.Net/Rest.Net/RouteListener.cs index 53c9c44..ff022a4 100644 --- a/Rest.Net/Rest.Net/RouteListener.cs +++ b/Rest.Net/Rest.Net/RouteListener.cs @@ -29,6 +29,16 @@ namespace MontoyaTech.Rest.Net /// public ushort Port = 8081; + /// + /// An event to preprocess routes before the route is executed. + /// + public event RoutePreprocess PreprocessEvent; + + /// + /// An event to postprocess routes before the route response is returned. + /// + public event RoutePostprocess PostprocessEvent; + /// /// Creates a new RouteListener with the default port number. /// @@ -111,16 +121,34 @@ namespace MontoyaTech.Rest.Net handled = true; close = this.Routes[i].CloseResponse; + var context = new RouteContext(ctx.Request, ctx.Response); + + //Preprocess the route context, if it returns false, then we have to not invoke the route. + try + { + if (this.PreprocessEvent != null && !this.PreprocessEvent.Invoke(context)) + break; + } + catch { } + //Make sure if the route fails we don't die here, just set the response to internal server error. try { - this.Routes[i].Invoke(new RouteContext(ctx.Request, ctx.Response), arguments); + this.Routes[i].Invoke(context, arguments); } catch { ctx.Response.WithStatus(HttpStatusCode.InternalServerError); } + //Post process the route context. + try + { + if (this.PostprocessEvent != null) + this.PostprocessEvent.Invoke(context); + } + catch { } + break; } } diff --git a/Rest.Net/Rest.Net/RouteMatcher.cs b/Rest.Net/Rest.Net/RouteMatcher.cs index 5e802b9..4f9052f 100644 --- a/Rest.Net/Rest.Net/RouteMatcher.cs +++ b/Rest.Net/Rest.Net/RouteMatcher.cs @@ -41,8 +41,11 @@ namespace MontoyaTech.Rest.Net var urlSegments = url.Split('/').Where(segment => segment.Length > 0).Select(segment => segment.Trim()).ToArray(); var syntaxSegments = syntax.Split('/').Where(segment => segment.Length > 0).Select(segment => segment.Trim()).ToArray(); + //If we have no url segments, and we have no syntax segments, this is a root match which is fine. + if (urlSegments.Length == 0 && syntaxSegments.Length == 0) + return true; //If we have no syntax segments this is not a match. - if (syntaxSegments.Length == 0) + else if (syntaxSegments.Length == 0) return false; //If we have segments and the url does not then this may not be a match. diff --git a/Rest.Net/Rest.Net/RoutePostprocess.cs b/Rest.Net/Rest.Net/RoutePostprocess.cs new file mode 100644 index 0000000..25d7b15 --- /dev/null +++ b/Rest.Net/Rest.Net/RoutePostprocess.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MontoyaTech.Rest.Net +{ + /// + /// A route post process delegate that can be used to process the response from routes. + /// + /// + public delegate void RoutePostprocess(RouteContext context); +} diff --git a/Rest.Net/Rest.Net/RoutePreprocess.cs b/Rest.Net/Rest.Net/RoutePreprocess.cs new file mode 100644 index 0000000..eeb517f --- /dev/null +++ b/Rest.Net/Rest.Net/RoutePreprocess.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MontoyaTech.Rest.Net +{ + /// + /// A route preprocess delegate that can be used to process requests before they reach a route + /// and reject them if needed. + /// + /// + /// + public delegate bool RoutePreprocess(RouteContext context); +}