Support adding custom plaintext headers to downstream requests (#314)

This commit is contained in:
Felix Boers 2018-04-14 07:41:12 +02:00 committed by Tom Pallister
parent b46ef1945d
commit fa09e4cf7a
14 changed files with 376 additions and 183 deletions

View File

@ -1,15 +1,31 @@
Headers Transformation 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. 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.
Add to Request
^^^^^^^^^^^^^^
This feature was requestes in `GitHub #313 <https://github.com/ThreeMammals/Ocelot/issues/313>`_.
If you want to add a header to your upstream request please add the following to a ReRoute in your configuration.json:
.. code-block:: json
"UpstreamHeaderTransform": {
"Uncle": "Bob"
}
In the example above a header with the key Uncle and value Bob would be send to to the upstream service.
Placeholders are supported too (see below).
Add to Response Add to Response
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
This feature was requested in `GitHub #280 <https://github.com/TomPallister/Ocelot/issues/280>`_. I have only implemented This feature was requested in `GitHub #280 <https://github.com/TomPallister/Ocelot/issues/280>`_.
for responses but could add for requests in the future.
If you want to add a header to your downstream response please add the following to a ReRoute in configuration.json.. If you want to add a header to your downstream response please add the following to a ReRoute in configuration.json.
.. code-block:: json .. code-block:: json
@ -50,7 +66,7 @@ Add the following to a ReRoute in configuration.json in order to replace http://
}, },
Post Downstream Request 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. 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.

View File

@ -39,12 +39,14 @@ namespace Ocelot.Configuration.Builder
private string _key; private string _key;
private List<string> _delegatingHandlers; private List<string> _delegatingHandlers;
private List<AddHeader> _addHeadersToDownstream; private List<AddHeader> _addHeadersToDownstream;
private List<AddHeader> _addHeadersToUpstream;
public DownstreamReRouteBuilder() public DownstreamReRouteBuilder()
{ {
_downstreamAddresses = new List<DownstreamHostAndPort>(); _downstreamAddresses = new List<DownstreamHostAndPort>();
_delegatingHandlers = new List<string>(); _delegatingHandlers = new List<string>();
_addHeadersToDownstream = new List<AddHeader>(); _addHeadersToDownstream = new List<AddHeader>();
_addHeadersToUpstream = new List<AddHeader>();
} }
public DownstreamReRouteBuilder WithDownstreamAddresses(List<DownstreamHostAndPort> downstreamAddresses) public DownstreamReRouteBuilder WithDownstreamAddresses(List<DownstreamHostAndPort> downstreamAddresses)
@ -233,6 +235,12 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public DownstreamReRouteBuilder WithAddHeadersToUpstream(List<AddHeader> addHeadersToUpstream)
{
_addHeadersToUpstream = addHeadersToUpstream;
return this;
}
public DownstreamReRoute Build() public DownstreamReRoute Build()
{ {
return new DownstreamReRoute( return new DownstreamReRoute(
@ -263,7 +271,8 @@ namespace Ocelot.Configuration.Builder
new PathTemplate(_downstreamPathTemplate), new PathTemplate(_downstreamPathTemplate),
_reRouteKey, _reRouteKey,
_delegatingHandlers, _delegatingHandlers,
_addHeadersToDownstream); _addHeadersToDownstream,
_addHeadersToUpstream);
} }
} }
} }

View File

@ -215,6 +215,7 @@ namespace Ocelot.Configuration.Creator
.WithUpstreamHost(fileReRoute.UpstreamHost) .WithUpstreamHost(fileReRoute.UpstreamHost)
.WithDelegatingHandlers(fileReRoute.DelegatingHandlers) .WithDelegatingHandlers(fileReRoute.DelegatingHandlers)
.WithAddHeadersToDownstream(hAndRs.AddHeadersToDownstream) .WithAddHeadersToDownstream(hAndRs.AddHeadersToDownstream)
.WithAddHeadersToUpstream(hAndRs.AddHeadersToUpstream)
.Build(); .Build();
return reRoute; return reRoute;

View File

@ -22,17 +22,25 @@ namespace Ocelot.Configuration.Creator
public HeaderTransformations Create(FileReRoute fileReRoute) public HeaderTransformations Create(FileReRoute fileReRoute)
{ {
var upstream = new List<HeaderFindAndReplace>(); var upstream = new List<HeaderFindAndReplace>();
var addHeadersToUpstream = new List<AddHeader>();
foreach(var input in fileReRoute.UpstreamHeaderTransform) foreach(var input in fileReRoute.UpstreamHeaderTransform)
{ {
var hAndr = Map(input); if (input.Value.Contains(","))
if(!hAndr.IsError)
{ {
upstream.Add(hAndr.Data); var hAndr = Map(input);
if (!hAndr.IsError)
{
upstream.Add(hAndr.Data);
}
else
{
_logger.LogWarning($"Unable to add UpstreamHeaderTransform {input.Key}: {input.Value}");
}
} }
else else
{ {
_logger.LogWarning($"Unable to add UpstreamHeaderTransform {input.Key}: {input.Value}"); addHeadersToUpstream.Add(new AddHeader(input.Key, input.Value));
} }
} }
@ -59,7 +67,7 @@ namespace Ocelot.Configuration.Creator
} }
} }
return new HeaderTransformations(upstream, downstream, addHeadersToDownstream); return new HeaderTransformations(upstream, downstream, addHeadersToDownstream, addHeadersToUpstream);
} }
private Response<HeaderFindAndReplace> Map(KeyValuePair<string,string> input) private Response<HeaderFindAndReplace> Map(KeyValuePair<string,string> input)

View File

@ -7,9 +7,11 @@ namespace Ocelot.Configuration.Creator
public HeaderTransformations( public HeaderTransformations(
List<HeaderFindAndReplace> upstream, List<HeaderFindAndReplace> upstream,
List<HeaderFindAndReplace> downstream, List<HeaderFindAndReplace> downstream,
List<AddHeader> addHeader) List<AddHeader> addHeaderToDownstream,
List<AddHeader> addHeaderToUpstream)
{ {
AddHeadersToDownstream = addHeader; AddHeadersToDownstream = addHeaderToDownstream;
AddHeadersToUpstream = addHeaderToUpstream;
Upstream = upstream; Upstream = upstream;
Downstream = downstream; Downstream = downstream;
} }
@ -19,5 +21,6 @@ namespace Ocelot.Configuration.Creator
public List<HeaderFindAndReplace> Downstream { get; } public List<HeaderFindAndReplace> Downstream { get; }
public List<AddHeader> AddHeadersToDownstream { get; } public List<AddHeader> AddHeadersToDownstream { get; }
public List<AddHeader> AddHeadersToUpstream { get; }
} }
} }

View File

@ -34,7 +34,8 @@ namespace Ocelot.Configuration
PathTemplate downstreamPathTemplate, PathTemplate downstreamPathTemplate,
string reRouteKey, string reRouteKey,
List<string> delegatingHandlers, List<string> delegatingHandlers,
List<AddHeader> addHeadersToDownstream) List<AddHeader> addHeadersToDownstream,
List<AddHeader> addHeadersToUpstream)
{ {
AddHeadersToDownstream = addHeadersToDownstream; AddHeadersToDownstream = addHeadersToDownstream;
DelegatingHandlers = delegatingHandlers; DelegatingHandlers = delegatingHandlers;
@ -64,6 +65,7 @@ namespace Ocelot.Configuration
AuthenticationOptions = authenticationOptions; AuthenticationOptions = authenticationOptions;
DownstreamPathTemplate = downstreamPathTemplate; DownstreamPathTemplate = downstreamPathTemplate;
ReRouteKey = reRouteKey; ReRouteKey = reRouteKey;
AddHeadersToUpstream = addHeadersToUpstream;
} }
public string Key { get; private set; } public string Key { get; private set; }
@ -94,5 +96,6 @@ namespace Ocelot.Configuration
public string ReRouteKey { get; private set; } public string ReRouteKey { get; private set; }
public List<string> DelegatingHandlers {get;private set;} public List<string> DelegatingHandlers {get;private set;}
public List<AddHeader> AddHeadersToDownstream {get;private set;} public List<AddHeader> AddHeadersToDownstream {get;private set;}
public List<AddHeader> AddHeadersToUpstream { get; private set; }
} }
} }

View File

@ -4,6 +4,7 @@ using Ocelot.Configuration;
using Ocelot.Infrastructure.Claims.Parser; using Ocelot.Infrastructure.Claims.Parser;
using Ocelot.Responses; using Ocelot.Responses;
using System.Net.Http; using System.Net.Http;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.Creator; using Ocelot.Configuration.Creator;
using Ocelot.Request.Middleware; using Ocelot.Request.Middleware;
@ -41,5 +42,19 @@ namespace Ocelot.Headers
return new OkResponse(); return new OkResponse();
} }
public void SetHeadersOnDownstreamRequest(IEnumerable<AddHeader> headers, HttpContext context)
{
var requestHeader = context.Request.Headers;
foreach (var header in headers)
{
if (requestHeader.ContainsKey(header.Key))
{
requestHeader.Remove(header.Key);
}
requestHeader.Add(header.Key, header.Value);
}
}
} }
} }

View File

@ -1,4 +1,6 @@
namespace Ocelot.Headers using Microsoft.AspNetCore.Http;
namespace Ocelot.Headers
{ {
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
@ -12,5 +14,6 @@
public interface IAddHeadersToRequest public interface IAddHeadersToRequest
{ {
Response SetHeadersOnDownstreamRequest(List<ClaimToThing> claimsToThings, IEnumerable<System.Security.Claims.Claim> claims, DownstreamRequest downstreamRequest); Response SetHeadersOnDownstreamRequest(List<ClaimToThing> claimsToThings, IEnumerable<System.Security.Claims.Claim> claims, DownstreamRequest downstreamRequest);
void SetHeadersOnDownstreamRequest(IEnumerable<AddHeader> headers, HttpContext context);
} }
} }

View File

@ -9,16 +9,19 @@ namespace Ocelot.Headers.Middleware
private readonly OcelotRequestDelegate _next; private readonly OcelotRequestDelegate _next;
private readonly IHttpContextRequestHeaderReplacer _preReplacer; private readonly IHttpContextRequestHeaderReplacer _preReplacer;
private readonly IHttpResponseHeaderReplacer _postReplacer; private readonly IHttpResponseHeaderReplacer _postReplacer;
private readonly IAddHeadersToResponse _addHeaders; private readonly IAddHeadersToResponse _addHeadersToResponse;
private readonly IAddHeadersToRequest _addHeadersToRequest;
public HttpHeadersTransformationMiddleware(OcelotRequestDelegate next, public HttpHeadersTransformationMiddleware(OcelotRequestDelegate next,
IOcelotLoggerFactory loggerFactory, IOcelotLoggerFactory loggerFactory,
IHttpContextRequestHeaderReplacer preReplacer, IHttpContextRequestHeaderReplacer preReplacer,
IHttpResponseHeaderReplacer postReplacer, IHttpResponseHeaderReplacer postReplacer,
IAddHeadersToResponse addHeaders) IAddHeadersToResponse addHeadersToResponse,
IAddHeadersToRequest addHeadersToRequest)
:base(loggerFactory.CreateLogger<HttpHeadersTransformationMiddleware>()) :base(loggerFactory.CreateLogger<HttpHeadersTransformationMiddleware>())
{ {
_addHeaders = addHeaders; _addHeadersToResponse = addHeadersToResponse;
_addHeadersToRequest = addHeadersToRequest;
_next = next; _next = next;
_postReplacer = postReplacer; _postReplacer = postReplacer;
_preReplacer = preReplacer; _preReplacer = preReplacer;
@ -31,13 +34,15 @@ namespace Ocelot.Headers.Middleware
//todo - this should be on httprequestmessage not httpcontext? //todo - this should be on httprequestmessage not httpcontext?
_preReplacer.Replace(context.HttpContext, preFAndRs); _preReplacer.Replace(context.HttpContext, preFAndRs);
_addHeadersToRequest.SetHeadersOnDownstreamRequest(context.DownstreamReRoute.AddHeadersToUpstream, context.HttpContext);
await _next.Invoke(context); await _next.Invoke(context);
var postFAndRs = context.DownstreamReRoute.DownstreamHeadersFindAndReplace; var postFAndRs = context.DownstreamReRoute.DownstreamHeadersFindAndReplace;
_postReplacer.Replace(context.DownstreamResponse, postFAndRs, context.DownstreamRequest); _postReplacer.Replace(context.DownstreamResponse, postFAndRs, context.DownstreamRequest);
_addHeaders.Add(context.DownstreamReRoute.AddHeadersToDownstream, context.DownstreamResponse); _addHeadersToResponse.Add(context.DownstreamReRoute.AddHeadersToDownstream, context.DownstreamResponse);
} }
} }
} }

View File

@ -829,6 +829,7 @@ namespace Ocelot.UnitTests.Configuration
result.DownstreamReRoute[0].RequestIdKey.ShouldBe(expected.DownstreamReRoute[0].RequestIdKey); result.DownstreamReRoute[0].RequestIdKey.ShouldBe(expected.DownstreamReRoute[0].RequestIdKey);
result.DownstreamReRoute[0].DelegatingHandlers.ShouldBe(expected.DownstreamReRoute[0].DelegatingHandlers); result.DownstreamReRoute[0].DelegatingHandlers.ShouldBe(expected.DownstreamReRoute[0].DelegatingHandlers);
result.DownstreamReRoute[0].AddHeadersToDownstream.ShouldBe(expected.DownstreamReRoute[0].AddHeadersToDownstream); result.DownstreamReRoute[0].AddHeadersToDownstream.ShouldBe(expected.DownstreamReRoute[0].AddHeadersToDownstream);
result.DownstreamReRoute[0].AddHeadersToUpstream.ShouldBe(expected.DownstreamReRoute[0].AddHeadersToUpstream, "AddHeadersToUpstream should be set");
} }
} }
@ -911,7 +912,7 @@ namespace Ocelot.UnitTests.Configuration
private void GivenTheHeaderFindAndReplaceCreatorReturns() private void GivenTheHeaderFindAndReplaceCreatorReturns()
{ {
_headerFindAndReplaceCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(new HeaderTransformations(new List<HeaderFindAndReplace>(), new List<HeaderFindAndReplace>(), new List<AddHeader>())); _headerFindAndReplaceCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(new HeaderTransformations(new List<HeaderFindAndReplace>(), new List<HeaderFindAndReplace>(), new List<AddHeader>(), new List<AddHeader>()));
} }
private void GivenTheFollowingIsReturned(ServiceProviderConfiguration serviceProviderConfiguration) private void GivenTheFollowingIsReturned(ServiceProviderConfiguration serviceProviderConfiguration)

View File

@ -149,7 +149,6 @@ namespace Ocelot.UnitTests.Configuration
.Then(x => ThenTheFollowingDownstreamIsReturned(downstream)) .Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
.BDDfy(); .BDDfy();
} }
[Fact] [Fact]
public void should_add_trace_id_header() public void should_add_trace_id_header()
{ {
@ -166,7 +165,45 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => GivenTheReRoute(reRoute)) this.Given(x => GivenTheReRoute(reRoute))
.And(x => GivenTheBaseUrlIs("http://ocelot.com/")) .And(x => GivenTheBaseUrlIs("http://ocelot.com/"))
.When(x => WhenICreate()) .When(x => WhenICreate())
.Then(x => ThenTheFollowingAddHeaderIsReturned(expected)) .Then(x => ThenTheFollowingAddHeaderToDownstreamIsReturned(expected))
.BDDfy();
}
[Fact]
public void should_add_downstream_header_as_is_when_no_replacement_is_given()
{
var reRoute = new FileReRoute
{
DownstreamHeaderTransform = new Dictionary<string, string>
{
{"X-Custom-Header", "Value"},
}
};
var expected = new AddHeader("X-Custom-Header", "Value");
this.Given(x => GivenTheReRoute(reRoute))
.And(x => WhenICreate())
.Then(x => x.ThenTheFollowingAddHeaderToDownstreamIsReturned(expected))
.BDDfy();
}
[Fact]
public void should_add_upstream_header_as_is_when_no_replacement_is_given()
{
var reRoute = new FileReRoute
{
UpstreamHeaderTransform = new Dictionary<string, string>
{
{"X-Custom-Header", "Value"},
}
};
var expected = new AddHeader("X-Custom-Header", "Value");
this.Given(x => GivenTheReRoute(reRoute))
.And(x => WhenICreate())
.Then(x => x.ThenTheFollowingAddHeaderToUpstreamIsReturned(expected))
.BDDfy(); .BDDfy();
} }
@ -180,12 +217,18 @@ namespace Ocelot.UnitTests.Configuration
_placeholders.Setup(x => x.Get(It.IsAny<string>())).Returns(new ErrorResponse<string>(new AnyError())); _placeholders.Setup(x => x.Get(It.IsAny<string>())).Returns(new ErrorResponse<string>(new AnyError()));
} }
private void ThenTheFollowingAddHeaderIsReturned(AddHeader addHeader) private void ThenTheFollowingAddHeaderToDownstreamIsReturned(AddHeader addHeader)
{ {
_result.AddHeadersToDownstream[0].Key.ShouldBe(addHeader.Key); _result.AddHeadersToDownstream[0].Key.ShouldBe(addHeader.Key);
_result.AddHeadersToDownstream[0].Value.ShouldBe(addHeader.Value); _result.AddHeadersToDownstream[0].Value.ShouldBe(addHeader.Value);
} }
private void ThenTheFollowingAddHeaderToUpstreamIsReturned(AddHeader addHeader)
{
_result.AddHeadersToUpstream[0].Key.ShouldBe(addHeader.Key);
_result.AddHeadersToUpstream[0].Value.ShouldBe(addHeader.Value);
}
private void ThenTheFollowingDownstreamIsReturned(List<HeaderFindAndReplace> downstream) private void ThenTheFollowingDownstreamIsReturned(List<HeaderFindAndReplace> downstream)
{ {
_result.Downstream.Count.ShouldBe(downstream.Count); _result.Downstream.Count.ShouldBe(downstream.Count);

View File

@ -15,7 +15,7 @@ using Ocelot.Request.Middleware;
namespace Ocelot.UnitTests.Headers namespace Ocelot.UnitTests.Headers
{ {
public class AddHeadersToRequestTests public class AddHeadersToRequestClaimToThingTests
{ {
private readonly AddHeadersToRequest _addHeadersToRequest; private readonly AddHeadersToRequest _addHeadersToRequest;
private readonly Mock<IClaimsParser> _parser; private readonly Mock<IClaimsParser> _parser;
@ -25,7 +25,7 @@ namespace Ocelot.UnitTests.Headers
private Response _result; private Response _result;
private Response<string> _claimValue; private Response<string> _claimValue;
public AddHeadersToRequestTests() public AddHeadersToRequestClaimToThingTests()
{ {
_parser = new Mock<IClaimsParser>(); _parser = new Mock<IClaimsParser>();
_addHeadersToRequest = new AddHeadersToRequest(_parser.Object); _addHeadersToRequest = new AddHeadersToRequest(_parser.Object);

View File

@ -0,0 +1,75 @@
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Configuration.Creator;
using Ocelot.Headers;
using Ocelot.Infrastructure.Claims.Parser;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Headers
{
public class AddHeadersToRequestPlainTests
{
private readonly AddHeadersToRequest _addHeadersToRequest;
private HttpContext _context;
private AddHeader _addedHeader;
public AddHeadersToRequestPlainTests()
{
_addHeadersToRequest = new AddHeadersToRequest(Mock.Of<IClaimsParser>());
}
[Fact]
public void should_add_plain_text_header_to_downstream_request()
{
this.Given(_ => GivenHttpRequestWithoutHeaders())
.When(_ => WhenAddingHeader("X-Custom-Header", "PlainValue"))
.Then(_ => ThenTheHeaderGetsTakenOverToTheRequestHeaders())
.BDDfy();
}
[Fact]
public void should_overwrite_existing_header_with_added_header()
{
this.Given(_ => GivenHttpRequestWithHeader("X-Custom-Header", "This should get overwritten"))
.When(_ => WhenAddingHeader("X-Custom-Header", "PlainValue"))
.Then(_ => ThenTheHeaderGetsTakenOverToTheRequestHeaders())
.BDDfy();
}
private void GivenHttpRequestWithoutHeaders()
{
_context = new DefaultHttpContext();
}
private void GivenHttpRequestWithHeader(string headerKey, string headerValue)
{
_context = new DefaultHttpContext
{
Request =
{
Headers =
{
{ headerKey, headerValue }
}
}
};
}
private void WhenAddingHeader(string headerKey, string headerValue)
{
_addedHeader = new AddHeader(headerKey, headerValue);
_addHeadersToRequest.SetHeadersOnDownstreamRequest(new[] { _addedHeader }, _context);
}
private void ThenTheHeaderGetsTakenOverToTheRequestHeaders()
{
var requestHeaders = _context.Request.Headers;
requestHeaders.ContainsKey(_addedHeader.Key).ShouldBeTrue($"Header {_addedHeader.Key} was expected but not there.");
var value = requestHeaders[_addedHeader.Key];
value.ShouldNotBeNull($"Value of header {_addedHeader.Key} was expected to not be null.");
value.ToString().ShouldBe(_addedHeader.Value);
}
}
}

View File

@ -27,7 +27,8 @@ namespace Ocelot.UnitTests.Headers
private readonly HttpHeadersTransformationMiddleware _middleware; private readonly HttpHeadersTransformationMiddleware _middleware;
private readonly DownstreamContext _downstreamContext; private readonly DownstreamContext _downstreamContext;
private OcelotRequestDelegate _next; private OcelotRequestDelegate _next;
private readonly Mock<IAddHeadersToResponse> _addHeaders; private readonly Mock<IAddHeadersToResponse> _addHeadersToResponse;
private readonly Mock<IAddHeadersToRequest> _addHeadersToRequest;
public HttpHeadersTransformationMiddlewareTests() public HttpHeadersTransformationMiddlewareTests()
{ {
@ -38,8 +39,11 @@ namespace Ocelot.UnitTests.Headers
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
_next = context => Task.CompletedTask; _next = context => Task.CompletedTask;
_addHeaders = new Mock<IAddHeadersToResponse>(); _addHeadersToResponse = new Mock<IAddHeadersToResponse>();
_middleware = new HttpHeadersTransformationMiddleware(_next, _loggerFactory.Object, _preReplacer.Object, _postReplacer.Object, _addHeaders.Object); _addHeadersToRequest = new Mock<IAddHeadersToRequest>();
_middleware = new HttpHeadersTransformationMiddleware(
_next, _loggerFactory.Object, _preReplacer.Object,
_postReplacer.Object, _addHeadersToResponse.Object, _addHeadersToRequest.Object);
} }
[Fact] [Fact]
@ -51,17 +55,24 @@ namespace Ocelot.UnitTests.Headers
.And(x => GivenTheHttpResponseMessageIs()) .And(x => GivenTheHttpResponseMessageIs())
.When(x => WhenICallTheMiddleware()) .When(x => WhenICallTheMiddleware())
.Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly()) .Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly())
.Then(x => ThenAddHeadersToRequestIsCalledCorrectly())
.And(x => ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly()) .And(x => ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly())
.And(x => ThenAddHeadersIsCalledCorrectly()) .And(x => ThenAddHeadersToResponseIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
private void ThenAddHeadersIsCalledCorrectly() private void ThenAddHeadersToResponseIsCalledCorrectly()
{ {
_addHeaders _addHeadersToResponse
.Verify(x => x.Add(_downstreamContext.DownstreamReRoute.AddHeadersToDownstream, _downstreamContext.DownstreamResponse), Times.Once); .Verify(x => x.Add(_downstreamContext.DownstreamReRoute.AddHeadersToDownstream, _downstreamContext.DownstreamResponse), Times.Once);
} }
private void ThenAddHeadersToRequestIsCalledCorrectly()
{
_addHeadersToRequest
.Verify(x => x.SetHeadersOnDownstreamRequest(_downstreamContext.DownstreamReRoute.AddHeadersToUpstream, _downstreamContext.HttpContext), Times.Once);
}
private void WhenICallTheMiddleware() private void WhenICallTheMiddleware()
{ {
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult(); _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();