mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 20:30:50 +08:00 
			
		
		
		
	#296 merged develop into this branch
This commit is contained in:
		@@ -1,13 +1,29 @@
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
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 ocelot.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
 | 
			
		||||
^^^^^^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
This feature was requested in `GitHub #280 <https://github.com/TomPallister/Ocelot/issues/280>`_. I have only implemented
 | 
			
		||||
for responses but could add for requests in the future.
 | 
			
		||||
This feature was requested in `GitHub #280 <https://github.com/TomPallister/Ocelot/issues/280>`_.
 | 
			
		||||
 | 
			
		||||
If you want to add a header to your downstream response please add the following to a ReRoute in ocelot.json..
 | 
			
		||||
 | 
			
		||||
@@ -50,7 +66,7 @@ Add the following to a ReRoute in ocelot.json in order to replace http://www.bbc
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
Post Downstream Request
 | 
			
		||||
^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
^^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
Add the following to a ReRoute in ocelot.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.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,12 +39,14 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
        private string _key;
 | 
			
		||||
        private List<string> _delegatingHandlers;
 | 
			
		||||
        private List<AddHeader> _addHeadersToDownstream;
 | 
			
		||||
        private List<AddHeader> _addHeadersToUpstream;
 | 
			
		||||
 | 
			
		||||
        public DownstreamReRouteBuilder()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamAddresses = new List<DownstreamHostAndPort>();
 | 
			
		||||
            _delegatingHandlers = new List<string>();
 | 
			
		||||
            _addHeadersToDownstream = new List<AddHeader>();
 | 
			
		||||
            _addHeadersToUpstream = new List<AddHeader>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DownstreamReRouteBuilder WithDownstreamAddresses(List<DownstreamHostAndPort> downstreamAddresses)
 | 
			
		||||
@@ -233,6 +235,12 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DownstreamReRouteBuilder WithAddHeadersToUpstream(List<AddHeader> addHeadersToUpstream)
 | 
			
		||||
        {
 | 
			
		||||
            _addHeadersToUpstream = addHeadersToUpstream;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DownstreamReRoute Build()
 | 
			
		||||
        {
 | 
			
		||||
            return new DownstreamReRoute(
 | 
			
		||||
@@ -263,7 +271,8 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
                new PathTemplate(_downstreamPathTemplate),
 | 
			
		||||
                _reRouteKey,
 | 
			
		||||
                _delegatingHandlers,
 | 
			
		||||
                _addHeadersToDownstream);
 | 
			
		||||
                _addHeadersToDownstream,
 | 
			
		||||
                _addHeadersToUpstream);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -212,6 +212,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                .WithUpstreamHost(fileReRoute.UpstreamHost)
 | 
			
		||||
                .WithDelegatingHandlers(fileReRoute.DelegatingHandlers)
 | 
			
		||||
                .WithAddHeadersToDownstream(hAndRs.AddHeadersToDownstream)
 | 
			
		||||
                .WithAddHeadersToUpstream(hAndRs.AddHeadersToUpstream)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            return reRoute;
 | 
			
		||||
 
 | 
			
		||||
@@ -22,11 +22,14 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        public HeaderTransformations Create(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var upstream = new List<HeaderFindAndReplace>();
 | 
			
		||||
            var addHeadersToUpstream = new List<AddHeader>();
 | 
			
		||||
 | 
			
		||||
            foreach(var input in fileReRoute.UpstreamHeaderTransform)
 | 
			
		||||
            {
 | 
			
		||||
                if (input.Value.Contains(","))
 | 
			
		||||
                {
 | 
			
		||||
                    var hAndr = Map(input);
 | 
			
		||||
                if(!hAndr.IsError)
 | 
			
		||||
                    if (!hAndr.IsError)
 | 
			
		||||
                    {
 | 
			
		||||
                        upstream.Add(hAndr.Data);
 | 
			
		||||
                    }
 | 
			
		||||
@@ -35,6 +38,11 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                        _logger.LogWarning($"Unable to add UpstreamHeaderTransform {input.Key}: {input.Value}");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    addHeadersToUpstream.Add(new AddHeader(input.Key, input.Value));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var downstream = new List<HeaderFindAndReplace>();
 | 
			
		||||
            var addHeadersToDownstream = new List<AddHeader>();
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,11 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        public HeaderTransformations(
 | 
			
		||||
            List<HeaderFindAndReplace> upstream, 
 | 
			
		||||
            List<HeaderFindAndReplace> downstream,
 | 
			
		||||
            List<AddHeader> addHeader)
 | 
			
		||||
            List<AddHeader> addHeaderToDownstream,
 | 
			
		||||
            List<AddHeader> addHeaderToUpstream)
 | 
			
		||||
        {
 | 
			
		||||
            AddHeadersToDownstream = addHeader;
 | 
			
		||||
            AddHeadersToDownstream = addHeaderToDownstream;
 | 
			
		||||
            AddHeadersToUpstream = addHeaderToUpstream;
 | 
			
		||||
            Upstream = upstream;
 | 
			
		||||
            Downstream = downstream;
 | 
			
		||||
        }
 | 
			
		||||
@@ -19,5 +21,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        public List<HeaderFindAndReplace> Downstream { get; }
 | 
			
		||||
 | 
			
		||||
        public List<AddHeader> AddHeadersToDownstream { get; }
 | 
			
		||||
        public List<AddHeader> AddHeadersToUpstream { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,8 @@ namespace Ocelot.Configuration
 | 
			
		||||
            PathTemplate downstreamPathTemplate, 
 | 
			
		||||
            string reRouteKey,
 | 
			
		||||
            List<string> delegatingHandlers,
 | 
			
		||||
            List<AddHeader> addHeadersToDownstream)
 | 
			
		||||
            List<AddHeader> addHeadersToDownstream,
 | 
			
		||||
            List<AddHeader> addHeadersToUpstream)
 | 
			
		||||
        {
 | 
			
		||||
            AddHeadersToDownstream = addHeadersToDownstream;
 | 
			
		||||
            DelegatingHandlers = delegatingHandlers;
 | 
			
		||||
@@ -64,6 +65,7 @@ namespace Ocelot.Configuration
 | 
			
		||||
            AuthenticationOptions = authenticationOptions;
 | 
			
		||||
            DownstreamPathTemplate = downstreamPathTemplate;
 | 
			
		||||
            ReRouteKey = reRouteKey;
 | 
			
		||||
            AddHeadersToUpstream = addHeadersToUpstream;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string Key { get; private set; }
 | 
			
		||||
@@ -94,5 +96,6 @@ namespace Ocelot.Configuration
 | 
			
		||||
        public string ReRouteKey { get; private set; }
 | 
			
		||||
        public List<string> DelegatingHandlers {get;private set;}
 | 
			
		||||
        public List<AddHeader> AddHeadersToDownstream {get;private set;}
 | 
			
		||||
        public List<AddHeader> AddHeadersToUpstream { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Infrastructure.Claims.Parser;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Ocelot.Configuration.Creator;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
 | 
			
		||||
@@ -41,5 +42,19 @@ namespace Ocelot.Headers
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Ocelot.Headers
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Headers
 | 
			
		||||
{
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
@@ -12,5 +14,6 @@
 | 
			
		||||
    public interface IAddHeadersToRequest
 | 
			
		||||
    {
 | 
			
		||||
        Response SetHeadersOnDownstreamRequest(List<ClaimToThing> claimsToThings, IEnumerable<System.Security.Claims.Claim> claims, DownstreamRequest downstreamRequest);
 | 
			
		||||
        void SetHeadersOnDownstreamRequest(IEnumerable<AddHeader> headers, HttpContext context);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,16 +9,19 @@ namespace Ocelot.Headers.Middleware
 | 
			
		||||
        private readonly OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly IHttpContextRequestHeaderReplacer _preReplacer;
 | 
			
		||||
        private readonly IHttpResponseHeaderReplacer _postReplacer;
 | 
			
		||||
        private readonly IAddHeadersToResponse _addHeaders;
 | 
			
		||||
        private readonly IAddHeadersToResponse _addHeadersToResponse;
 | 
			
		||||
        private readonly IAddHeadersToRequest _addHeadersToRequest;
 | 
			
		||||
 | 
			
		||||
        public HttpHeadersTransformationMiddleware(OcelotRequestDelegate next,
 | 
			
		||||
            IOcelotLoggerFactory loggerFactory,
 | 
			
		||||
            IHttpContextRequestHeaderReplacer preReplacer,
 | 
			
		||||
            IHttpResponseHeaderReplacer postReplacer,
 | 
			
		||||
            IAddHeadersToResponse addHeaders) 
 | 
			
		||||
            IAddHeadersToResponse addHeadersToResponse,
 | 
			
		||||
            IAddHeadersToRequest addHeadersToRequest) 
 | 
			
		||||
                :base(loggerFactory.CreateLogger<HttpHeadersTransformationMiddleware>())
 | 
			
		||||
        {
 | 
			
		||||
            _addHeaders = addHeaders;
 | 
			
		||||
            _addHeadersToResponse = addHeadersToResponse;
 | 
			
		||||
            _addHeadersToRequest = addHeadersToRequest;
 | 
			
		||||
            _next = next;
 | 
			
		||||
            _postReplacer = postReplacer;
 | 
			
		||||
            _preReplacer = preReplacer;
 | 
			
		||||
@@ -31,13 +34,15 @@ namespace Ocelot.Headers.Middleware
 | 
			
		||||
            //todo - this should be on httprequestmessage not httpcontext?
 | 
			
		||||
            _preReplacer.Replace(context.HttpContext, preFAndRs);
 | 
			
		||||
 | 
			
		||||
            _addHeadersToRequest.SetHeadersOnDownstreamRequest(context.DownstreamReRoute.AddHeadersToUpstream, context.HttpContext);
 | 
			
		||||
 | 
			
		||||
            await _next.Invoke(context);
 | 
			
		||||
 | 
			
		||||
            var postFAndRs = context.DownstreamReRoute.DownstreamHeadersFindAndReplace;
 | 
			
		||||
 | 
			
		||||
            _postReplacer.Replace(context.DownstreamResponse, postFAndRs, context.DownstreamRequest);
 | 
			
		||||
 | 
			
		||||
            _addHeaders.Add(context.DownstreamReRoute.AddHeadersToDownstream, context.DownstreamResponse);
 | 
			
		||||
            _addHeadersToResponse.Add(context.DownstreamReRoute.AddHeadersToDownstream, context.DownstreamResponse);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -819,6 +819,7 @@
 | 
			
		||||
                result.DownstreamReRoute[0].RequestIdKey.ShouldBe(expected.DownstreamReRoute[0].RequestIdKey);   
 | 
			
		||||
                result.DownstreamReRoute[0].DelegatingHandlers.ShouldBe(expected.DownstreamReRoute[0].DelegatingHandlers);      
 | 
			
		||||
                result.DownstreamReRoute[0].AddHeadersToDownstream.ShouldBe(expected.DownstreamReRoute[0].AddHeadersToDownstream);           
 | 
			
		||||
                result.DownstreamReRoute[0].AddHeadersToUpstream.ShouldBe(expected.DownstreamReRoute[0].AddHeadersToUpstream, "AddHeadersToUpstream should be set");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -901,7 +902,7 @@
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,13 +12,17 @@ using Ocelot.Configuration.Repository;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
{
 | 
			
		||||
    public class FileConfigurationRepositoryTests
 | 
			
		||||
    public class FileConfigurationRepositoryTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHostingEnvironment> _hostingEnvironment = new Mock<IHostingEnvironment>();
 | 
			
		||||
        private IFileConfigurationRepository _repo;
 | 
			
		||||
        private FileConfiguration _result;
 | 
			
		||||
        private FileConfiguration _fileConfiguration;
 | 
			
		||||
        private string _environmentName = "DEV";
 | 
			
		||||
        
 | 
			
		||||
        // This is a bit dirty and it is dev.dev so that the configuration tests
 | 
			
		||||
        // cant pick it up if they run in parralel..sigh these are not really unit 
 | 
			
		||||
        // tests but whatever...
 | 
			
		||||
        private string _environmentName = "DEV.DEV";
 | 
			
		||||
 | 
			
		||||
        public FileConfigurationRepositoryTests()
 | 
			
		||||
        {
 | 
			
		||||
@@ -221,5 +225,10 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                ReRoutes = reRoutes
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            File.Delete($"./ocelot.{_environmentName}.json");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -149,7 +149,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                .Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_trace_id_header()
 | 
			
		||||
        {
 | 
			
		||||
@@ -166,7 +165,45 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            this.Given(x => GivenTheReRoute(reRoute))
 | 
			
		||||
                .And(x => GivenTheBaseUrlIs("http://ocelot.com/"))
 | 
			
		||||
                .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();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -180,12 +217,18 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            _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].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)
 | 
			
		||||
        {
 | 
			
		||||
            _result.Downstream.Count.ShouldBe(downstream.Count);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
{
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using Newtonsoft.Json;
 | 
			
		||||
@@ -17,7 +18,7 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
        private string _result;
 | 
			
		||||
        private IConfigurationRoot _configRoot;
 | 
			
		||||
        private FileConfiguration _globalConfig;
 | 
			
		||||
        private FileConfiguration _reRoute;
 | 
			
		||||
        private FileConfiguration _reRouteA;
 | 
			
		||||
        private FileConfiguration _reRouteB;
 | 
			
		||||
        private FileConfiguration _aggregate;
 | 
			
		||||
 | 
			
		||||
@@ -64,7 +65,7 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _reRoute = new FileConfiguration
 | 
			
		||||
            _reRouteA = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
@@ -160,17 +161,10 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var globalJson = JsonConvert.SerializeObject(_globalConfig);
 | 
			
		||||
            File.WriteAllText("ocelot.global.json", globalJson);
 | 
			
		||||
 | 
			
		||||
            var reRouteJson = JsonConvert.SerializeObject(_reRoute);
 | 
			
		||||
            File.WriteAllText("ocelot.reRoutes.json", reRouteJson);
 | 
			
		||||
 | 
			
		||||
            var reRouteJsonB = JsonConvert.SerializeObject(_reRouteB);
 | 
			
		||||
            File.WriteAllText("ocelot.reRoutesB.json", reRouteJsonB);
 | 
			
		||||
 | 
			
		||||
            var aggregates = JsonConvert.SerializeObject(_aggregate);
 | 
			
		||||
            File.WriteAllText("ocelot.aggregates.json", aggregates);
 | 
			
		||||
            File.WriteAllText("ocelot.global.json", JsonConvert.SerializeObject(_globalConfig));
 | 
			
		||||
            File.WriteAllText("ocelot.reRoutesA.json", JsonConvert.SerializeObject(_reRouteA));
 | 
			
		||||
            File.WriteAllText("ocelot.reRoutesB.json", JsonConvert.SerializeObject(_reRouteB));
 | 
			
		||||
            File.WriteAllText("ocelot.aggregates.json", JsonConvert.SerializeObject(_aggregate));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAddOcelotConfiguration()
 | 
			
		||||
@@ -195,21 +189,21 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
            fc.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Port);
 | 
			
		||||
            fc.GlobalConfiguration.ServiceDiscoveryProvider.Type.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Type);
 | 
			
		||||
 | 
			
		||||
            fc.ReRoutes.Count.ShouldBe(_reRoute.ReRoutes.Count + _reRouteB.ReRoutes.Count);
 | 
			
		||||
            fc.ReRoutes.Count.ShouldBe(_reRouteA.ReRoutes.Count + _reRouteB.ReRoutes.Count);
 | 
			
		||||
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.DownstreamPathTemplate == _reRoute.ReRoutes[0].DownstreamPathTemplate);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.DownstreamPathTemplate == _reRouteA.ReRoutes[0].DownstreamPathTemplate);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.DownstreamPathTemplate == _reRouteB.ReRoutes[0].DownstreamPathTemplate);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.DownstreamPathTemplate == _reRouteB.ReRoutes[1].DownstreamPathTemplate);
 | 
			
		||||
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.DownstreamScheme == _reRoute.ReRoutes[0].DownstreamScheme);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.DownstreamScheme == _reRouteA.ReRoutes[0].DownstreamScheme);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.DownstreamScheme == _reRouteB.ReRoutes[0].DownstreamScheme);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.DownstreamScheme == _reRouteB.ReRoutes[1].DownstreamScheme);
 | 
			
		||||
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.Key == _reRoute.ReRoutes[0].Key);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.Key == _reRouteA.ReRoutes[0].Key);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.Key == _reRouteB.ReRoutes[0].Key);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.Key == _reRouteB.ReRoutes[1].Key);
 | 
			
		||||
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.UpstreamHost == _reRoute.ReRoutes[0].UpstreamHost);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.UpstreamHost == _reRouteA.ReRoutes[0].UpstreamHost);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.UpstreamHost == _reRouteB.ReRoutes[0].UpstreamHost);
 | 
			
		||||
            fc.ReRoutes.ShouldContain(x => x.UpstreamHost == _reRouteB.ReRoutes[1].UpstreamHost);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ using Ocelot.Request.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Headers
 | 
			
		||||
{
 | 
			
		||||
    public class AddHeadersToRequestTests
 | 
			
		||||
    public class AddHeadersToRequestClaimToThingTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly AddHeadersToRequest _addHeadersToRequest;
 | 
			
		||||
        private readonly Mock<IClaimsParser> _parser;
 | 
			
		||||
@@ -25,7 +25,7 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
        private Response _result;
 | 
			
		||||
        private Response<string> _claimValue;
 | 
			
		||||
 | 
			
		||||
        public AddHeadersToRequestTests()
 | 
			
		||||
        public AddHeadersToRequestClaimToThingTests()
 | 
			
		||||
        {
 | 
			
		||||
            _parser = new Mock<IClaimsParser>();
 | 
			
		||||
            _addHeadersToRequest = new AddHeadersToRequest(_parser.Object);
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -27,7 +27,8 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
        private readonly HttpHeadersTransformationMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly Mock<IAddHeadersToResponse> _addHeaders;
 | 
			
		||||
        private readonly Mock<IAddHeadersToResponse> _addHeadersToResponse;
 | 
			
		||||
        private readonly Mock<IAddHeadersToRequest> _addHeadersToRequest;
 | 
			
		||||
 | 
			
		||||
        public HttpHeadersTransformationMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
@@ -38,8 +39,11 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _addHeaders = new Mock<IAddHeadersToResponse>();
 | 
			
		||||
            _middleware = new HttpHeadersTransformationMiddleware(_next, _loggerFactory.Object, _preReplacer.Object, _postReplacer.Object, _addHeaders.Object);
 | 
			
		||||
            _addHeadersToResponse = new Mock<IAddHeadersToResponse>();
 | 
			
		||||
            _addHeadersToRequest = new Mock<IAddHeadersToRequest>();
 | 
			
		||||
            _middleware = new HttpHeadersTransformationMiddleware(
 | 
			
		||||
                _next, _loggerFactory.Object, _preReplacer.Object,
 | 
			
		||||
                _postReplacer.Object, _addHeadersToResponse.Object, _addHeadersToRequest.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -51,17 +55,24 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
                .And(x => GivenTheHttpResponseMessageIs())
 | 
			
		||||
                .When(x => WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly())
 | 
			
		||||
                .Then(x => ThenAddHeadersToRequestIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenAddHeadersIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenAddHeadersToResponseIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAddHeadersIsCalledCorrectly()
 | 
			
		||||
        private void ThenAddHeadersToResponseIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _addHeaders
 | 
			
		||||
            _addHeadersToResponse
 | 
			
		||||
                .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()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user