mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 20:10:50 +08:00 
			
		
		
		
	* #280 can now add response headers inc trace id, now need to consolidate the header place holder stuff * #280 changed port for linux tests * #280 lots of hacking around to handle errors and consolidate placeholders into one class
This commit is contained in:
		@@ -3,8 +3,32 @@ 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Syntax
 | 
					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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you want to add a header to your downstream response please add the following to a ReRoute in configuration.json..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    "DownstreamHeaderTransform": {
 | 
				
			||||||
 | 
					        "Uncle": "Bob"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the example above a header with the key Uncle and value Bob would be returned by Ocelot when requesting the specific ReRoute.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you want to return the Butterfly APM trace id then do something like the following..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    "DownstreamHeaderTransform": {
 | 
				
			||||||
 | 
					        "AnyKey": "{TraceId}"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Find and Replace
 | 
				
			||||||
 | 
					^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In order to transform a header first we specify the header key and then the type of transform we want e.g.
 | 
					In order to transform a header first we specify the header key and then the type of transform we want e.g.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -43,6 +67,7 @@ Ocelot allows placeholders that can be used in header transformation.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{BaseUrl} - This will use Ocelot's base url e.g. http://localhost:5000 as its value.
 | 
					{BaseUrl} - This will use Ocelot's base url e.g. http://localhost:5000 as its value.
 | 
				
			||||||
{DownstreamBaseUrl} - This will use the downstream services base url e.g. http://localhost:5000 as its value. This only works for DownstreamHeaderTransform at the moment.
 | 
					{DownstreamBaseUrl} - This will use the downstream services base url e.g. http://localhost:5000 as its value. This only works for DownstreamHeaderTransform at the moment.
 | 
				
			||||||
 | 
					{TraceId} - This will use the Butterfly APM Trace Id. This only works for DownstreamHeaderTransform at the moment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Handling 302 Redirects
 | 
					Handling 302 Redirects
 | 
				
			||||||
^^^^^^^^^^^^^^^^^^^^^^
 | 
					^^^^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ using System.Collections.Generic;
 | 
				
			|||||||
using System.Net.Http;
 | 
					using System.Net.Http;
 | 
				
			||||||
using Ocelot.Values;
 | 
					using Ocelot.Values;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.Creator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Configuration.Builder
 | 
					namespace Ocelot.Configuration.Builder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -37,11 +38,13 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
        private string _upstreamHost;
 | 
					        private string _upstreamHost;
 | 
				
			||||||
        private string _key;
 | 
					        private string _key;
 | 
				
			||||||
        private List<string> _delegatingHandlers;
 | 
					        private List<string> _delegatingHandlers;
 | 
				
			||||||
 | 
					        private List<AddHeader> _addHeadersToDownstream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamReRouteBuilder()
 | 
					        public DownstreamReRouteBuilder()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _downstreamAddresses = new List<DownstreamHostAndPort>();
 | 
					            _downstreamAddresses = new List<DownstreamHostAndPort>();
 | 
				
			||||||
            _delegatingHandlers = new List<string>();
 | 
					            _delegatingHandlers = new List<string>();
 | 
				
			||||||
 | 
					            _addHeadersToDownstream = new List<AddHeader>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamReRouteBuilder WithDownstreamAddresses(List<DownstreamHostAndPort> downstreamAddresses)
 | 
					        public DownstreamReRouteBuilder WithDownstreamAddresses(List<DownstreamHostAndPort> downstreamAddresses)
 | 
				
			||||||
@@ -224,6 +227,12 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DownstreamReRouteBuilder WithAddHeadersToDownstream(List<AddHeader> addHeadersToDownstream)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _addHeadersToDownstream = addHeadersToDownstream;
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamReRoute Build()
 | 
					        public DownstreamReRoute Build()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new DownstreamReRoute(
 | 
					            return new DownstreamReRoute(
 | 
				
			||||||
@@ -253,7 +262,8 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
                _authenticationOptions, 
 | 
					                _authenticationOptions, 
 | 
				
			||||||
                new PathTemplate(_downstreamPathTemplate),
 | 
					                new PathTemplate(_downstreamPathTemplate),
 | 
				
			||||||
                _reRouteKey,
 | 
					                _reRouteKey,
 | 
				
			||||||
                _delegatingHandlers);
 | 
					                _delegatingHandlers,
 | 
				
			||||||
 | 
					                _addHeadersToDownstream);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -213,6 +213,7 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
                .WithDownstreamHeaderFindAndReplace(hAndRs.Downstream)
 | 
					                .WithDownstreamHeaderFindAndReplace(hAndRs.Downstream)
 | 
				
			||||||
                .WithUpstreamHost(fileReRoute.UpstreamHost)
 | 
					                .WithUpstreamHost(fileReRoute.UpstreamHost)
 | 
				
			||||||
                .WithDelegatingHandlers(fileReRoute.DelegatingHandlers)
 | 
					                .WithDelegatingHandlers(fileReRoute.DelegatingHandlers)
 | 
				
			||||||
 | 
					                .WithAddHeadersToDownstream(hAndRs.AddHeadersToDownstream)
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return reRoute;
 | 
					            return reRoute;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,22 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using Ocelot.Configuration.File;
 | 
					using Ocelot.Configuration.File;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure;
 | 
				
			||||||
 | 
					using Ocelot.Logging;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Configuration.Creator
 | 
					namespace Ocelot.Configuration.Creator
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class HeaderFindAndReplaceCreator : IHeaderFindAndReplaceCreator
 | 
					    public class HeaderFindAndReplaceCreator : IHeaderFindAndReplaceCreator
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private IBaseUrlFinder _finder;
 | 
					        private IPlaceholders _placeholders;
 | 
				
			||||||
        private readonly Dictionary<string, Func<string>> _placeholders;
 | 
					        private IOcelotLogger _logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HeaderFindAndReplaceCreator(IBaseUrlFinder finder)
 | 
					        public HeaderFindAndReplaceCreator(IPlaceholders placeholders, IOcelotLoggerFactory factory)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _finder = finder;
 | 
					            _logger = factory.CreateLogger<HeaderFindAndReplaceCreator>();;
 | 
				
			||||||
            _placeholders = new Dictionary<string, Func<string>>();
 | 
					            _placeholders = placeholders;
 | 
				
			||||||
            _placeholders.Add("{BaseUrl}", () => _finder.Find());
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HeaderTransformations Create(FileReRoute fileReRoute)
 | 
					        public HeaderTransformations Create(FileReRoute fileReRoute)
 | 
				
			||||||
@@ -24,21 +26,43 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
            foreach(var input in fileReRoute.UpstreamHeaderTransform)
 | 
					            foreach(var input in fileReRoute.UpstreamHeaderTransform)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var hAndr = Map(input);
 | 
					                var hAndr = Map(input);
 | 
				
			||||||
                upstream.Add(hAndr);
 | 
					                if(!hAndr.IsError)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    upstream.Add(hAndr.Data);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _logger.LogError($"Unable to add UpstreamHeaderTransform {input.Key}: {input.Value}");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var downstream = new List<HeaderFindAndReplace>();
 | 
					            var downstream = new List<HeaderFindAndReplace>();
 | 
				
			||||||
 | 
					            var addHeadersToDownstream = new List<AddHeader>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            foreach(var input in fileReRoute.DownstreamHeaderTransform)
 | 
					            foreach(var input in fileReRoute.DownstreamHeaderTransform)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var hAndr = Map(input);
 | 
					                if(input.Value.Contains(","))
 | 
				
			||||||
                downstream.Add(hAndr);
 | 
					                {
 | 
				
			||||||
 | 
					                    var hAndr = Map(input);
 | 
				
			||||||
 | 
					                    if(!hAndr.IsError)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        downstream.Add(hAndr.Data);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        _logger.LogError($"Unable to add DownstreamHeaderTransform {input.Key}: {input.Value}");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    addHeadersToDownstream.Add(new AddHeader(input.Key, input.Value));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            return new HeaderTransformations(upstream, downstream);
 | 
					            return new HeaderTransformations(upstream, downstream, addHeadersToDownstream);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private HeaderFindAndReplace Map(KeyValuePair<string,string> input)
 | 
					        private Response<HeaderFindAndReplace> Map(KeyValuePair<string,string> input)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var findAndReplace = input.Value.Split(",");
 | 
					            var findAndReplace = input.Value.Split(",");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,16 +75,19 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
                
 | 
					                
 | 
				
			||||||
                var placeholder = replace.Substring(startOfPlaceholder, startOfPlaceholder + (endOfPlaceholder + 1));
 | 
					                var placeholder = replace.Substring(startOfPlaceholder, startOfPlaceholder + (endOfPlaceholder + 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if(_placeholders.ContainsKey(placeholder))
 | 
					                var value = _placeholders.Get(placeholder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(value.IsError)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    var value = _placeholders[placeholder].Invoke();
 | 
					                    return new ErrorResponse<HeaderFindAndReplace>(value.Errors);
 | 
				
			||||||
                    replace = replace.Replace(placeholder, value);
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                replace = replace.Replace(placeholder, value.Data);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var hAndr = new HeaderFindAndReplace(input.Key, findAndReplace[0], replace, 0);
 | 
					            var hAndr = new HeaderFindAndReplace(input.Key, findAndReplace[0], replace, 0);
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            return hAndr;
 | 
					            return new OkResponse<HeaderFindAndReplace>(hAndr);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,14 +4,31 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class HeaderTransformations
 | 
					    public class HeaderTransformations
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public HeaderTransformations(List<HeaderFindAndReplace> upstream, List<HeaderFindAndReplace> downstream)
 | 
					        public HeaderTransformations(
 | 
				
			||||||
 | 
					            List<HeaderFindAndReplace> upstream, 
 | 
				
			||||||
 | 
					            List<HeaderFindAndReplace> downstream,
 | 
				
			||||||
 | 
					            List<AddHeader> addHeader)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            AddHeadersToDownstream = addHeader;
 | 
				
			||||||
            Upstream = upstream;
 | 
					            Upstream = upstream;
 | 
				
			||||||
            Downstream = downstream;
 | 
					            Downstream = downstream;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public List<HeaderFindAndReplace> Upstream {get;private set;}
 | 
					        public List<HeaderFindAndReplace> Upstream { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public List<HeaderFindAndReplace> Downstream {get;private set;}
 | 
					        public List<HeaderFindAndReplace> Downstream { get; private set; }
 | 
				
			||||||
 | 
					        public List<AddHeader> AddHeadersToDownstream {get;private set;}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class AddHeader
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public AddHeader(string key, string value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Key = key;
 | 
				
			||||||
 | 
					            this.Value = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public string Key { get; private set; }
 | 
				
			||||||
 | 
					        public string Value { get; private set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.Creator;
 | 
				
			||||||
using Ocelot.Values;
 | 
					using Ocelot.Values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Configuration
 | 
					namespace Ocelot.Configuration
 | 
				
			||||||
@@ -32,8 +33,10 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
            AuthenticationOptions authenticationOptions, 
 | 
					            AuthenticationOptions authenticationOptions, 
 | 
				
			||||||
            PathTemplate downstreamPathTemplate, 
 | 
					            PathTemplate downstreamPathTemplate, 
 | 
				
			||||||
            string reRouteKey,
 | 
					            string reRouteKey,
 | 
				
			||||||
            List<string> delegatingHandlers)
 | 
					            List<string> delegatingHandlers,
 | 
				
			||||||
 | 
					            List<AddHeader> addHeadersToDownstream)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            AddHeadersToDownstream = addHeadersToDownstream;
 | 
				
			||||||
            DelegatingHandlers = delegatingHandlers;
 | 
					            DelegatingHandlers = delegatingHandlers;
 | 
				
			||||||
            Key = key;
 | 
					            Key = key;
 | 
				
			||||||
            UpstreamPathTemplate = upstreamPathTemplate;
 | 
					            UpstreamPathTemplate = upstreamPathTemplate;
 | 
				
			||||||
@@ -90,5 +93,6 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
        public PathTemplate DownstreamPathTemplate { get; private set; }
 | 
					        public PathTemplate DownstreamPathTemplate { get; private set; }
 | 
				
			||||||
        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;}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,6 +52,7 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
    using System.Linq;
 | 
					    using System.Linq;
 | 
				
			||||||
    using System.Net.Http;
 | 
					    using System.Net.Http;
 | 
				
			||||||
    using Butterfly.Client.AspNetCore;
 | 
					    using Butterfly.Client.AspNetCore;
 | 
				
			||||||
 | 
					    using Ocelot.Infrastructure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class OcelotBuilder : IOcelotBuilder
 | 
					    public class OcelotBuilder : IOcelotBuilder
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -149,6 +150,8 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
            // We add this here so that we can always inject something into the factory for IoC..
 | 
					            // We add this here so that we can always inject something into the factory for IoC..
 | 
				
			||||||
            _services.AddSingleton<IServiceTracer, FakeServiceTracer>();
 | 
					            _services.AddSingleton<IServiceTracer, FakeServiceTracer>();
 | 
				
			||||||
            _services.TryAddSingleton<IConsulPollerConfiguration, InMemoryConsulPollerConfiguration>();
 | 
					            _services.TryAddSingleton<IConsulPollerConfiguration, InMemoryConsulPollerConfiguration>();
 | 
				
			||||||
 | 
					            _services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
 | 
				
			||||||
 | 
					            _services.TryAddSingleton<IPlaceholders, Placeholders>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
 | 
					        public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@
 | 
				
			|||||||
        RateLimitOptionsError,
 | 
					        RateLimitOptionsError,
 | 
				
			||||||
        PathTemplateDoesntStartWithForwardSlash,
 | 
					        PathTemplateDoesntStartWithForwardSlash,
 | 
				
			||||||
        FileValidationFailedError,
 | 
					        FileValidationFailedError,
 | 
				
			||||||
        UnableToFindDelegatingHandlerProviderError
 | 
					        UnableToFindDelegatingHandlerProviderError,
 | 
				
			||||||
 | 
					        CouldNotFindPlaceholderError
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 Ocelot.Configuration.Creator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Headers
 | 
					namespace Ocelot.Headers
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								src/Ocelot/Headers/AddHeadersToResponse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/Ocelot/Headers/AddHeadersToResponse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					namespace Ocelot.Headers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using System;
 | 
				
			||||||
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
 | 
					    using System.Net.Http;
 | 
				
			||||||
 | 
					    using Ocelot.Configuration.Creator;
 | 
				
			||||||
 | 
					    using Ocelot.Infrastructure;
 | 
				
			||||||
 | 
					    using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
 | 
					    using Ocelot.Logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class AddHeadersToResponse : IAddHeadersToResponse
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private IPlaceholders _placeholders;
 | 
				
			||||||
 | 
					        private IOcelotLogger _logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public AddHeadersToResponse(IPlaceholders placeholders, IOcelotLoggerFactory factory)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _logger = factory.CreateLogger<AddHeadersToResponse>();
 | 
				
			||||||
 | 
					            _placeholders = placeholders;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public void Add(List<AddHeader> addHeaders, HttpResponseMessage response)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach(var add in addHeaders)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if(add.Value.StartsWith('{') && add.Value.EndsWith('}'))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var value = _placeholders.Get(add.Value);
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    if(value.IsError)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        _logger.LogError($"Unable to add header to response {add.Key}: {add.Value}");
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    response.Headers.TryAddWithoutValidation(add.Key, value.Data);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    response.Headers.TryAddWithoutValidation(add.Key, add.Value);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 | 
				
			|||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Net.Http;
 | 
					using System.Net.Http;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure;
 | 
				
			||||||
using Ocelot.Infrastructure.Extensions;
 | 
					using Ocelot.Infrastructure.Extensions;
 | 
				
			||||||
using Ocelot.Responses;
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -10,24 +11,14 @@ namespace Ocelot.Headers
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class HttpResponseHeaderReplacer : IHttpResponseHeaderReplacer
 | 
					    public class HttpResponseHeaderReplacer : IHttpResponseHeaderReplacer
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private Dictionary<string, Func<HttpRequestMessage, string>> _placeholders;
 | 
					        private IPlaceholders _placeholders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpResponseHeaderReplacer()
 | 
					        public HttpResponseHeaderReplacer(IPlaceholders placeholders)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _placeholders = new Dictionary<string, Func<HttpRequestMessage, string>>();
 | 
					            _placeholders = placeholders;
 | 
				
			||||||
            _placeholders.Add("{DownstreamBaseUrl}", x => {
 | 
					 | 
				
			||||||
                var downstreamUrl = $"{x.RequestUri.Scheme}://{x.RequestUri.Host}";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if(x.RequestUri.Port != 80 && x.RequestUri.Port != 443)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    downstreamUrl = $"{downstreamUrl}:{x.RequestUri.Port}";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return $"{downstreamUrl}/";
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public Response Replace(HttpResponseMessage response, List<HeaderFindAndReplace> fAndRs, HttpRequestMessage httpRequestMessage)
 | 
					        public Response Replace(HttpResponseMessage response, List<HeaderFindAndReplace> fAndRs, HttpRequestMessage request)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            foreach (var f in fAndRs)
 | 
					            foreach (var f in fAndRs)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -35,11 +26,13 @@ namespace Ocelot.Headers
 | 
				
			|||||||
                if(response.Headers.TryGetValues(f.Key, out var values))
 | 
					                if(response.Headers.TryGetValues(f.Key, out var values))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    //check to see if it is a placeholder in the find...
 | 
					                    //check to see if it is a placeholder in the find...
 | 
				
			||||||
                    if(_placeholders.TryGetValue(f.Find, out var replacePlaceholder))
 | 
					                    var placeholderValue = _placeholders.Get(f.Find, request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if(!placeholderValue.IsError)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        //if it is we need to get the value of the placeholder
 | 
					                        //if it is we need to get the value of the placeholder
 | 
				
			||||||
                        var find = replacePlaceholder(httpRequestMessage);
 | 
					                        //var find = replacePlaceholder(httpRequestMessage);
 | 
				
			||||||
                        var replaced = values.ToList()[f.Index].Replace(find, f.Replace.LastCharAsForwardSlash());
 | 
					                        var replaced = values.ToList()[f.Index].Replace(placeholderValue.Data, f.Replace.LastCharAsForwardSlash());
 | 
				
			||||||
                        response.Headers.Remove(f.Key);
 | 
					                        response.Headers.Remove(f.Key);
 | 
				
			||||||
                        response.Headers.Add(f.Key, replaced);
 | 
					                        response.Headers.Add(f.Key, replaced);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@
 | 
				
			|||||||
    using System.Net.Http;
 | 
					    using System.Net.Http;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    using Ocelot.Configuration;
 | 
					    using Ocelot.Configuration;
 | 
				
			||||||
 | 
					    using Ocelot.Configuration.Creator;
 | 
				
			||||||
 | 
					    using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
    using Ocelot.Responses;
 | 
					    using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public interface IAddHeadersToRequest
 | 
					    public interface IAddHeadersToRequest
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								src/Ocelot/Headers/IAddHeadersToResponse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Ocelot/Headers/IAddHeadersToResponse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					namespace Ocelot.Headers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
 | 
					    using System.Net.Http;
 | 
				
			||||||
 | 
					    using Ocelot.Configuration.Creator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public interface IAddHeadersToResponse
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        void Add(List<AddHeader> addHeaders, HttpResponseMessage response);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -13,12 +13,15 @@ namespace Ocelot.Headers.Middleware
 | 
				
			|||||||
        private readonly IOcelotLogger _logger;
 | 
					        private readonly IOcelotLogger _logger;
 | 
				
			||||||
        private readonly IHttpContextRequestHeaderReplacer _preReplacer;
 | 
					        private readonly IHttpContextRequestHeaderReplacer _preReplacer;
 | 
				
			||||||
        private readonly IHttpResponseHeaderReplacer _postReplacer;
 | 
					        private readonly IHttpResponseHeaderReplacer _postReplacer;
 | 
				
			||||||
 | 
					        private readonly IAddHeadersToResponse _addHeaders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpHeadersTransformationMiddleware(OcelotRequestDelegate next,
 | 
					        public HttpHeadersTransformationMiddleware(OcelotRequestDelegate next,
 | 
				
			||||||
            IOcelotLoggerFactory loggerFactory,
 | 
					            IOcelotLoggerFactory loggerFactory,
 | 
				
			||||||
            IHttpContextRequestHeaderReplacer preReplacer,
 | 
					            IHttpContextRequestHeaderReplacer preReplacer,
 | 
				
			||||||
            IHttpResponseHeaderReplacer postReplacer) 
 | 
					            IHttpResponseHeaderReplacer postReplacer,
 | 
				
			||||||
 | 
					            IAddHeadersToResponse addHeaders) 
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            _addHeaders = addHeaders;
 | 
				
			||||||
            _next = next;
 | 
					            _next = next;
 | 
				
			||||||
            _postReplacer = postReplacer;
 | 
					            _postReplacer = postReplacer;
 | 
				
			||||||
            _preReplacer = preReplacer;
 | 
					            _preReplacer = preReplacer;
 | 
				
			||||||
@@ -37,6 +40,8 @@ namespace Ocelot.Headers.Middleware
 | 
				
			|||||||
            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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								src/Ocelot/Infrastructure/CouldNotFindPlaceholderError.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Ocelot/Infrastructure/CouldNotFindPlaceholderError.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					using Ocelot.Errors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Infrastructure
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class CouldNotFindPlaceholderError : Error
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public CouldNotFindPlaceholderError(string placeholder) 
 | 
				
			||||||
 | 
					            : base($"Unable to find placeholder called {placeholder}", OcelotErrorCode.CouldNotFindPlaceholderError)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/Ocelot/Infrastructure/IPlaceholders.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Ocelot/Infrastructure/IPlaceholders.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Infrastructure
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IPlaceholders
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Response<string> Get(string key);
 | 
				
			||||||
 | 
					        Response<string> Get(string key, HttpRequestMessage request);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										70
									
								
								src/Ocelot/Infrastructure/Placeholders.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/Ocelot/Infrastructure/Placeholders.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Infrastructure
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class Placeholders : IPlaceholders
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private Dictionary<string, Func<Response<string>>> _placeholders;
 | 
				
			||||||
 | 
					        private Dictionary<string, Func<HttpRequestMessage, string>> _requestPlaceholders;
 | 
				
			||||||
 | 
					        private readonly IBaseUrlFinder _finder;
 | 
				
			||||||
 | 
					        private readonly IRequestScopedDataRepository _repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Placeholders(IBaseUrlFinder finder, IRequestScopedDataRepository repo)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _repo = repo;
 | 
				
			||||||
 | 
					            _finder = finder;
 | 
				
			||||||
 | 
					            _placeholders = new Dictionary<string, Func<Response<string>>>();
 | 
				
			||||||
 | 
					            _placeholders.Add("{BaseUrl}", () => new OkResponse<string>(_finder.Find()));
 | 
				
			||||||
 | 
					            _placeholders.Add("{TraceId}", () => {
 | 
				
			||||||
 | 
					                var traceId = _repo.Get<string>("TraceId");
 | 
				
			||||||
 | 
					                if(traceId.IsError)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return new ErrorResponse<string>(traceId.Errors);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return new OkResponse<string>(traceId.Data);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _requestPlaceholders = new Dictionary<string, Func<HttpRequestMessage, string>>();
 | 
				
			||||||
 | 
					            _requestPlaceholders.Add("{DownstreamBaseUrl}", x => {
 | 
				
			||||||
 | 
					                var downstreamUrl = $"{x.RequestUri.Scheme}://{x.RequestUri.Host}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(x.RequestUri.Port != 80 && x.RequestUri.Port != 443)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    downstreamUrl = $"{downstreamUrl}:{x.RequestUri.Port}";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return $"{downstreamUrl}/";
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Response<string> Get(string key)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(_placeholders.ContainsKey(key))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var response = _placeholders[key].Invoke();
 | 
				
			||||||
 | 
					                if(!response.IsError)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return new OkResponse<string>(response.Data);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return new ErrorResponse<string>(new CouldNotFindPlaceholderError(key));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Response<string> Get(string key, HttpRequestMessage request)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(_requestPlaceholders.ContainsKey(key))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new OkResponse<string>(_requestPlaceholders[key].Invoke(request));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return new ErrorResponse<string>(new CouldNotFindPlaceholderError(key));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -5,26 +5,37 @@ using System.Threading;
 | 
				
			|||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Butterfly.Client.Tracing;
 | 
					using Butterfly.Client.Tracing;
 | 
				
			||||||
using Butterfly.OpenTracing;
 | 
					using Butterfly.OpenTracing;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Requester
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class OcelotHttpTracingHandler : DelegatingHandler, ITracingHandler
 | 
					    public class OcelotHttpTracingHandler : DelegatingHandler, ITracingHandler
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IServiceTracer _tracer;
 | 
					        private readonly IServiceTracer _tracer;
 | 
				
			||||||
 | 
					        private readonly IRequestScopedDataRepository _repo;
 | 
				
			||||||
        private const string prefix_spanId = "ot-spanId";
 | 
					        private const string prefix_spanId = "ot-spanId";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public OcelotHttpTracingHandler(IServiceTracer tracer, HttpMessageHandler httpMessageHandler = null)
 | 
					        public OcelotHttpTracingHandler(
 | 
				
			||||||
 | 
					            IServiceTracer tracer, 
 | 
				
			||||||
 | 
					            IRequestScopedDataRepository repo,
 | 
				
			||||||
 | 
					            HttpMessageHandler httpMessageHandler = null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            _repo = repo;
 | 
				
			||||||
            _tracer = tracer ?? throw new ArgumentNullException(nameof(tracer));
 | 
					            _tracer = tracer ?? throw new ArgumentNullException(nameof(tracer));
 | 
				
			||||||
            InnerHandler = httpMessageHandler ?? new HttpClientHandler();
 | 
					            InnerHandler = httpMessageHandler ?? new HttpClientHandler();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
					        protected override Task<HttpResponseMessage> SendAsync(
 | 
				
			||||||
 | 
					            HttpRequestMessage request, 
 | 
				
			||||||
 | 
					            CancellationToken cancellationToken)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return _tracer.ChildTraceAsync($"httpclient {request.Method}", DateTimeOffset.UtcNow, span => TracingSendAsync(span, request, cancellationToken));
 | 
					            return _tracer.ChildTraceAsync($"httpclient {request.Method}", DateTimeOffset.UtcNow, span => TracingSendAsync(span, request, cancellationToken));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected virtual async Task<HttpResponseMessage> TracingSendAsync(ISpan span, HttpRequestMessage request, CancellationToken cancellationToken)
 | 
					        protected virtual async Task<HttpResponseMessage> TracingSendAsync(
 | 
				
			||||||
 | 
					            ISpan span, 
 | 
				
			||||||
 | 
					            HttpRequestMessage request, 
 | 
				
			||||||
 | 
					            CancellationToken cancellationToken)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            IEnumerable<string> traceIdVals = null;
 | 
					            IEnumerable<string> traceIdVals = null;
 | 
				
			||||||
            if (request.Headers.TryGetValues(prefix_spanId, out traceIdVals))
 | 
					            if (request.Headers.TryGetValues(prefix_spanId, out traceIdVals))
 | 
				
			||||||
@@ -33,6 +44,8 @@ namespace Ocelot.Requester
 | 
				
			|||||||
                request.Headers.TryAddWithoutValidation(prefix_spanId, span.SpanContext.SpanId);
 | 
					                request.Headers.TryAddWithoutValidation(prefix_spanId, span.SpanContext.SpanId);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _repo.Add("TraceId", span.SpanContext.TraceId);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            span.Tags.Client().Component("HttpClient")
 | 
					            span.Tags.Client().Component("HttpClient")
 | 
				
			||||||
                .HttpMethod(request.Method.Method)
 | 
					                .HttpMethod(request.Method.Method)
 | 
				
			||||||
                .HttpUrl(request.RequestUri.OriginalString)
 | 
					                .HttpUrl(request.RequestUri.OriginalString)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,25 @@
 | 
				
			|||||||
using Butterfly.Client.Tracing;
 | 
					using Butterfly.Client.Tracing;
 | 
				
			||||||
using Butterfly.OpenTracing;
 | 
					using Butterfly.OpenTracing;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Requester
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class TracingHandlerFactory : ITracingHandlerFactory
 | 
					    public class TracingHandlerFactory : ITracingHandlerFactory
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IServiceTracer _tracer;
 | 
					        private readonly IServiceTracer _tracer;
 | 
				
			||||||
 | 
					        private readonly IRequestScopedDataRepository _repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public TracingHandlerFactory(IServiceTracer tracer)
 | 
					        public TracingHandlerFactory(
 | 
				
			||||||
 | 
					            IServiceTracer tracer,
 | 
				
			||||||
 | 
					            IRequestScopedDataRepository repo)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            _repo = repo;
 | 
				
			||||||
            _tracer = tracer;
 | 
					            _tracer = tracer;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public ITracingHandler Get()
 | 
					        public ITracingHandler Get()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new OcelotHttpTracingHandler(_tracer);
 | 
					            return new OcelotHttpTracingHandler(_tracer, _repo);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,7 +70,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                                new FileHostAndPort
 | 
					                                new FileHostAndPort
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    Host = "localhost",
 | 
					                                    Host = "localhost",
 | 
				
			||||||
                                    Port = 51888,
 | 
					                                    Port = 51388,
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                            UpstreamPathTemplate = "/api002/values",
 | 
					                            UpstreamPathTemplate = "/api002/values",
 | 
				
			||||||
@@ -92,7 +92,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            var butterflyUrl = "http://localhost:9618";
 | 
					            var butterflyUrl = "http://localhost:9618";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenServiceOneIsRunning("http://localhost:51887", "/api/values", 200, "Hello from Laura", butterflyUrl))
 | 
					            this.Given(x => GivenServiceOneIsRunning("http://localhost:51887", "/api/values", 200, "Hello from Laura", butterflyUrl))
 | 
				
			||||||
                .And(x => GivenServiceTwoIsRunning("http://localhost:51888", "/api/values", 200, "Hello from Tom", butterflyUrl))
 | 
					                .And(x => GivenServiceTwoIsRunning("http://localhost:51388", "/api/values", 200, "Hello from Tom", butterflyUrl))
 | 
				
			||||||
                .And(x => GivenFakeButterfly(butterflyUrl))
 | 
					                .And(x => GivenFakeButterfly(butterflyUrl))
 | 
				
			||||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
                .And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
 | 
					                .And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
 | 
				
			||||||
@@ -109,6 +109,60 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            commandOnAllStateMachines.ShouldBeTrue();
 | 
					            commandOnAllStateMachines.ShouldBeTrue();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_tracing_header()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var configuration = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ReRoutes = new List<FileReRoute>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new FileReRoute
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            DownstreamPathTemplate = "/api/values",
 | 
				
			||||||
 | 
					                            DownstreamScheme = "http",
 | 
				
			||||||
 | 
					                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                new FileHostAndPort
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    Host = "localhost",
 | 
				
			||||||
 | 
					                                    Port = 51387,
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            UpstreamPathTemplate = "/api001/values",
 | 
				
			||||||
 | 
					                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
				
			||||||
 | 
					                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                UseTracing = true
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            QoSOptions = new FileQoSOptions
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                ExceptionsAllowedBeforeBreaking = 3,
 | 
				
			||||||
 | 
					                                DurationOfBreak = 10,
 | 
				
			||||||
 | 
					                                TimeoutValue = 5000
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            DownstreamHeaderTransform = new Dictionary<string, string>()
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                {"Trace-Id", "{TraceId}"},
 | 
				
			||||||
 | 
					                                {"Tom", "Laura"}
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var butterflyUrl = "http://localhost:9618";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenServiceOneIsRunning("http://localhost:51387", "/api/values", 200, "Hello from Laura", butterflyUrl))
 | 
				
			||||||
 | 
					                .And(x => GivenFakeButterfly(butterflyUrl))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
 | 
				
			||||||
 | 
					                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
 | 
				
			||||||
 | 
					                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
				
			||||||
 | 
					                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
				
			||||||
 | 
					                .And(x => _steps.ThenTheTraceHeaderIsSet("Trace-Id"))
 | 
				
			||||||
 | 
					                .And(x => _steps.ThenTheResponseHeaderIs("Tom", "Laura"))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void GivenServiceOneIsRunning(string baseUrl, string basePath, int statusCode, string responseBody, string butterflyUrl)
 | 
					        private void GivenServiceOneIsRunning(string baseUrl, string basePath, int statusCode, string responseBody, string butterflyUrl)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _serviceOneBuilder = new WebHostBuilder()
 | 
					            _serviceOneBuilder = new WebHostBuilder()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -318,6 +318,12 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            header.First().ShouldBe(value);
 | 
					            header.First().ShouldBe(value);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void ThenTheTraceHeaderIsSet(string key)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var header = _response.Headers.GetValues(key);
 | 
				
			||||||
 | 
					            header.First().ShouldNotBeNullOrEmpty();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void GivenOcelotIsRunningUsingJsonSerializedCache()
 | 
					        public void GivenOcelotIsRunningUsingJsonSerializedCache()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _webHostBuilder = new WebHostBuilder();
 | 
					            _webHostBuilder = new WebHostBuilder();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,10 +34,10 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
            _fileConfig = new FileConfiguration();
 | 
					            _fileConfig = new FileConfiguration();
 | 
				
			||||||
            _config = new Mock<IConsulPollerConfiguration>();
 | 
					            _config = new Mock<IConsulPollerConfiguration>();
 | 
				
			||||||
            _repo.Setup(x => x.Get()).ReturnsAsync(new OkResponse<FileConfiguration>(_fileConfig));
 | 
					            _repo.Setup(x => x.Get()).ReturnsAsync(new OkResponse<FileConfiguration>(_fileConfig));
 | 
				
			||||||
            _config.Setup(x => x.Delay).Returns(10);
 | 
					            _config.Setup(x => x.Delay).Returns(100);
 | 
				
			||||||
            _poller = new ConsulFileConfigurationPoller(_factory.Object, _repo.Object, _setter.Object, _config.Object);
 | 
					            _poller = new ConsulFileConfigurationPoller(_factory.Object, _repo.Object, _setter.Object, _config.Object);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        public void Dispose()
 | 
					        public void Dispose()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _poller.Dispose();
 | 
					            _poller.Dispose();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -826,7 +826,8 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
                result.DownstreamReRoute[0].ClaimsToHeaders.Count.ShouldBe(expected.DownstreamReRoute[0].ClaimsToHeaders.Count);
 | 
					                result.DownstreamReRoute[0].ClaimsToHeaders.Count.ShouldBe(expected.DownstreamReRoute[0].ClaimsToHeaders.Count);
 | 
				
			||||||
                result.DownstreamReRoute[0].ClaimsToQueries.Count.ShouldBe(expected.DownstreamReRoute[0].ClaimsToQueries.Count);
 | 
					                result.DownstreamReRoute[0].ClaimsToQueries.Count.ShouldBe(expected.DownstreamReRoute[0].ClaimsToQueries.Count);
 | 
				
			||||||
                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);           
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -909,7 +910,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>()));
 | 
					            _headerFindAndReplaceCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(new HeaderTransformations(new List<HeaderFindAndReplace>(), new List<HeaderFindAndReplace>(), new List<AddHeader>()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void GivenTheFollowingIsReturned(ServiceProviderConfiguration serviceProviderConfiguration)
 | 
					        private void GivenTheFollowingIsReturned(ServiceProviderConfiguration serviceProviderConfiguration)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,11 @@ using Ocelot.Configuration;
 | 
				
			|||||||
using Ocelot.Configuration.Builder;
 | 
					using Ocelot.Configuration.Builder;
 | 
				
			||||||
using Ocelot.Configuration.Creator;
 | 
					using Ocelot.Configuration.Creator;
 | 
				
			||||||
using Ocelot.Configuration.File;
 | 
					using Ocelot.Configuration.File;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure;
 | 
				
			||||||
 | 
					using Ocelot.Logging;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					using Ocelot.UnitTests.Responder;
 | 
				
			||||||
using Shouldly;
 | 
					using Shouldly;
 | 
				
			||||||
using TestStack.BDDfy;
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
using Xunit;
 | 
					using Xunit;
 | 
				
			||||||
@@ -17,12 +21,17 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
        private HeaderFindAndReplaceCreator _creator;
 | 
					        private HeaderFindAndReplaceCreator _creator;
 | 
				
			||||||
        private FileReRoute _reRoute;
 | 
					        private FileReRoute _reRoute;
 | 
				
			||||||
        private HeaderTransformations _result;
 | 
					        private HeaderTransformations _result;
 | 
				
			||||||
        private Mock<IBaseUrlFinder> _finder;
 | 
					        private Mock<IPlaceholders> _placeholders;
 | 
				
			||||||
 | 
					        private Mock<IOcelotLoggerFactory> _factory;
 | 
				
			||||||
 | 
					        private Mock<IOcelotLogger> _logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HeaderFindAndReplaceCreatorTests()
 | 
					        public HeaderFindAndReplaceCreatorTests()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _finder = new Mock<IBaseUrlFinder>();
 | 
					            _logger = new Mock<IOcelotLogger>();
 | 
				
			||||||
            _creator = new HeaderFindAndReplaceCreator(_finder.Object);
 | 
					            _factory = new Mock<IOcelotLoggerFactory>();
 | 
				
			||||||
 | 
					            _factory.Setup(x => x.CreateLogger<HeaderFindAndReplaceCreator>()).Returns(_logger.Object);
 | 
				
			||||||
 | 
					            _placeholders = new Mock<IPlaceholders>();
 | 
				
			||||||
 | 
					            _creator = new HeaderFindAndReplaceCreator(_placeholders.Object, _factory.Object);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
@@ -84,6 +93,40 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_log_errors_and_not_add_headers()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var reRoute = new FileReRoute
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                DownstreamHeaderTransform = new Dictionary<string, string>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    {"Location", "http://www.bbc.co.uk/, {BaseUrl}"},
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                UpstreamHeaderTransform = new Dictionary<string, string>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    {"Location", "http://www.bbc.co.uk/, {BaseUrl}"},
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var expected = new List<HeaderFindAndReplace>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheReRoute(reRoute))
 | 
				
			||||||
 | 
					                .And(x => GivenTheBaseUrlErrors())
 | 
				
			||||||
 | 
					                .When(x => WhenICreate())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheFollowingDownstreamIsReturned(expected))
 | 
				
			||||||
 | 
					                .And(x => ThenTheFollowingUpstreamIsReturned(expected))
 | 
				
			||||||
 | 
					                .And(x => ThenTheLoggerIsCalledCorrectly("Unable to add DownstreamHeaderTransform Location: http://www.bbc.co.uk/, {BaseUrl}"))
 | 
				
			||||||
 | 
					                .And(x => ThenTheLoggerIsCalledCorrectly("Unable to add UpstreamHeaderTransform Location: http://www.bbc.co.uk/, {BaseUrl}"))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheLoggerIsCalledCorrectly(string message)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _logger.Verify(x => x.LogError(message), Times.Once);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_use_base_url_partial_placeholder()
 | 
					        public void should_use_base_url_partial_placeholder()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -107,9 +150,41 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_add_trace_id_header()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var reRoute = new FileReRoute
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                 DownstreamHeaderTransform = new Dictionary<string, string>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    {"Trace-Id", "{TraceId}"},
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var expected = new AddHeader("Trace-Id", "{TraceId}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheReRoute(reRoute))
 | 
				
			||||||
 | 
					                .And(x => GivenTheBaseUrlIs("http://ocelot.com/"))
 | 
				
			||||||
 | 
					                .When(x => WhenICreate())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheFollowingAddHeaderIsReturned(expected))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void GivenTheBaseUrlIs(string baseUrl)
 | 
					        private void GivenTheBaseUrlIs(string baseUrl)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _finder.Setup(x => x.Find()).Returns(baseUrl);
 | 
					            _placeholders.Setup(x => x.Get(It.IsAny<string>())).Returns(new OkResponse<string>(baseUrl));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheBaseUrlErrors()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _placeholders.Setup(x => x.Get(It.IsAny<string>())).Returns(new ErrorResponse<string>(new AnyError()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheFollowingAddHeaderIsReturned(AddHeader addHeader)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result.AddHeadersToDownstream[0].Key.ShouldBe(addHeader.Key);
 | 
				
			||||||
 | 
					            _result.AddHeadersToDownstream[0].Value.ShouldBe(addHeader.Value);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheFollowingDownstreamIsReturned(List<HeaderFindAndReplace> downstream)
 | 
					        private void ThenTheFollowingDownstreamIsReturned(List<HeaderFindAndReplace> downstream)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										148
									
								
								test/Ocelot.UnitTests/Headers/AddHeadersToResponseTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								test/Ocelot.UnitTests/Headers/AddHeadersToResponseTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
				
			|||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Ocelot.Headers;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.Creator;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Moq;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure;
 | 
				
			||||||
 | 
					using Ocelot.UnitTests.Responder;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using Ocelot.Logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Headers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class AddHeadersToResponseTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private IAddHeadersToResponse _adder;
 | 
				
			||||||
 | 
					        private Mock<IPlaceholders> _placeholders;
 | 
				
			||||||
 | 
					        private HttpResponseMessage _response;
 | 
				
			||||||
 | 
					        private List<AddHeader> _addHeaders;
 | 
				
			||||||
 | 
					        private Mock<IOcelotLoggerFactory> _factory;
 | 
				
			||||||
 | 
					        private Mock<IOcelotLogger> _logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public AddHeadersToResponseTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _factory = new Mock<IOcelotLoggerFactory>();
 | 
				
			||||||
 | 
					            _logger = new Mock<IOcelotLogger>();
 | 
				
			||||||
 | 
					            _factory.Setup(x => x.CreateLogger<AddHeadersToResponse>()).Returns(_logger.Object);
 | 
				
			||||||
 | 
					            _placeholders = new Mock<IPlaceholders>();
 | 
				
			||||||
 | 
					            _adder = new AddHeadersToResponse(_placeholders.Object, _factory.Object);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_add_header()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var addHeaders = new List<AddHeader>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new AddHeader("Laura", "Tom")
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(_ => GivenAResponseMessage())
 | 
				
			||||||
 | 
					                .And(_ => GivenTheAddHeaders(addHeaders))
 | 
				
			||||||
 | 
					                .When(_ => WhenIAdd())
 | 
				
			||||||
 | 
					                .And(_ => ThenTheHeaderIsReturned("Laura", "Tom"))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_add_trace_id_placeholder()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var addHeaders = new List<AddHeader>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new AddHeader("Trace-Id", "{TraceId}")
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					             
 | 
				
			||||||
 | 
					             var traceId = "123";
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            this.Given(_ => GivenAResponseMessage())
 | 
				
			||||||
 | 
					                .And(_ => GivenTheTraceIdIs(traceId))
 | 
				
			||||||
 | 
					                .And(_ => GivenTheAddHeaders(addHeaders))
 | 
				
			||||||
 | 
					                .When(_ => WhenIAdd())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheHeaderIsReturned("Trace-Id", traceId))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_add_trace_id_placeholder_and_normal()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var addHeaders = new List<AddHeader>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new AddHeader("Trace-Id", "{TraceId}"),
 | 
				
			||||||
 | 
					                new AddHeader("Tom", "Laura")
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var traceId = "123";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(_ => GivenAResponseMessage())
 | 
				
			||||||
 | 
					                .And(_ => GivenTheTraceIdIs(traceId))
 | 
				
			||||||
 | 
					                .And(_ => GivenTheAddHeaders(addHeaders))
 | 
				
			||||||
 | 
					                .When(_ => WhenIAdd())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheHeaderIsReturned("Trace-Id", traceId))
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheHeaderIsReturned("Tom", "Laura"))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_do_nothing_and_log_error()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var addHeaders = new List<AddHeader>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new AddHeader("Trace-Id", "{TraceId}")
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					             
 | 
				
			||||||
 | 
					            this.Given(_ => GivenAResponseMessage())
 | 
				
			||||||
 | 
					                .And(_ => GivenTheTraceIdErrors())
 | 
				
			||||||
 | 
					                .And(_ => GivenTheAddHeaders(addHeaders))
 | 
				
			||||||
 | 
					                .When(_ => WhenIAdd())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheHeaderIsNotAdded("Trace-Id"))
 | 
				
			||||||
 | 
					                .And(_ => ThenTheErrorIsLogged())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheErrorIsLogged()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _logger.Verify(x => x.LogError("Unable to add header to response Trace-Id: {TraceId}"), Times.Once);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheHeaderIsNotAdded(string key)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _response.Headers.TryGetValues(key, out var values).ShouldBeFalse();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheTraceIdIs(string traceId)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _placeholders.Setup(x => x.Get("{TraceId}")).Returns(new OkResponse<string>(traceId));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheTraceIdErrors()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _placeholders.Setup(x => x.Get("{TraceId}")).Returns(new ErrorResponse<string>(new AnyError()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheHeaderIsReturned(string key, string value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var values = _response.Headers.GetValues(key);
 | 
				
			||||||
 | 
					            values.First().ShouldBe(value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIAdd()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _adder.Add(_addHeaders, _response);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenAResponseMessage()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _response = new HttpResponseMessage();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheAddHeaders(List<AddHeader> addHeaders)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _addHeaders = addHeaders;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -26,6 +26,7 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
        private HttpHeadersTransformationMiddleware _middleware;
 | 
					        private HttpHeadersTransformationMiddleware _middleware;
 | 
				
			||||||
        private DownstreamContext _downstreamContext;
 | 
					        private DownstreamContext _downstreamContext;
 | 
				
			||||||
        private OcelotRequestDelegate _next;
 | 
					        private OcelotRequestDelegate _next;
 | 
				
			||||||
 | 
					        private Mock<IAddHeadersToResponse> _addHeaders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpHeadersTransformationMiddlewareTests()
 | 
					        public HttpHeadersTransformationMiddlewareTests()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -36,7 +37,8 @@ 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;
 | 
				
			||||||
            _middleware = new HttpHeadersTransformationMiddleware(_next, _loggerFactory.Object, _preReplacer.Object, _postReplacer.Object);
 | 
					            _addHeaders = new Mock<IAddHeadersToResponse>();
 | 
				
			||||||
 | 
					            _middleware = new HttpHeadersTransformationMiddleware(_next, _loggerFactory.Object, _preReplacer.Object, _postReplacer.Object, _addHeaders.Object);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
@@ -49,9 +51,16 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
                .When(x => WhenICallTheMiddleware())
 | 
					                .When(x => WhenICallTheMiddleware())
 | 
				
			||||||
                .Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly())
 | 
					                .Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly())
 | 
				
			||||||
                .And(x => ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly())
 | 
					                .And(x => ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly())
 | 
				
			||||||
 | 
					                .And(x => ThenAddHeadersIsCalledCorrectly())
 | 
				
			||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenAddHeadersIsCalledCorrectly()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _addHeaders
 | 
				
			||||||
 | 
					                .Verify(x => x.Add(_downstreamContext.DownstreamReRoute.AddHeadersToDownstream, _downstreamContext.DownstreamResponse), Times.Once);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void WhenICallTheMiddleware()
 | 
					        private void WhenICallTheMiddleware()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
					            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,20 +7,30 @@ using Ocelot.Configuration;
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using Ocelot.Responses;
 | 
					using Ocelot.Responses;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Moq;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure;
 | 
				
			||||||
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.UnitTests.Headers
 | 
					namespace Ocelot.UnitTests.Headers
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class HttpResponseHeaderReplacerTests
 | 
					    public class HttpResponseHeaderReplacerTests
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private HttpResponseMessage _response;
 | 
					        private HttpResponseMessage _response;
 | 
				
			||||||
 | 
					        private Placeholders _placeholders;
 | 
				
			||||||
        private HttpResponseHeaderReplacer _replacer;
 | 
					        private HttpResponseHeaderReplacer _replacer;
 | 
				
			||||||
        private List<HeaderFindAndReplace> _headerFindAndReplaces;
 | 
					        private List<HeaderFindAndReplace> _headerFindAndReplaces;
 | 
				
			||||||
        private Response _result;
 | 
					        private Response _result;
 | 
				
			||||||
        private HttpRequestMessage _request;
 | 
					        private HttpRequestMessage _request;
 | 
				
			||||||
 | 
					        private Mock<IBaseUrlFinder> _finder;
 | 
				
			||||||
 | 
					        private Mock<IRequestScopedDataRepository> _repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpResponseHeaderReplacerTests()
 | 
					        public HttpResponseHeaderReplacerTests()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _replacer = new HttpResponseHeaderReplacer();
 | 
					            _repo = new Mock<IRequestScopedDataRepository>();
 | 
				
			||||||
 | 
					            _finder = new Mock<IBaseUrlFinder>();
 | 
				
			||||||
 | 
					            _placeholders = new Placeholders(_finder.Object, _repo.Object);
 | 
				
			||||||
 | 
					            _replacer = new HttpResponseHeaderReplacer(_placeholders);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										79
									
								
								test/Ocelot.UnitTests/Infrastructure/PlaceholdersTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								test/Ocelot.UnitTests/Infrastructure/PlaceholdersTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using Moq;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Infrastructure
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class PlaceholdersTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private IPlaceholders _placeholders;
 | 
				
			||||||
 | 
					        private Mock<IBaseUrlFinder> _finder;
 | 
				
			||||||
 | 
					        private Mock<IRequestScopedDataRepository> _repo;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public PlaceholdersTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _repo = new Mock<IRequestScopedDataRepository>();
 | 
				
			||||||
 | 
					            _finder = new Mock<IBaseUrlFinder>();
 | 
				
			||||||
 | 
					            _placeholders = new Placeholders(_finder.Object, _repo.Object);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_base_url()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var baseUrl = "http://www.bbc.co.uk";
 | 
				
			||||||
 | 
					            _finder.Setup(x => x.Find()).Returns(baseUrl);
 | 
				
			||||||
 | 
					            var result = _placeholders.Get("{BaseUrl}");
 | 
				
			||||||
 | 
					            result.Data.ShouldBe(baseUrl);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_key_does_not_exist()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var result = _placeholders.Get("{Test}");
 | 
				
			||||||
 | 
					            result.IsError.ShouldBeTrue();
 | 
				
			||||||
 | 
					            result.Errors[0].Message.ShouldBe("Unable to find placeholder called {Test}");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_downstream_base_url_when_port_is_not_80_or_443()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var request = new HttpRequestMessage();
 | 
				
			||||||
 | 
					            request.RequestUri = new Uri("http://www.bbc.co.uk");
 | 
				
			||||||
 | 
					            var result = _placeholders.Get("{DownstreamBaseUrl}", request);
 | 
				
			||||||
 | 
					            result.Data.ShouldBe("http://www.bbc.co.uk/");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_downstream_base_url_when_port_is_80_or_443()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					              var request = new HttpRequestMessage();
 | 
				
			||||||
 | 
					            request.RequestUri = new Uri("http://www.bbc.co.uk:123");
 | 
				
			||||||
 | 
					            var result = _placeholders.Get("{DownstreamBaseUrl}", request);
 | 
				
			||||||
 | 
					            result.Data.ShouldBe("http://www.bbc.co.uk:123/");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_key_does_not_exist_for_http_request_message()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var result = _placeholders.Get("{Test}", new System.Net.Http.HttpRequestMessage());
 | 
				
			||||||
 | 
					            result.IsError.ShouldBeTrue();
 | 
				
			||||||
 | 
					            result.Errors[0].Message.ShouldBe("Unable to find placeholder called {Test}");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_trace_id()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var traceId = "123";
 | 
				
			||||||
 | 
					            _repo.Setup(x => x.Get<string>("TraceId")).Returns(new OkResponse<string>(traceId));
 | 
				
			||||||
 | 
					            var result = _placeholders.Get("{TraceId}");
 | 
				
			||||||
 | 
					            result.Data.ShouldBe(traceId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using Butterfly.Client.Tracing;
 | 
					using Butterfly.Client.Tracing;
 | 
				
			||||||
using Moq;
 | 
					using Moq;
 | 
				
			||||||
 | 
					using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
using Ocelot.Requester;
 | 
					using Ocelot.Requester;
 | 
				
			||||||
using Shouldly;
 | 
					using Shouldly;
 | 
				
			||||||
using Xunit;
 | 
					using Xunit;
 | 
				
			||||||
@@ -10,11 +11,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        private TracingHandlerFactory _factory;
 | 
					        private TracingHandlerFactory _factory;
 | 
				
			||||||
        private Mock<IServiceTracer> _tracer;
 | 
					        private Mock<IServiceTracer> _tracer;
 | 
				
			||||||
 | 
					        private Mock<IRequestScopedDataRepository> _repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public TracingHandlerFactoryTests()
 | 
					        public TracingHandlerFactoryTests()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _tracer = new Mock<IServiceTracer>();
 | 
					            _tracer = new Mock<IServiceTracer>();
 | 
				
			||||||
            _factory = new TracingHandlerFactory(_tracer.Object);
 | 
					            _repo = new Mock<IRequestScopedDataRepository>();
 | 
				
			||||||
 | 
					            _factory = new TracingHandlerFactory(_tracer.Object, _repo.Object);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,7 +120,7 @@ namespace Ocelot.UnitTests.Responder
 | 
				
			|||||||
            // If this test fails then it's because the number of error codes has changed.
 | 
					            // If this test fails then it's because the number of error codes has changed.
 | 
				
			||||||
            // You should make the appropriate changes to the test cases here to ensure
 | 
					            // You should make the appropriate changes to the test cases here to ensure
 | 
				
			||||||
            // they cover all the error codes, and then modify this assertion.
 | 
					            // they cover all the error codes, and then modify this assertion.
 | 
				
			||||||
            Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(33, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
 | 
					            Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(34, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
 | 
					        private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user