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 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
73 changes: 42 additions & 31 deletions src/Ocelot/Configuration/Creator/HeaderFindAndReplaceCreator.cs
Original file line number Diff line number Diff line change
@@ -1,73 +1,71 @@
using Microsoft.Extensions.Options;
using Ocelot.Configuration.File;
using Ocelot.Infrastructure;
using Ocelot.Logging;
using Ocelot.Responses;
using System;
using System.Collections.Generic;
using System.Linq;
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(','))
{
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(',');

Expand All @@ -94,5 +92,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; }
}
}