Skip to content

Commit 8474527

Browse files
authored
Fix Middleware Crash (#111)
* Update version * Add HasEntityBody property to request * Add new content types for form data and moves form handling extensions to Grapeseed * Add check for entity body in form parsing middleware * Fix issue with async event handling Fixes #110
1 parent fdcfcc4 commit 8474527

File tree

12 files changed

+89
-24
lines changed

12 files changed

+89
-24
lines changed

src/Grapeseed/ContentType.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public class ContentType
1414

1515
public static ContentType Css = new ContentType("text/css", false);
1616

17+
public static ContentType FormUrlEncoded = new ContentType("application/x-www-form-urlencoded");
18+
1719
public static ContentType Gif = new ContentType("image/gif");
1820

1921
public static ContentType Html = new ContentType("text/html", false);
@@ -30,6 +32,8 @@ public class ContentType
3032

3133
public static ContentType Mp4 = new ContentType("video/mp4");
3234

35+
public static ContentType MultipartFormData = new ContentType("multipart/form-data");
36+
3337
public static ContentType Pdf = new ContentType("application/pdf");
3438

3539
public static ContentType Png = new ContentType("image/png");

src/Grapeseed/Grapeseed.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
1212
<AssemblyVersion>$(Version)</AssemblyVersion>
1313
<FileVersion>$(Version)</FileVersion>
14-
<Version>5.0.0-rc.9</Version>
14+
<Version>5.0.0-rc.10</Version>
1515
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
1616
<PackageLicenseFile>LICENSE</PackageLicenseFile>
1717
<RepositoryUrl>https://github.com/scottoffen/grapevine</RepositoryUrl>

src/Grapeseed/HandlerList.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
4+
namespace Grapevine
5+
{
6+
public class RequestReceivedEvent : List<RequestReceivedAsyncEventHandler>
7+
{
8+
public async Task<int> Invoke(IHttpContext context, IRestServer server)
9+
{
10+
var counter = 0;
11+
foreach(var handler in this)
12+
{
13+
await handler(context, server);
14+
counter++;
15+
if (context.WasRespondedTo) break;
16+
}
17+
return counter;
18+
}
19+
20+
public static RequestReceivedEvent operator + (RequestReceivedEvent source, RequestReceivedAsyncEventHandler obj)
21+
{
22+
source.Add(obj);
23+
return source;
24+
}
25+
26+
public static RequestReceivedEvent operator - (RequestReceivedEvent source, RequestReceivedAsyncEventHandler obj)
27+
{
28+
source.Remove(obj);
29+
return source;
30+
}
31+
}
32+
33+
public class RequestRoutingEvent : List<RoutingAsyncEventHandler>
34+
{
35+
public async Task<int> Invoke(IHttpContext context)
36+
{
37+
var counter = 0;
38+
foreach(var handler in this)
39+
{
40+
await handler(context);
41+
counter++;
42+
if (context.WasRespondedTo) break;
43+
}
44+
return counter;
45+
}
46+
47+
public static RequestRoutingEvent operator + (RequestRoutingEvent source, RoutingAsyncEventHandler obj)
48+
{
49+
source.Add(obj);
50+
return source;
51+
}
52+
53+
public static RequestRoutingEvent operator - (RequestRoutingEvent source, RoutingAsyncEventHandler obj)
54+
{
55+
source.Remove(obj);
56+
return source;
57+
}
58+
}
59+
}

src/Grapevine/HttpRequestExtensions.cs renamed to src/Grapeseed/HttpRequestExtensions.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ namespace Grapevine
77
{
88
public static class HttpRequestExtensions
99
{
10-
private static readonly string _multipartContentType = "multipart/form-data; boundary=";
11-
private static readonly int _startIndex = _multipartContentType.Length;
10+
private static readonly int _startIndex = ContentType.MultipartFormData.ToString().Length;
1211

13-
internal static string GetMultipartBoundary(this IHttpRequest request)
12+
public static string GetMultipartBoundary(this IHttpRequest request)
1413
{
15-
return (string.IsNullOrWhiteSpace(request.ContentType) || !request.ContentType.StartsWith(_multipartContentType))
14+
return (string.IsNullOrWhiteSpace(request.ContentType) || !request.ContentType.StartsWith(ContentType.MultipartFormData))
1615
? string.Empty
1716
: request.ContentType.Substring(_startIndex);
1817
}

src/Grapeseed/IHttpRequest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ public interface IHttpRequest
3434
/// </summary>
3535
CookieCollection Cookies { get; }
3636

37+
/// <summary>
38+
/// Gets a boolean value that indicates whether the request has associated body data.
39+
/// </summary>
40+
bool HasEntityBody { get; }
41+
3742
/// <summary>
3843
/// Gets the collection of header name/value pairs sent in the request
3944
/// </summary>

src/Grapeseed/IRestServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public interface IRestServer : IDisposable
9696
/// <summary>
9797
/// Raised after an incoming request is received, but before routing the request.
9898
/// </summary>
99-
event RequestReceivedAsyncEventHandler OnRequestAsync;
99+
RequestReceivedEvent OnRequestAsync { get; set; }
100100

101101
/// <summary>
102102
/// Starts the server, raising BeforeStart and AfterStart events appropriately.

src/Grapeseed/IRouter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ public interface IRouter
4848
/// <summary>
4949
/// Raised after a request has completed invoking matching routes
5050
/// </summary>
51-
event RoutingAsyncEventHandler AfterRoutingAsync;
51+
RequestRoutingEvent AfterRoutingAsync { get; set; }
5252

5353
/// <summary>
5454
/// Raised prior to sending any request though matching routes
5555
/// </summary>
56-
event RoutingAsyncEventHandler BeforeRoutingAsync;
56+
RequestRoutingEvent BeforeRoutingAsync { get; set; }
5757

5858
/// <summary>
5959
/// Adds the route to the routing table
@@ -63,7 +63,7 @@ public interface IRouter
6363
IRouter Register(IRoute route);
6464

6565
/// <summary>
66-
/// Routes the IHttpContext through all enabled registered routes that match the (IHttpConext)state provided
66+
/// Routes the IHttpContext through all enabled registered routes that match the (IHttpContext)state provided
6767
/// </summary>
6868
/// <param name="state"></param>
6969
void RouteAsync(object state);

src/Grapeseed/Router.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ public abstract class RouterBase : IRouter
6969

7070
public IServiceProvider ServiceProvider { get; set; }
7171

72-
public abstract event RoutingAsyncEventHandler AfterRoutingAsync;
73-
public abstract event RoutingAsyncEventHandler BeforeRoutingAsync;
72+
public virtual RequestRoutingEvent AfterRoutingAsync { get; set; } = new RequestRoutingEvent();
73+
public virtual RequestRoutingEvent BeforeRoutingAsync { get; set; } = new RequestRoutingEvent();
7474

7575
public abstract IRouter Register(IRoute route);
7676

@@ -123,9 +123,6 @@ public class Router : RouterBase
123123

124124
public override IList<IRoute> RoutingTable => RegisteredRoutes.ToList().AsReadOnly();
125125

126-
public override event RoutingAsyncEventHandler AfterRoutingAsync;
127-
public override event RoutingAsyncEventHandler BeforeRoutingAsync;
128-
129126
public Router(ILogger<IRouter> logger)
130127
{
131128
Logger = logger ?? DefaultLogger.GetInstance<IRouter>();
@@ -182,8 +179,8 @@ public virtual async Task<int> RouteAsync(IHttpContext context)
182179
if (!context.CancellationToken.IsCancellationRequested)
183180
{
184181
Logger.LogTrace($"{context.Id} : Invoking before routing handlers for {context.Request.Name}");
185-
if (BeforeRoutingAsync != null) await BeforeRoutingAsync.Invoke(context);
186-
Logger.LogTrace($"{context.Id} : Before routing handlers invoked for {context.Request.Name}");
182+
var beforeCount = (BeforeRoutingAsync != null) ? await BeforeRoutingAsync.Invoke(context) : 0;
183+
Logger.LogTrace($"{context.Id} : {beforeCount} Before routing handlers invoked for {context.Request.Name}");
187184
}
188185

189186
// 3. Iterate over the routes until a response is sent
@@ -203,8 +200,8 @@ public virtual async Task<int> RouteAsync(IHttpContext context)
203200
if (!context.CancellationToken.IsCancellationRequested)
204201
{
205202
Logger.LogTrace($"{context.Id} : Invoking after routing handlers for {context.Request.Name}");
206-
if (AfterRoutingAsync != null) await AfterRoutingAsync.Invoke(context);
207-
Logger.LogTrace($"{context.Id} : After routing handlers invoked for {context.Request.Name}");
203+
var afterCount = (AfterRoutingAsync != null) ? await AfterRoutingAsync.Invoke(context) : 0;
204+
Logger.LogTrace($"{context.Id} : {afterCount} After routing handlers invoked for {context.Request.Name}");
208205
}
209206

210207
return count;

src/Grapevine/Grapevine.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<PackageTags>rest http api web router client server express json xml embedded</PackageTags>
1313
<AssemblyVersion>$(Version)</AssemblyVersion>
1414
<FileVersion>$(Version)</FileVersion>
15-
<Version>5.0.0-rc.9</Version>
15+
<Version>5.0.0-rc.10</Version>
1616
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
1717
<PackageLicenseFile>LICENSE</PackageLicenseFile>
1818
<RepositoryUrl>https://github.com/scottoffen/grapevine</RepositoryUrl>

src/Grapevine/HttpRequest.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public class HttpRequest : IHttpRequest
2121

2222
public CookieCollection Cookies => Advanced.Cookies;
2323

24+
public bool HasEntityBody => Advanced.HasEntityBody;
25+
2426
public NameValueCollection Headers => Advanced.Headers;
2527

2628
public string HostPrefix { get; }

src/Grapevine/Middleware/FormUrlEncodedData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public static class FormUrlEncodedData
66
{
77
public async static Task Parse(IHttpContext context, IRestServer server)
88
{
9-
if (context.Request.ContentType != "application/x-www-form-urlencoded") return;
9+
if ((context.Request.ContentType != ContentType.FormUrlEncoded) || (!context.Request.HasEntityBody)) return;
1010
context.Locals.TryAdd("FormData", await context.Request.ParseFormUrlEncodedData());
1111
}
1212
}

src/Grapevine/RestServer.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public abstract class RestServerBase : IRestServer
3939
public abstract event ServerEventHandler AfterStopping;
4040
public abstract event ServerEventHandler BeforeStarting;
4141
public abstract event ServerEventHandler BeforeStopping;
42-
public abstract event RequestReceivedAsyncEventHandler OnRequestAsync;
42+
public virtual RequestReceivedEvent OnRequestAsync { get; set; } = new RequestReceivedEvent();
4343

4444
public abstract void Dispose();
4545

@@ -87,7 +87,6 @@ public class RestServer : RestServerBase
8787
public override event ServerEventHandler AfterStopping;
8888
public override event ServerEventHandler BeforeStarting;
8989
public override event ServerEventHandler BeforeStopping;
90-
public override event RequestReceivedAsyncEventHandler OnRequestAsync;
9190

9291
public RestServer(IRouter router, IRouteScanner scanner, ILogger<IRestServer> logger)
9392
{
@@ -267,8 +266,8 @@ protected async void RequestHandlerAsync(object state)
267266
try
268267
{
269268
Logger.LogTrace($"{context.Id} : Invoking OnRequest Handlers for {context.Request.Name}");
270-
if (OnRequestAsync != null) await OnRequestAsync.Invoke(context, this);
271-
Logger.LogTrace($"{context.Id} : OnRequest Handlers Invoked for {context.Request.Name}");
269+
var count = (OnRequestAsync != null) ? await OnRequestAsync.Invoke(context, this) : 0;
270+
Logger.LogTrace($"{context.Id} : {count} OnRequest Handlers Invoked for {context.Request.Name}");
272271
}
273272
catch (System.Net.HttpListenerException hl) when (hl.ErrorCode == 1229)
274273
{

0 commit comments

Comments
 (0)