mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 18:40:50 +08:00 
			
		
		
		
	Feature/proxy reason phrase (#618)
* #599 started work to proxy reason phrase * #599 test for aggregator
This commit is contained in:
		@@ -9,14 +9,15 @@ namespace Ocelot.Cache
 | 
				
			|||||||
            HttpStatusCode statusCode,
 | 
					            HttpStatusCode statusCode,
 | 
				
			||||||
            Dictionary<string, IEnumerable<string>> headers,
 | 
					            Dictionary<string, IEnumerable<string>> headers,
 | 
				
			||||||
            string body,
 | 
					            string body,
 | 
				
			||||||
            Dictionary<string, IEnumerable<string>> contentHeaders
 | 
					            Dictionary<string, IEnumerable<string>> contentHeaders,
 | 
				
			||||||
 | 
					            string reasonPhrase
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            StatusCode = statusCode;
 | 
					            StatusCode = statusCode;
 | 
				
			||||||
            Headers = headers ?? new Dictionary<string, IEnumerable<string>>();
 | 
					            Headers = headers ?? new Dictionary<string, IEnumerable<string>>();
 | 
				
			||||||
            ContentHeaders = contentHeaders ?? new Dictionary<string, IEnumerable<string>>();
 | 
					            ContentHeaders = contentHeaders ?? new Dictionary<string, IEnumerable<string>>();
 | 
				
			||||||
            Body = body ?? "";
 | 
					            Body = body ?? "";
 | 
				
			||||||
 | 
					            ReasonPhrase = reasonPhrase;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpStatusCode StatusCode { get; private set; }
 | 
					        public HttpStatusCode StatusCode { get; private set; }
 | 
				
			||||||
@@ -26,5 +27,7 @@ namespace Ocelot.Cache
 | 
				
			|||||||
        public Dictionary<string, IEnumerable<string>> ContentHeaders { get; private set; }
 | 
					        public Dictionary<string, IEnumerable<string>> ContentHeaders { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string Body { get; private set; }
 | 
					        public string Body { get; private set; }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public string ReasonPhrase { get; private set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,7 +87,7 @@
 | 
				
			|||||||
                streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
 | 
					                streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return new DownstreamResponse(streamContent, cached.StatusCode, cached.Headers.ToList());
 | 
					            return new DownstreamResponse(streamContent, cached.StatusCode, cached.Headers.ToList(), cached.ReasonPhrase);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        internal async Task<CachedResponse> CreateCachedResponse(DownstreamResponse response)
 | 
					        internal async Task<CachedResponse> CreateCachedResponse(DownstreamResponse response)
 | 
				
			||||||
@@ -109,7 +109,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var contentHeaders = response?.Content?.Headers.ToDictionary(v => v.Key, v => v.Value);
 | 
					            var contentHeaders = response?.Content?.Headers.ToDictionary(v => v.Key, v => v.Value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var cached = new CachedResponse(statusCode, headers, body, contentHeaders);
 | 
					            var cached = new CachedResponse(statusCode, headers, body, contentHeaders, response.ReasonPhrase);
 | 
				
			||||||
            return cached;
 | 
					            return cached;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,25 +7,27 @@ namespace Ocelot.Middleware
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class DownstreamResponse
 | 
					    public class DownstreamResponse
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public DownstreamResponse(HttpContent content, HttpStatusCode statusCode, List<Header> headers)
 | 
					        public DownstreamResponse(HttpContent content, HttpStatusCode statusCode, List<Header> headers, string reasonPhrase)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Content = content;
 | 
					            Content = content;
 | 
				
			||||||
            StatusCode = statusCode;
 | 
					            StatusCode = statusCode;
 | 
				
			||||||
            Headers = headers ?? new List<Header>();
 | 
					            Headers = headers ?? new List<Header>();
 | 
				
			||||||
 | 
					            ReasonPhrase = reasonPhrase;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamResponse(HttpResponseMessage response)
 | 
					        public DownstreamResponse(HttpResponseMessage response)
 | 
				
			||||||
            :this(response.Content, response.StatusCode, response.Headers.Select(x => new Header(x.Key, x.Value)).ToList())
 | 
					            :this(response.Content, response.StatusCode, response.Headers.Select(x => new Header(x.Key, x.Value)).ToList(), response.ReasonPhrase)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamResponse(HttpContent content, HttpStatusCode statusCode, IEnumerable<KeyValuePair<string, IEnumerable<string>>> headers)
 | 
					        public DownstreamResponse(HttpContent content, HttpStatusCode statusCode, IEnumerable<KeyValuePair<string, IEnumerable<string>>> headers, string reasonPhrase)
 | 
				
			||||||
            :this(content, statusCode, headers.Select(x => new Header(x.Key, x.Value)).ToList())
 | 
					            :this(content, statusCode, headers.Select(x => new Header(x.Key, x.Value)).ToList(), reasonPhrase)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpContent Content { get; }
 | 
					        public HttpContent Content { get; }
 | 
				
			||||||
        public HttpStatusCode StatusCode { get; }
 | 
					        public HttpStatusCode StatusCode { get; }
 | 
				
			||||||
        public List<Header> Headers { get; }
 | 
					        public List<Header> Headers { get; }
 | 
				
			||||||
 | 
					        public string ReasonPhrase {get;}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@ namespace Ocelot.Middleware.Multiplexer
 | 
				
			|||||||
                Headers = {ContentType = new MediaTypeHeaderValue("application/json")}
 | 
					                Headers = {ContentType = new MediaTypeHeaderValue("application/json")}
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            originalContext.DownstreamResponse = new DownstreamResponse(stringContent, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>());
 | 
					            originalContext.DownstreamResponse = new DownstreamResponse(stringContent, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "cannot return from aggregate..which reason phrase would you use?");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static void MapAggregateError(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts, int i)
 | 
					        private static void MapAggregateError(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts, int i)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ using System.Linq;
 | 
				
			|||||||
using System.Net;
 | 
					using System.Net;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Http.Features;
 | 
				
			||||||
using Microsoft.Extensions.Primitives;
 | 
					using Microsoft.Extensions.Primitives;
 | 
				
			||||||
using Ocelot.Headers;
 | 
					using Ocelot.Headers;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
@@ -45,6 +46,8 @@ namespace Ocelot.Responder
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            context.Response.StatusCode = (int)response.StatusCode;
 | 
					            context.Response.StatusCode = (int)response.StatusCode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            context.Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = response.ReasonPhrase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            using(content)
 | 
					            using(content)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (response.StatusCode != HttpStatusCode.NotModified && context.Response.ContentLength != 0)
 | 
					                if (response.StatusCode != HttpStatusCode.NotModified && context.Response.ContentLength != 0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -559,7 +559,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            var merge = $"{one}, {two}";
 | 
					            var merge = $"{one}, {two}";
 | 
				
			||||||
            merge = merge.Replace("Hello", "Bye").Replace("{", "").Replace("}", "");
 | 
					            merge = merge.Replace("Hello", "Bye").Replace("{", "").Replace("}", "");
 | 
				
			||||||
            var headers = responses.SelectMany(x => x.Headers).ToList();
 | 
					            var headers = responses.SelectMany(x => x.Headers).ToList();
 | 
				
			||||||
            return new DownstreamResponse(new StringContent(merge), HttpStatusCode.OK, headers);
 | 
					            return new DownstreamResponse(new StringContent(merge), HttpStatusCode.OK, headers, "some reason");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										76
									
								
								test/Ocelot.AcceptanceTests/ReasonPhraseTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								test/Ocelot.AcceptanceTests/ReasonPhraseTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					namespace Ocelot.AcceptanceTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using System;
 | 
				
			||||||
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
 | 
					    using System.Net;
 | 
				
			||||||
 | 
					    using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					    using Microsoft.AspNetCore.Http.Features;
 | 
				
			||||||
 | 
					    using Ocelot.Configuration.File;
 | 
				
			||||||
 | 
					    using Shouldly;
 | 
				
			||||||
 | 
					    using TestStack.BDDfy;
 | 
				
			||||||
 | 
					    using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class ReasonPhraseTests : IDisposable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly Steps _steps;
 | 
				
			||||||
 | 
					        private string _contentType;
 | 
				
			||||||
 | 
					        private long? _contentLength;
 | 
				
			||||||
 | 
					        private bool _contentTypeHeaderExists;
 | 
				
			||||||
 | 
					        private readonly ServiceHandler _serviceHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public ReasonPhraseTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _serviceHandler = new ServiceHandler();
 | 
				
			||||||
 | 
					            _steps = new Steps();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_reason_phrase()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var configuration = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ReRoutes = new List<FileReRoute>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new FileReRoute
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            DownstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                            DownstreamScheme = "http",
 | 
				
			||||||
 | 
					                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                new FileHostAndPort
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    Host = "localhost",
 | 
				
			||||||
 | 
					                                    Port = 51339,
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            UpstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51339", "/", "some reason"))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenOcelotIsRunning())
 | 
				
			||||||
 | 
					                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .And(_ => _steps.ThenTheReasonPhraseIs("some reason"))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string reasonPhrase)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                context.Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = reasonPhrase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                await context.Response.WriteAsync("YOYO!");
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Dispose()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _serviceHandler?.Dispose();
 | 
				
			||||||
 | 
					            _steps.Dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -452,6 +452,11 @@
 | 
				
			|||||||
            header.First().ShouldBe(value);
 | 
					            header.First().ShouldBe(value);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void ThenTheReasonPhraseIs(string expected)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _response.ReasonPhrase.ShouldBe(expected);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
 | 
					        /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,7 @@
 | 
				
			|||||||
                { "content-type", new List<string> { "application/json" } }
 | 
					                { "content-type", new List<string> { "application/json" } }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var cachedResponse = new CachedResponse(HttpStatusCode.OK, headers, "", contentHeaders);
 | 
					            var cachedResponse = new CachedResponse(HttpStatusCode.OK, headers, "", contentHeaders, "some reason");
 | 
				
			||||||
            this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
 | 
					            this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
 | 
				
			||||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
					                .And(x => x.GivenTheDownstreamRouteIs())
 | 
				
			||||||
                .When(x => x.WhenICallTheMiddleware())
 | 
					                .When(x => x.WhenICallTheMiddleware())
 | 
				
			||||||
@@ -69,7 +69,7 @@
 | 
				
			|||||||
                { "Expires", new List<string> { "-1" } }
 | 
					                { "Expires", new List<string> { "-1" } }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var cachedResponse = new CachedResponse(HttpStatusCode.OK, new Dictionary<string, IEnumerable<string>>(), "", contentHeaders);
 | 
					            var cachedResponse = new CachedResponse(HttpStatusCode.OK, new Dictionary<string, IEnumerable<string>>(), "", contentHeaders, "some reason");
 | 
				
			||||||
            this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
 | 
					            this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
 | 
				
			||||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
					                .And(x => x.GivenTheDownstreamRouteIs())
 | 
				
			||||||
                .When(x => x.WhenICallTheMiddleware())
 | 
					                .When(x => x.WhenICallTheMiddleware())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,7 +43,7 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
 | 
				
			||||||
                });
 | 
					                }, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var fAndRs = new List<HeaderFindAndReplace> {new HeaderFindAndReplace("test", "test", "chiken", 0)};
 | 
					            var fAndRs = new List<HeaderFindAndReplace> {new HeaderFindAndReplace("test", "test", "chiken", 0)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,7 +61,7 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
 | 
				
			||||||
                });
 | 
					                }, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var fAndRs = new List<HeaderFindAndReplace>();
 | 
					            var fAndRs = new List<HeaderFindAndReplace>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -84,7 +84,7 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
				
			||||||
                });
 | 
					                }, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var fAndRs = new List<HeaderFindAndReplace>
 | 
					            var fAndRs = new List<HeaderFindAndReplace>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -111,7 +111,7 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
				
			||||||
                });
 | 
					                }, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var fAndRs = new List<HeaderFindAndReplace>
 | 
					            var fAndRs = new List<HeaderFindAndReplace>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -138,7 +138,7 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
				
			||||||
                });
 | 
					                }, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var fAndRs = new List<HeaderFindAndReplace>
 | 
					            var fAndRs = new List<HeaderFindAndReplace>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -165,7 +165,7 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
				
			||||||
                });
 | 
					                }, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var fAndRs = new List<HeaderFindAndReplace>
 | 
					            var fAndRs = new List<HeaderFindAndReplace>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -192,7 +192,7 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
				
			||||||
                });
 | 
					                }, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var fAndRs = new List<HeaderFindAndReplace>
 | 
					            var fAndRs = new List<HeaderFindAndReplace>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -219,7 +219,7 @@ namespace Ocelot.UnitTests.Headers
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
 | 
				
			||||||
                });
 | 
					                }, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var fAndRs = new List<HeaderFindAndReplace>
 | 
					            var fAndRs = new List<HeaderFindAndReplace>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,13 +49,13 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
					            var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new EditableList<KeyValuePair<string, IEnumerable<string>>>()),
 | 
					                DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new EditableList<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
				
			||||||
                DownstreamReRoute = billDownstreamReRoute
 | 
					                DownstreamReRoute = billDownstreamReRoute
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
					            var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                DownstreamResponse = new DownstreamResponse(new StringContent("George says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>()),
 | 
					                DownstreamResponse = new DownstreamResponse(new StringContent("George says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
				
			||||||
                DownstreamReRoute = georgeDownstreamReRoute
 | 
					                DownstreamReRoute = georgeDownstreamReRoute
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,6 +69,7 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
                .When(x => WhenIAggregate())
 | 
					                .When(x => WhenIAggregate())
 | 
				
			||||||
                .Then(x => ThenTheContentIs(expected))
 | 
					                .Then(x => ThenTheContentIs(expected))
 | 
				
			||||||
                .And(x => ThenTheContentTypeIs("application/json"))
 | 
					                .And(x => ThenTheContentTypeIs("application/json"))
 | 
				
			||||||
 | 
					                .And(x => ThenTheReasonPhraseIs("cannot return from aggregate..which reason phrase would you use?"))
 | 
				
			||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,13 +92,13 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
					            var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>()),
 | 
					                DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
				
			||||||
                DownstreamReRoute = billDownstreamReRoute
 | 
					                DownstreamReRoute = billDownstreamReRoute
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
					            var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                DownstreamResponse = new DownstreamResponse(new StringContent("Error"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>()),
 | 
					                DownstreamResponse = new DownstreamResponse(new StringContent("Error"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
				
			||||||
                DownstreamReRoute = georgeDownstreamReRoute,
 | 
					                DownstreamReRoute = georgeDownstreamReRoute,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,6 +117,11 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheReasonPhraseIs(string expected)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _upstreamContext.DownstreamResponse.ReasonPhrase.ShouldBe(expected);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheErrorIsMapped()
 | 
					        private void ThenTheErrorIsMapped()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _upstreamContext.Errors.ShouldBe(_downstreamContexts[1].Errors);
 | 
					            _upstreamContext.Errors.ShouldBe(_downstreamContexts[1].Errors);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,11 +43,11 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                new DownstreamContext(new DefaultHttpContext())
 | 
					                new DownstreamContext(new DefaultHttpContext())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    DownstreamResponse = new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>())
 | 
					                    DownstreamResponse = new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason")
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                new DownstreamContext(new DefaultHttpContext())
 | 
					                new DownstreamContext(new DefaultHttpContext())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    DownstreamResponse = new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>())
 | 
					                    DownstreamResponse = new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -72,11 +72,11 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                new DownstreamContext(new DefaultHttpContext())
 | 
					                new DownstreamContext(new DefaultHttpContext())
 | 
				
			||||||
                { 
 | 
					                { 
 | 
				
			||||||
                    DownstreamResponse = new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>())
 | 
					                    DownstreamResponse = new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason")
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                new DownstreamContext(new DefaultHttpContext())
 | 
					                new DownstreamContext(new DefaultHttpContext())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    DownstreamResponse = new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>())
 | 
					                    DownstreamResponse = new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -146,7 +146,7 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
                var laura = await responses[1].Content.ReadAsStringAsync();
 | 
					                var laura = await responses[1].Content.ReadAsStringAsync();
 | 
				
			||||||
                var content = $"{tom}, {laura}";
 | 
					                var content = $"{tom}, {laura}";
 | 
				
			||||||
                var headers = responses.SelectMany(x => x.Headers).ToList();
 | 
					                var headers = responses.SelectMany(x => x.Headers).ToList();
 | 
				
			||||||
                return new DownstreamResponse(new StringContent(content), HttpStatusCode.OK, headers);
 | 
					                return new DownstreamResponse(new StringContent(content), HttpStatusCode.OK, headers, "some reason");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ using System.Linq;
 | 
				
			|||||||
using System.Net;
 | 
					using System.Net;
 | 
				
			||||||
using System.Net.Http;
 | 
					using System.Net.Http;
 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Http.Features;
 | 
				
			||||||
using Ocelot.Headers;
 | 
					using Ocelot.Headers;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
using Ocelot.Middleware.Multiplexer;
 | 
					using Ocelot.Middleware.Multiplexer;
 | 
				
			||||||
@@ -31,7 +32,7 @@ namespace Ocelot.UnitTests.Responder
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("Transfer-Encoding", new List<string> {"woop"})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("Transfer-Encoding", new List<string> {"woop"})
 | 
				
			||||||
                });
 | 
					                }, "some reason");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
 | 
					            _responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
 | 
				
			||||||
            var header = httpContext.Response.Headers["Transfer-Encoding"];
 | 
					            var header = httpContext.Response.Headers["Transfer-Encoding"];
 | 
				
			||||||
@@ -43,7 +44,7 @@ namespace Ocelot.UnitTests.Responder
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            var httpContext = new DefaultHttpContext();
 | 
					            var httpContext = new DefaultHttpContext();
 | 
				
			||||||
            var response = new DownstreamResponse(new StringContent("test"), HttpStatusCode.OK,
 | 
					            var response = new DownstreamResponse(new StringContent("test"), HttpStatusCode.OK,
 | 
				
			||||||
                new List<KeyValuePair<string, IEnumerable<string>>>());
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
 | 
					            _responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
 | 
				
			||||||
            var header = httpContext.Response.Headers["Content-Length"];
 | 
					            var header = httpContext.Response.Headers["Content-Length"];
 | 
				
			||||||
@@ -58,13 +59,28 @@ namespace Ocelot.UnitTests.Responder
 | 
				
			|||||||
                new List<KeyValuePair<string, IEnumerable<string>>>
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
 | 
				
			||||||
                });
 | 
					                }, "some reason");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
 | 
					            _responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
 | 
				
			||||||
            var header = httpContext.Response.Headers["test"];
 | 
					            var header = httpContext.Response.Headers["test"];
 | 
				
			||||||
            header.First().ShouldBe("test");
 | 
					            header.First().ShouldBe("test");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_add_reason_phrase()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var httpContext = new DefaultHttpContext();
 | 
				
			||||||
 | 
					            var response = new DownstreamResponse(new StringContent(""), HttpStatusCode.OK,
 | 
				
			||||||
 | 
					                new List<KeyValuePair<string, IEnumerable<string>>>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
 | 
				
			||||||
 | 
					                }, "some reason");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
 | 
				
			||||||
 | 
					            httpContext.Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase.ShouldBe(response.ReasonPhrase);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_call_without_exception()
 | 
					        public void should_call_without_exception()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user