Skip to content
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

#1658 Adds global header transforms #1659

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
72 changes: 40 additions & 32 deletions src/Ocelot/Configuration/Creator/HeaderFindAndReplaceCreator.cs
Original file line number Diff line number Diff line change
@@ -1,75 +1,70 @@
using Microsoft.Extensions.Options;
using Ocelot.Configuration.File;
using Ocelot.Infrastructure;
using Ocelot.Logging;
using Ocelot.Responses;
using Header = System.Collections.Generic.KeyValuePair<string, string>;

namespace Ocelot.Configuration.Creator
{
public class HeaderFindAndReplaceCreator : IHeaderFindAndReplaceCreator
{
private readonly FileGlobalConfiguration _fileGlobalConfiguration;
private readonly IPlaceholders _placeholders;
private readonly IOcelotLogger _logger;

public HeaderFindAndReplaceCreator(IPlaceholders placeholders, IOcelotLoggerFactory factory)
public HeaderFindAndReplaceCreator(IOptions<FileConfiguration> fileConfiguration, IPlaceholders placeholders, IOcelotLoggerFactory factory)
{
_logger = factory.CreateLogger<HeaderFindAndReplaceCreator>();
_fileGlobalConfiguration = fileConfiguration.Value.GlobalConfiguration;
_placeholders = placeholders;
}

public HeaderTransformations Create(FileRoute fileRoute)
{
var upstream = new List<HeaderFindAndReplace>();
var addHeadersToUpstream = new List<AddHeader>();
var upstreamHeaderTransform = Merge(fileRoute.UpstreamHeaderTransform, _fileGlobalConfiguration.UpstreamHeaderTransform);
var (upstream, addHeadersToUpstream) = ProcessHeaders(upstreamHeaderTransform, nameof(fileRoute.UpstreamHeaderTransform));

foreach (var input in fileRoute.UpstreamHeaderTransform)
{
if (input.Value.Contains(","))
{
var hAndr = Map(input);
if (!hAndr.IsError)
{
upstream.Add(hAndr.Data);
}
else
{
_logger.LogWarning(() => $"Unable to add UpstreamHeaderTransform {input.Key}: {input.Value}");
}
}
else
{
addHeadersToUpstream.Add(new AddHeader(input.Key, input.Value));
}
}
var downstreamHeaderTransform = Merge(fileRoute.DownstreamHeaderTransform, _fileGlobalConfiguration.DownstreamHeaderTransform);
var (downstream, addHeadersToDownstream) = ProcessHeaders(downstreamHeaderTransform, nameof(fileRoute.DownstreamHeaderTransform));

return new HeaderTransformations(upstream, downstream, addHeadersToDownstream, addHeadersToUpstream);
}

var downstream = new List<HeaderFindAndReplace>();
var addHeadersToDownstream = new List<AddHeader>();
private (List<HeaderFindAndReplace> StreamHeaders, List<AddHeader> AddHeaders) ProcessHeaders(IEnumerable<Header> headerTransform, string propertyName = null)
{
var headerPairs = headerTransform ?? Enumerable.Empty<Header>();

foreach (var input in fileRoute.DownstreamHeaderTransform)
var streamHeaders = new List<HeaderFindAndReplace>();
var addHeaders = new List<AddHeader>();

foreach (var input in headerPairs)
{
if (input.Value.Contains(","))
if (input.Value.Contains(HeaderFindAndReplace.Comma))
{
var hAndr = Map(input);
if (!hAndr.IsError)
{
downstream.Add(hAndr.Data);
streamHeaders.Add(hAndr.Data);
}
else
{
_logger.LogWarning(() => $"Unable to add DownstreamHeaderTransform {input.Key}: {input.Value}");
var name = propertyName ?? "Headers Transformation";
_logger.LogWarning(() => $"Unable to add {name} {input.Key}: {input.Value}");
}
}
else
{
addHeadersToDownstream.Add(new AddHeader(input.Key, input.Value));
addHeaders.Add(new AddHeader(input.Key, input.Value));
}
}

return new HeaderTransformations(upstream, downstream, addHeadersToDownstream, addHeadersToUpstream);
return (streamHeaders, addHeaders);
}

private Response<HeaderFindAndReplace> Map(KeyValuePair<string, string> input)
private Response<HeaderFindAndReplace> Map(Header input)
{
var findAndReplace = input.Value.Split(',');
var findAndReplace = input.Value.Split(HeaderFindAndReplace.Comma);

var replace = findAndReplace[1].TrimStart();

Expand All @@ -94,5 +89,18 @@ private Response<HeaderFindAndReplace> Map(KeyValuePair<string, string> input)

return new OkResponse<HeaderFindAndReplace>(hAndr);
}

/// <summary>
/// Merge global Up/Downstream settings to the Route local ones.
/// </summary>
/// <param name="local">The Route local settings.</param>
/// <param name="global">Global default settings.</param>
/// <returns> An <see cref="IEnumerable{T}"/> collection.</returns>
public static IEnumerable<Header> Merge(Dictionary<string, string> local, Dictionary<string, string> global)
{
// Winning strategy: The Route local setting wins over global one
var toAdd = global.ExceptBy(local.Keys, x => x.Key);
return local.Union(toAdd).ToList();
}
}
}
6 changes: 6 additions & 0 deletions src/Ocelot/Configuration/File/FileGlobalConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public FileGlobalConfiguration()
HttpHandlerOptions = new FileHttpHandlerOptions();
CacheOptions = new FileCacheOptions();
MetadataOptions = new FileMetadataOptions();
UpstreamHeaderTransform = new Dictionary<string, string>();
DownstreamHeaderTransform = new Dictionary<string, string>();
}

public string RequestIdKey { get; set; }
Expand Down Expand Up @@ -48,5 +50,9 @@ public FileGlobalConfiguration()
public FileCacheOptions CacheOptions { get; set; }

public FileMetadataOptions MetadataOptions { get; set; }

public Dictionary<string, string> UpstreamHeaderTransform { get; set; }

public Dictionary<string, string> DownstreamHeaderTransform { get; set; }
}
}
52 changes: 36 additions & 16 deletions src/Ocelot/Configuration/HeaderFindAndReplace.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
namespace Ocelot.Configuration
namespace Ocelot.Configuration;

public class HeaderFindAndReplace
{
public class HeaderFindAndReplace
public const char Comma = ',';

public HeaderFindAndReplace(HeaderFindAndReplace from)
{
public HeaderFindAndReplace(string key, string find, string replace, int index)
{
Key = key;
Find = find;
Replace = replace;
Index = index;
}
Key = from.Key;
Find = from.Find;
Replace = from.Replace;
Index = from.Index;
}

public string Key { get; }
public string Find { get; }
public string Replace { get; }

// only index 0 for now..
public int Index { get; }
public HeaderFindAndReplace(KeyValuePair<string, string> from)
{
Key = from.Key;
string[] parsed = from.Value.Split(Comma);
Find = parsed[0].Trim();
Replace = parsed[1].Trim();
Index = 0;
}
}

public HeaderFindAndReplace(string key, string find, string replace, int index)
{
Key = key;
Find = find;
Replace = replace;
Index = index;
}

public string Key { get; }
public string Find { get; }
public string Replace { get; }

// only index 0 for now..
public int Index { get; }

public override string ToString() => $"{Key} at {Index}: {Find} → {Replace}";
}
Loading