Skip to content

Commit ba5186b

Browse files
committed
PR feedback and benchmark
1 parent 05c3bb5 commit ba5186b

File tree

4 files changed

+150
-88
lines changed

4 files changed

+150
-88
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using BenchmarkDotNet.Attributes;
6+
using Microsoft.AspNetCore.Http;
7+
8+
namespace Microsoft.AspNetCore.Routing.Matching
9+
{
10+
public class HttpMethodPolicyJumpTableBenchmark
11+
{
12+
private PolicyJumpTable _dictionaryJumptable;
13+
private PolicyJumpTable _singleEntryJumptable;
14+
private DefaultHttpContext _httpContext;
15+
16+
[GlobalSetup]
17+
public void Setup()
18+
{
19+
_dictionaryJumptable = new HttpMethodDictionaryPolicyJumpTable(
20+
0,
21+
new Dictionary<string, int>
22+
{
23+
[HttpMethods.Get] = 1
24+
},
25+
-1,
26+
new Dictionary<string, int>
27+
{
28+
[HttpMethods.Get] = 2
29+
});
30+
_singleEntryJumptable = new HttpMethodSingleEntryPolicyJumpTable(
31+
0,
32+
HttpMethods.Get,
33+
-1,
34+
supportsCorsPreflight: true,
35+
-1,
36+
2);
37+
38+
_httpContext = new DefaultHttpContext();
39+
_httpContext.Request.Method = HttpMethods.Get;
40+
}
41+
42+
[Benchmark]
43+
public int DictionaryPolicyJumpTable()
44+
{
45+
return _dictionaryJumptable.GetDestination(_httpContext);
46+
}
47+
48+
[Benchmark]
49+
public int SingleEntryPolicyJumpTable()
50+
{
51+
return _singleEntryJumptable.GetDestination(_httpContext);
52+
}
53+
}
54+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using Microsoft.AspNetCore.Http;
6+
7+
namespace Microsoft.AspNetCore.Routing.Matching
8+
{
9+
internal sealed class HttpMethodDictionaryPolicyJumpTable : PolicyJumpTable
10+
{
11+
private readonly int _exitDestination;
12+
private readonly Dictionary<string, int>? _destinations;
13+
private readonly int _corsPreflightExitDestination;
14+
private readonly Dictionary<string, int>? _corsPreflightDestinations;
15+
16+
private readonly bool _supportsCorsPreflight;
17+
18+
public HttpMethodDictionaryPolicyJumpTable(
19+
int exitDestination,
20+
Dictionary<string, int>? destinations,
21+
int corsPreflightExitDestination,
22+
Dictionary<string, int>? corsPreflightDestinations)
23+
{
24+
_exitDestination = exitDestination;
25+
_destinations = destinations;
26+
_corsPreflightExitDestination = corsPreflightExitDestination;
27+
_corsPreflightDestinations = corsPreflightDestinations;
28+
29+
_supportsCorsPreflight = _corsPreflightDestinations != null && _corsPreflightDestinations.Count > 0;
30+
}
31+
32+
public override int GetDestination(HttpContext httpContext)
33+
{
34+
int destination;
35+
36+
var httpMethod = httpContext.Request.Method;
37+
if (_supportsCorsPreflight && HttpMethodMatcherPolicy.IsCorsPreflightRequest(httpContext, httpMethod, out var accessControlRequestMethod))
38+
{
39+
return _corsPreflightDestinations!.TryGetValue(accessControlRequestMethod, out destination)
40+
? destination
41+
: _corsPreflightExitDestination;
42+
}
43+
44+
return _destinations != null &&
45+
_destinations.TryGetValue(httpMethod, out destination) ? destination : _exitDestination;
46+
}
47+
}
48+
}

src/Http/Routing/src/Matching/HttpMethodMatcherPolicy.cs

Lines changed: 3 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ public PolicyJumpTable BuildJumpTable(int exitDestination, IReadOnlyList<PolicyJ
386386
corsPreflightDestination = corsPreflightDestinations.Single().Value;
387387
}
388388

389-
return new SingleEntryHttpMethodPolicyJumpTable(
389+
return new HttpMethodSingleEntryPolicyJumpTable(
390390
exitDestination,
391391
method,
392392
destination,
@@ -396,7 +396,7 @@ public PolicyJumpTable BuildJumpTable(int exitDestination, IReadOnlyList<PolicyJ
396396
}
397397
else
398398
{
399-
return new DictionaryHttpMethodPolicyJumpTable(
399+
return new HttpMethodDictionaryPolicyJumpTable(
400400
exitDestination,
401401
destinations,
402402
corsPreflightExitDestination,
@@ -445,7 +445,7 @@ private static bool ContainsHttpMethod(List<string> httpMethods, string httpMeth
445445
return false;
446446
}
447447

448-
private static bool IsCorsPreflightRequest(HttpContext httpContext, string httpMethod, out StringValues accessControlRequestMethod)
448+
public static bool IsCorsPreflightRequest(HttpContext httpContext, string httpMethod, out StringValues accessControlRequestMethod)
449449
{
450450
accessControlRequestMethod = default;
451451
var headers = httpContext.Request.Headers;
@@ -456,91 +456,6 @@ private static bool IsCorsPreflightRequest(HttpContext httpContext, string httpM
456456
!StringValues.IsNullOrEmpty(accessControlRequestMethod);
457457
}
458458

459-
private sealed class SingleEntryHttpMethodPolicyJumpTable : PolicyJumpTable
460-
{
461-
private readonly int _exitDestination;
462-
private readonly string _method;
463-
private readonly int _destination;
464-
private readonly int _corsPreflightExitDestination;
465-
private readonly int _corsPreflightDestination;
466-
467-
private readonly bool _supportsCorsPreflight;
468-
469-
public SingleEntryHttpMethodPolicyJumpTable(
470-
int exitDestination,
471-
string method,
472-
int destination,
473-
bool supportsCorsPreflight,
474-
int corsPreflightExitDestination,
475-
int corsPreflightDestination)
476-
{
477-
_exitDestination = exitDestination;
478-
_method = method;
479-
_destination = destination;
480-
_supportsCorsPreflight = supportsCorsPreflight;
481-
_corsPreflightExitDestination = corsPreflightExitDestination;
482-
_corsPreflightDestination = corsPreflightDestination;
483-
}
484-
485-
public override int GetDestination(HttpContext httpContext)
486-
{
487-
var httpMethod = httpContext.Request.Method;
488-
if (_supportsCorsPreflight && IsCorsPreflightRequest(httpContext, httpMethod, out var accessControlRequestMethod))
489-
{
490-
return CompareMethod(accessControlRequestMethod, _method) ? _corsPreflightDestination : _corsPreflightExitDestination;
491-
}
492-
493-
return CompareMethod(httpMethod, _method) ? _destination : _exitDestination;
494-
495-
static bool CompareMethod(string requestMethod, string endpointMethod)
496-
{
497-
// Known methods (GET, POST, PUT, etc) will match by reference.
498-
// Custom methods fallback to ignore case compare.
499-
return ReferenceEquals(requestMethod, endpointMethod) || StringComparer.OrdinalIgnoreCase.Equals(requestMethod, endpointMethod);
500-
}
501-
}
502-
}
503-
504-
private sealed class DictionaryHttpMethodPolicyJumpTable : PolicyJumpTable
505-
{
506-
private readonly int _exitDestination;
507-
private readonly Dictionary<string, int>? _destinations;
508-
private readonly int _corsPreflightExitDestination;
509-
private readonly Dictionary<string, int>? _corsPreflightDestinations;
510-
511-
private readonly bool _supportsCorsPreflight;
512-
513-
public DictionaryHttpMethodPolicyJumpTable(
514-
int exitDestination,
515-
Dictionary<string, int>? destinations,
516-
int corsPreflightExitDestination,
517-
Dictionary<string, int>? corsPreflightDestinations)
518-
{
519-
_exitDestination = exitDestination;
520-
_destinations = destinations;
521-
_corsPreflightExitDestination = corsPreflightExitDestination;
522-
_corsPreflightDestinations = corsPreflightDestinations;
523-
524-
_supportsCorsPreflight = _corsPreflightDestinations != null && _corsPreflightDestinations.Count > 0;
525-
}
526-
527-
public override int GetDestination(HttpContext httpContext)
528-
{
529-
int destination;
530-
531-
var httpMethod = httpContext.Request.Method;
532-
if (_supportsCorsPreflight && IsCorsPreflightRequest(httpContext, httpMethod, out var accessControlRequestMethod))
533-
{
534-
return _corsPreflightDestinations!.TryGetValue(accessControlRequestMethod, out destination)
535-
? destination
536-
: _corsPreflightExitDestination;
537-
}
538-
539-
return _destinations != null &&
540-
_destinations.TryGetValue(httpMethod, out destination) ? destination : _exitDestination;
541-
}
542-
}
543-
544459
private class HttpMethodMetadataEndpointComparer : EndpointMetadataComparer<IHttpMethodMetadata>
545460
{
546461
protected override int CompareMetadata(IHttpMethodMetadata? x, IHttpMethodMetadata? y)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNetCore.Http;
5+
6+
namespace Microsoft.AspNetCore.Routing.Matching
7+
{
8+
internal sealed class HttpMethodSingleEntryPolicyJumpTable : PolicyJumpTable
9+
{
10+
private readonly int _exitDestination;
11+
private readonly string _method;
12+
private readonly int _destination;
13+
private readonly int _corsPreflightExitDestination;
14+
private readonly int _corsPreflightDestination;
15+
16+
private readonly bool _supportsCorsPreflight;
17+
18+
public HttpMethodSingleEntryPolicyJumpTable(
19+
int exitDestination,
20+
string method,
21+
int destination,
22+
bool supportsCorsPreflight,
23+
int corsPreflightExitDestination,
24+
int corsPreflightDestination)
25+
{
26+
_exitDestination = exitDestination;
27+
_method = method;
28+
_destination = destination;
29+
_supportsCorsPreflight = supportsCorsPreflight;
30+
_corsPreflightExitDestination = corsPreflightExitDestination;
31+
_corsPreflightDestination = corsPreflightDestination;
32+
}
33+
34+
public override int GetDestination(HttpContext httpContext)
35+
{
36+
var httpMethod = httpContext.Request.Method;
37+
if (_supportsCorsPreflight && HttpMethodMatcherPolicy.IsCorsPreflightRequest(httpContext, httpMethod, out var accessControlRequestMethod))
38+
{
39+
return HttpMethods.Equals(accessControlRequestMethod, _method) ? _corsPreflightDestination : _corsPreflightExitDestination;
40+
}
41+
42+
return HttpMethods.Equals(httpMethod, _method) ? _destination : _exitDestination;
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)