Skip to content

Commit

Permalink
Merge branch 'release-2.0.11'
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Gardham-Pallister committed Jan 22, 2018
2 parents 1824f99 + d0eee70 commit a38f3cb
Show file tree
Hide file tree
Showing 34 changed files with 1,280 additions and 18 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,7 @@ test/Ocelot.AcceptanceTests/configuration.json
# Read the docstates
_build/
_static/
_templates/
_templates/

# JetBrains Rider
.idea/
70 changes: 70 additions & 0 deletions docs/features/headerstransformation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
Headers Transformation
=====================

Ocelot allows the user to transform headers pre and post downstream request. At the moment Ocelot only supports find and replace. This feature was requested `GitHub #190 <https://github.com/TomPallister/Ocelot/issues/190>`_ and I decided that it was going to be useful in various ways.

Syntax
^^^^^^

In order to transform a header first we specify the header key and then the type of transform we want e.g.

.. code-block:: json
"Test": "http://www.bbc.co.uk/, http://ocelot.com/"
The key is "Test" and the value is "http://www.bbc.co.uk/, http://ocelot.com/". The value is saying replace http://www.bbc.co.uk/ with http://ocelot.com/. The syntax is {find}, {replace}. Hopefully pretty simple. There are examples below that explain more.

Pre Downstream Request
^^^^^^^^^^^^^^^^^^^^^^

Add the following to a ReRoute in configuration.json in order to replace http://www.bbc.co.uk/ with http://ocelot.com/. This header will be changed before the request downstream and will be sent to the downstream server.

.. code-block:: json
"UpstreamHeaderTransform": {
"Test": "http://www.bbc.co.uk/, http://ocelot.com/"
},
Post Downstream Request
^^^^^^^^^^^^^^^^^^^^^^

Add the following to a ReRoute in configuration.json in order to replace http://www.bbc.co.uk/ with http://ocelot.com/. This transformation will take place after Ocelot has received the response from the downstream service.

.. code-block:: json
"DownstreamHeaderTransform": {
"Test": "http://www.bbc.co.uk/, http://ocelot.com/"
},
Placeholders
^^^^^^^^^^^^

Ocelot allows placeholders that can be used in header transformation. At the moment there is only one placeholder.

{BaseUrl} - This will use Ocelot's base url e.g. http://localhost:5000 as its value.

Handling 302 Redirects
^^^^^^^^^^^^^^^^^^^^^^
Ocelot will by default automatically follow redirects however if you want to return the location header to the client you might want to change the location to be Ocelot not the downstream service. Ocelot allows this with the following configuration.

.. code-block:: json
"DownstreamHeaderTransform": {
"Location": "http://www.bbc.co.uk/, http://ocelot.com/"
},
"HttpHandlerOptions": {
"AllowAutoRedirect": false,
},
or you could use the BaseUrl placeholder.

.. code-block:: json
"DownstreamHeaderTransform": {
"Location": "http://localhost:6773, {BaseUrl}"
},
"HttpHandlerOptions": {
"AllowAutoRedirect": false,
},
Ocelot will not try and replace the location header returned by the downstream service with its own URL.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Thanks for taking a look at the Ocelot documentation. Please use the left hand n
features/raft
features/caching
features/qualityofservice
features/headerstransformation
features/claimstransformation
features/logging
features/requestid
Expand Down
3 changes: 3 additions & 0 deletions run-acceptance-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

./build.sh --target RunAcceptanceTests
3 changes: 3 additions & 0 deletions run-unit-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

./build.sh --target RunUnitTests
19 changes: 18 additions & 1 deletion src/Ocelot/Configuration/Builder/ReRouteBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public class ReRouteBuilder
private bool _useServiceDiscovery;
private string _serviceName;

private List<HeaderFindAndReplace> _upstreamHeaderFindAndReplace;
private List<HeaderFindAndReplace> _downstreamHeaderFindAndReplace;

public ReRouteBuilder WithLoadBalancer(string loadBalancer)
{
_loadBalancer = loadBalancer;
Expand Down Expand Up @@ -198,6 +201,18 @@ public ReRouteBuilder WithServiceName(string serviceName)
return this;
}

public ReRouteBuilder WithUpstreamHeaderFindAndReplace(List<HeaderFindAndReplace> upstreamHeaderFindAndReplace)
{
_upstreamHeaderFindAndReplace = upstreamHeaderFindAndReplace;
return this;
}

public ReRouteBuilder WithDownstreamHeaderFindAndReplace(List<HeaderFindAndReplace> downstreamHeaderFindAndReplace)
{
_downstreamHeaderFindAndReplace = downstreamHeaderFindAndReplace;
return this;
}

public ReRoute Build()
{
return new ReRoute(
Expand Down Expand Up @@ -226,7 +241,9 @@ public ReRoute Build()
_rateLimitOptions,
_httpHandlerOptions,
_useServiceDiscovery,
_serviceName);
_serviceName,
_upstreamHeaderFindAndReplace,
_downstreamHeaderFindAndReplace);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class FileOcelotConfigurationCreator : IOcelotConfigurationCreator
private readonly IRegionCreator _regionCreator;
private readonly IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
private readonly IAdministrationPath _adminPath;
private readonly IHeaderFindAndReplaceCreator _headerFAndRCreator;


public FileOcelotConfigurationCreator(
Expand All @@ -53,9 +54,11 @@ public FileOcelotConfigurationCreator(
IRateLimitOptionsCreator rateLimitOptionsCreator,
IRegionCreator regionCreator,
IHttpHandlerOptionsCreator httpHandlerOptionsCreator,
IAdministrationPath adminPath
IAdministrationPath adminPath,
IHeaderFindAndReplaceCreator headerFAndRCreator
)
{
_headerFAndRCreator = headerFAndRCreator;
_adminPath = adminPath;
_regionCreator = regionCreator;
_rateLimitOptionsCreator = rateLimitOptionsCreator;
Expand Down Expand Up @@ -128,6 +131,8 @@ private ReRoute SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration gl

var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute);

var hAndRs = _headerFAndRCreator.Create(fileReRoute);

var reRoute = new ReRouteBuilder()
.WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate)
.WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate)
Expand Down Expand Up @@ -155,6 +160,8 @@ private ReRoute SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration gl
.WithHttpHandlerOptions(httpHandlerOptions)
.WithServiceName(fileReRoute.ServiceName)
.WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery)
.WithUpstreamHeaderFindAndReplace(hAndRs.Upstream)
.WithDownstreamHeaderFindAndReplace(hAndRs.Downstream)
.Build();

return reRoute;
Expand Down
68 changes: 68 additions & 0 deletions src/Ocelot/Configuration/Creator/HeaderFindAndReplaceCreator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using Ocelot.Configuration.File;
using Ocelot.Middleware;

namespace Ocelot.Configuration.Creator
{
public class HeaderFindAndReplaceCreator : IHeaderFindAndReplaceCreator
{
private IBaseUrlFinder _finder;
private Dictionary<string, Func<string>> _placeholders;

public HeaderFindAndReplaceCreator(IBaseUrlFinder finder)
{
_finder = finder;
_placeholders = new Dictionary<string, Func<string>>();
_placeholders.Add("{BaseUrl}", () => {
return _finder.Find();
});
}

public HeaderTransformations Create(FileReRoute fileReRoute)
{
var upstream = new List<HeaderFindAndReplace>();

foreach(var input in fileReRoute.UpstreamHeaderTransform)
{
var hAndr = Map(input);
upstream.Add(hAndr);
}

var downstream = new List<HeaderFindAndReplace>();

foreach(var input in fileReRoute.DownstreamHeaderTransform)
{
var hAndr = Map(input);
downstream.Add(hAndr);
}

return new HeaderTransformations(upstream, downstream);
}

private HeaderFindAndReplace Map(KeyValuePair<string,string> input)
{
var findAndReplace = input.Value.Split(",");

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

var startOfPlaceholder = replace.IndexOf("{");
if(startOfPlaceholder > -1)
{
var endOfPlaceholder = replace.IndexOf("}", startOfPlaceholder);

var placeholder = replace.Substring(startOfPlaceholder, startOfPlaceholder + (endOfPlaceholder + 1));

if(_placeholders.ContainsKey(placeholder))
{
var value = _placeholders[placeholder].Invoke();
replace = replace.Replace(placeholder, value);
}
}

var hAndr = new HeaderFindAndReplace(input.Key, findAndReplace[0], replace, 0);

return hAndr;
}
}
}
17 changes: 17 additions & 0 deletions src/Ocelot/Configuration/Creator/HeaderTransformations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;

namespace Ocelot.Configuration.Creator
{
public class HeaderTransformations
{
public HeaderTransformations(List<HeaderFindAndReplace> upstream, List<HeaderFindAndReplace> downstream)
{
Upstream = upstream;
Downstream = downstream;
}

public List<HeaderFindAndReplace> Upstream {get;private set;}

public List<HeaderFindAndReplace> Downstream {get;private set;}
}
}
10 changes: 10 additions & 0 deletions src/Ocelot/Configuration/Creator/IHeaderFindAndReplaceCreator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using Ocelot.Configuration.File;

namespace Ocelot.Configuration.Creator
{
public interface IHeaderFindAndReplaceCreator
{
HeaderTransformations Create(FileReRoute fileReRoute);
}
}
4 changes: 4 additions & 0 deletions src/Ocelot/Configuration/File/FileReRoute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,21 @@ public FileReRoute()
AddClaimsToRequest = new Dictionary<string, string>();
RouteClaimsRequirement = new Dictionary<string, string>();
AddQueriesToRequest = new Dictionary<string, string>();
DownstreamHeaderTransform = new Dictionary<string, string>();
FileCacheOptions = new FileCacheOptions();
QoSOptions = new FileQoSOptions();
RateLimitOptions = new FileRateLimitRule();
AuthenticationOptions = new FileAuthenticationOptions();
HttpHandlerOptions = new FileHttpHandlerOptions();
UpstreamHeaderTransform = new Dictionary<string, string>();
}

public string DownstreamPathTemplate { get; set; }
public string UpstreamPathTemplate { get; set; }
public List<string> UpstreamHttpMethod { get; set; }
public Dictionary<string, string> AddHeadersToRequest { get; set; }
public Dictionary<string, string> UpstreamHeaderTransform { get; set; }
public Dictionary<string, string> DownstreamHeaderTransform { get; set; }
public Dictionary<string, string> AddClaimsToRequest { get; set; }
public Dictionary<string, string> RouteClaimsRequirement { get; set; }
public Dictionary<string, string> AddQueriesToRequest { get; set; }
Expand Down
20 changes: 20 additions & 0 deletions src/Ocelot/Configuration/HeaderFindAndReplace.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Ocelot.Configuration
{
public class HeaderFindAndReplace
{
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;}
}
}
9 changes: 8 additions & 1 deletion src/Ocelot/Configuration/ReRoute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ public ReRoute(PathTemplate downstreamPathTemplate,
RateLimitOptions ratelimitOptions,
HttpHandlerOptions httpHandlerOptions,
bool useServiceDiscovery,
string serviceName)
string serviceName,
List<HeaderFindAndReplace> upstreamHeadersFindAndReplace,
List<HeaderFindAndReplace> downstreamHeadersFindAndReplace)
{
DownstreamHeadersFindAndReplace = downstreamHeadersFindAndReplace;
UpstreamHeadersFindAndReplace = upstreamHeadersFindAndReplace;
ServiceName = serviceName;
UseServiceDiscovery = useServiceDiscovery;
ReRouteKey = reRouteKey;
Expand Down Expand Up @@ -91,5 +95,8 @@ public ReRoute(PathTemplate downstreamPathTemplate,
public HttpHandlerOptions HttpHandlerOptions { get; private set; }
public bool UseServiceDiscovery {get;private set;}
public string ServiceName {get;private set;}
public List<HeaderFindAndReplace> UpstreamHeadersFindAndReplace {get;private set;}
public List<HeaderFindAndReplace> DownstreamHeadersFindAndReplace {get;private set;}

}
}
3 changes: 3 additions & 0 deletions src/Ocelot/DependencyInjection/OcelotBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ public OcelotBuilder(IServiceCollection services, IConfiguration configurationRo

//add ocelot services...
_services.Configure<FileConfiguration>(configurationRoot);
_services.TryAddSingleton<IHttpResponseHeaderReplacer, HttpResponseHeaderReplacer>();
_services.TryAddSingleton<IHttpContextRequestHeaderReplacer, HttpContextRequestHeaderReplacer>();
_services.TryAddSingleton<IHeaderFindAndReplaceCreator, HeaderFindAndReplaceCreator>();
_services.TryAddSingleton<IOcelotConfigurationCreator, FileOcelotConfigurationCreator>();
_services.TryAddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
_services.TryAddSingleton<IConfigurationValidator, FileConfigurationFluentValidator>();
Expand Down
1 change: 1 addition & 0 deletions src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ public DownstreamRoute(List<PlaceholderNameAndValue> templatePlaceholderNameAndV
}
public List<PlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; private set; }
public ReRoute ReRoute { get; private set; }
public object UpstreamHeadersFindAndReplace {get;private set;}
}
}
7 changes: 5 additions & 2 deletions src/Ocelot/Errors/Middleware/ExceptionHandlerMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public ExceptionHandlerMiddleware(RequestDelegate next,
public async Task Invoke(HttpContext context)
{
try
{
{
await TrySetGlobalRequestId(context);

_logger.LogDebug("ocelot pipeline started");
Expand Down Expand Up @@ -85,7 +85,10 @@ private async Task TrySetGlobalRequestId(HttpContext context)

private void SetInternalServerErrorOnResponse(HttpContext context)
{
context.Response.StatusCode = 500;
if (!context.Response.HasStarted)
{
context.Response.StatusCode = 500;
}
}

private string CreateMessage(HttpContext context, Exception e)
Expand Down
Loading

0 comments on commit a38f3cb

Please sign in to comment.