-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#360 Routing based on values in designated upstream request headers #1684
base: develop
Are you sure you want to change the base?
Changes from all commits
d7207e1
f257989
a70a27a
378ad62
bfbc586
780a7f9
eb00e01
af708f2
4622bb8
fec3b9f
453cc69
1bf0517
5f56f96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using Ocelot.Configuration.File; | ||
|
||
namespace Ocelot.Configuration.Creator; | ||
|
||
public interface IUpstreamHeaderRoutingOptionsCreator | ||
{ | ||
UpstreamHeaderRoutingOptions Create(FileUpstreamHeaderRoutingOptions options); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using Ocelot.Configuration.File; | ||
|
||
namespace Ocelot.Configuration.Creator; | ||
|
||
public class UpstreamHeaderRoutingOptionsCreator : IUpstreamHeaderRoutingOptionsCreator | ||
{ | ||
public UpstreamHeaderRoutingOptions Create(FileUpstreamHeaderRoutingOptions options) | ||
{ | ||
var mode = UpstreamHeaderRoutingTriggerMode.Any; | ||
if (options.TriggerOn.Length > 0) | ||
{ | ||
mode = Enum.Parse<UpstreamHeaderRoutingTriggerMode>(options.TriggerOn, true); | ||
} | ||
|
||
// Keys are converted to uppercase as apparently that is the preferred | ||
// approach according to https://learn.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings | ||
// Values are left untouched but value comparison at runtime is done in | ||
// a case-insensitive manner by using the appropriate StringComparer. | ||
var headers = options.Headers.ToDictionary( | ||
kv => kv.Key.ToUpperInvariant(), | ||
kv => kv.Value); | ||
|
||
return new UpstreamHeaderRoutingOptions(headers, mode); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Ocelot.Configuration.File; | ||
|
||
public class FileUpstreamHeaderRoutingOptions | ||
{ | ||
public IDictionary<string, ICollection<string>> Headers { get; set; } = new Dictionary<string, ICollection<string>>(); | ||
|
||
public string TriggerOn { get; set; } = string.Empty; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace Ocelot.Configuration; | ||
|
||
public class UpstreamHeaderRoutingOptions | ||
{ | ||
public UpstreamHeaderRoutingOptions(IReadOnlyDictionary<string, ICollection<string>> headers, UpstreamHeaderRoutingTriggerMode mode) | ||
{ | ||
Headers = new UpstreamRoutingHeaders(headers); | ||
Mode = mode; | ||
} | ||
|
||
public bool Enabled() => Headers.Any(); | ||
|
||
public UpstreamRoutingHeaders Headers { get; } | ||
|
||
public UpstreamHeaderRoutingTriggerMode Mode { get; } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Ocelot.Configuration; | ||
|
||
public enum UpstreamHeaderRoutingTriggerMode : byte | ||
{ | ||
Any, | ||
All, | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,62 @@ | ||||||||||||||||||||||||||||||||||||||||||
using Microsoft.AspNetCore.Http; | ||||||||||||||||||||||||||||||||||||||||||
using Microsoft.Extensions.Primitives; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
namespace Ocelot.Configuration; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
public class UpstreamRoutingHeaders | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
public IReadOnlyDictionary<string, ICollection<string>> Headers { get; } | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
public UpstreamRoutingHeaders(IReadOnlyDictionary<string, ICollection<string>> headers) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
Headers = headers; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
public bool Any() => Headers.Any(); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
public bool HasAnyOf(IHeaderDictionary requestHeaders) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
IHeaderDictionary normalizedHeaders = NormalizeHeaderNames(requestHeaders); | ||||||||||||||||||||||||||||||||||||||||||
foreach (var h in Headers) | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
if (normalizedHeaders.TryGetValue(h.Key, out var values) && | ||||||||||||||||||||||||||||||||||||||||||
h.Value.Intersect(values, StringComparer.OrdinalIgnoreCase).Any()) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
return true; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+19
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
return false; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
public bool HasAllOf(IHeaderDictionary requestHeaders) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
IHeaderDictionary normalizedHeaders = NormalizeHeaderNames(requestHeaders); | ||||||||||||||||||||||||||||||||||||||||||
foreach (var h in Headers) | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
if (!normalizedHeaders.TryGetValue(h.Key, out var values)) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
return false; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
if (!h.Value.Intersect(values, StringComparer.OrdinalIgnoreCase).Any()) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
return false; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
return true; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
private static IHeaderDictionary NormalizeHeaderNames(IHeaderDictionary headers) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
var upperCaseHeaders = new HeaderDictionary(); | ||||||||||||||||||||||||||||||||||||||||||
foreach (KeyValuePair<string, StringValues> kv in headers) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
var key = kv.Key.ToUpperInvariant(); | ||||||||||||||||||||||||||||||||||||||||||
upperCaseHeaders.Add(key, kv.Value); | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
return upperCaseHeaders; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+51
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be private ?