From a8b56a63c24ea8b6dc5db522e40aaf6a8abf2312 Mon Sep 17 00:00:00 2001 From: Oleksandr Yershov Date: Thu, 28 Sep 2017 09:41:13 +0300 Subject: [PATCH 01/17] Cookie proxying and auto redirect configuration #128 HttpHandlerOptions are added to ReRoute configuration and passed down to HttpClientHttpRequester as Request properties. --- .../Configuration/Builder/ReRouteBuilder.cs | 11 ++- .../Creator/FileOcelotConfigurationCreator.cs | 8 ++- .../Creator/HttpHandlerOptionsCreator.cs | 13 ++++ .../Creator/IHttpHandlerOptionsCreator.cs | 12 ++++ .../File/FileHttpHandlerOptions.cs | 15 ++++ src/Ocelot/Configuration/File/FileReRoute.cs | 2 + .../Configuration/HttpHandlerOptions.cs | 25 +++++++ src/Ocelot/Configuration/ReRoute.cs | 5 +- .../ServiceCollectionExtensions.cs | 1 + .../Request/Builder/HttpRequestCreator.cs | 6 +- src/Ocelot/Request/Builder/IRequestCreator.cs | 4 +- .../HttpRequestBuilderMiddleware.cs | 4 +- src/Ocelot/Request/Request.cs | 8 ++- src/Ocelot/Requester/HttpClientBuilder.cs | 4 +- .../Requester/HttpClientHttpRequester.cs | 12 ++-- src/Ocelot/Requester/IHttpClientBuilder.cs | 12 ++-- .../FileConfigurationCreatorTests.cs | 43 ++++++++++- .../HttpHandlerOptionsCreatorTests.cs | 71 +++++++++++++++++++ .../HttpRequestBuilderMiddlewareTests.cs | 14 ++-- .../Request/HttpRequestCreatorTests.cs | 25 ++++++- .../Requester/HttpRequesterMiddlewareTests.cs | 2 +- 21 files changed, 269 insertions(+), 28 deletions(-) create mode 100644 src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs create mode 100644 src/Ocelot/Configuration/Creator/IHttpHandlerOptionsCreator.cs create mode 100644 src/Ocelot/Configuration/File/FileHttpHandlerOptions.cs create mode 100644 src/Ocelot/Configuration/HttpHandlerOptions.cs create mode 100644 test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index 852c4870..ad84a3e6 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -28,7 +28,8 @@ namespace Ocelot.Configuration.Builder private string _loadBalancer; private ServiceProviderConfiguration _serviceProviderConfiguraion; private bool _useQos; - private QoSOptions _qosOptions; + private QoSOptions _qosOptions; + private HttpHandlerOptions _httpHandlerOptions; public bool _enableRateLimiting; public RateLimitOptions _rateLimitOptions; @@ -176,6 +177,11 @@ namespace Ocelot.Configuration.Builder return this; } + public ReRouteBuilder WithHttpHandlerOptions(HttpHandlerOptions input) + { + _httpHandlerOptions = input; + return this; + } public ReRoute Build() { @@ -203,7 +209,8 @@ namespace Ocelot.Configuration.Builder _useQos, _qosOptions, _enableRateLimiting, - _rateLimitOptions); + _rateLimitOptions, + _httpHandlerOptions); } } } diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index c6f5f4fe..b8a2df07 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -38,6 +38,7 @@ namespace Ocelot.Configuration.Creator private readonly IReRouteOptionsCreator _fileReRouteOptionsCreator; private readonly IRateLimitOptionsCreator _rateLimitOptionsCreator; private readonly IRegionCreator _regionCreator; + private readonly IHttpHandlerOptionsCreator _httpHandlerOptionsCreator; public FileOcelotConfigurationCreator( IOptions options, @@ -55,7 +56,8 @@ namespace Ocelot.Configuration.Creator IQoSOptionsCreator qosOptionsCreator, IReRouteOptionsCreator fileReRouteOptionsCreator, IRateLimitOptionsCreator rateLimitOptionsCreator, - IRegionCreator regionCreator + IRegionCreator regionCreator, + IHttpHandlerOptionsCreator httpHandlerOptionsCreator ) { _regionCreator = regionCreator; @@ -74,6 +76,7 @@ namespace Ocelot.Configuration.Creator _serviceProviderConfigCreator = serviceProviderConfigCreator; _qosOptionsCreator = qosOptionsCreator; _fileReRouteOptionsCreator = fileReRouteOptionsCreator; + _httpHandlerOptionsCreator = httpHandlerOptionsCreator; } public async Task> Create() @@ -143,6 +146,8 @@ namespace Ocelot.Configuration.Creator var region = _regionCreator.Create(fileReRoute); + var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute); + var reRoute = new ReRouteBuilder() .WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate) .WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate) @@ -168,6 +173,7 @@ namespace Ocelot.Configuration.Creator .WithQosOptions(qosOptions) .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) .WithRateLimitOptions(rateLimitOption) + .WithHttpHandlerOptions(httpHandlerOptions) .Build(); await SetupLoadBalancer(reRoute); diff --git a/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs b/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs new file mode 100644 index 00000000..52aa7694 --- /dev/null +++ b/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs @@ -0,0 +1,13 @@ +using Ocelot.Configuration.File; + +namespace Ocelot.Configuration.Creator +{ + public class HttpHandlerOptionsCreator : IHttpHandlerOptionsCreator + { + public HttpHandlerOptions Create(FileReRoute fileReRoute) + { + return new HttpHandlerOptions(fileReRoute.HttpHandlerOptions.AllowAutoRedirect, + fileReRoute.HttpHandlerOptions.UseCookieContainer); + } + } +} diff --git a/src/Ocelot/Configuration/Creator/IHttpHandlerOptionsCreator.cs b/src/Ocelot/Configuration/Creator/IHttpHandlerOptionsCreator.cs new file mode 100644 index 00000000..34e5ffd1 --- /dev/null +++ b/src/Ocelot/Configuration/Creator/IHttpHandlerOptionsCreator.cs @@ -0,0 +1,12 @@ +using Ocelot.Configuration.File; + +namespace Ocelot.Configuration.Creator +{ + /// + /// Describes creation of HttpHandlerOptions + /// + public interface IHttpHandlerOptionsCreator + { + HttpHandlerOptions Create(FileReRoute fileReRoute); + } +} diff --git a/src/Ocelot/Configuration/File/FileHttpHandlerOptions.cs b/src/Ocelot/Configuration/File/FileHttpHandlerOptions.cs new file mode 100644 index 00000000..ea352767 --- /dev/null +++ b/src/Ocelot/Configuration/File/FileHttpHandlerOptions.cs @@ -0,0 +1,15 @@ +namespace Ocelot.Configuration.File +{ + public class FileHttpHandlerOptions + { + public FileHttpHandlerOptions() + { + AllowAutoRedirect = true; + UseCookieContainer = true; + } + + public bool AllowAutoRedirect { get; set; } + + public bool UseCookieContainer { get; set; } + } +} diff --git a/src/Ocelot/Configuration/File/FileReRoute.cs b/src/Ocelot/Configuration/File/FileReRoute.cs index 59483aee..1505e50a 100644 --- a/src/Ocelot/Configuration/File/FileReRoute.cs +++ b/src/Ocelot/Configuration/File/FileReRoute.cs @@ -15,6 +15,7 @@ namespace Ocelot.Configuration.File FileCacheOptions = new FileCacheOptions(); QoSOptions = new FileQoSOptions(); RateLimitOptions = new FileRateLimitRule(); + HttpHandlerOptions = new FileHttpHandlerOptions(); } public string DownstreamPathTemplate { get; set; } @@ -35,5 +36,6 @@ namespace Ocelot.Configuration.File public FileQoSOptions QoSOptions { get; set; } public string LoadBalancer {get;set;} public FileRateLimitRule RateLimitOptions { get; set; } + public FileHttpHandlerOptions HttpHandlerOptions { get; set; } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/HttpHandlerOptions.cs b/src/Ocelot/Configuration/HttpHandlerOptions.cs new file mode 100644 index 00000000..0ec72d1d --- /dev/null +++ b/src/Ocelot/Configuration/HttpHandlerOptions.cs @@ -0,0 +1,25 @@ +namespace Ocelot.Configuration +{ + /// + /// Describes configuration parameters for http handler, + /// that is created to handle a request to service + /// + public class HttpHandlerOptions + { + public HttpHandlerOptions(bool allowAutoRedirect, bool useCookieContainer) + { + AllowAutoRedirect = allowAutoRedirect; + UseCookieContainer = useCookieContainer; + } + + /// + /// Specify if auto redirect is enabled + /// + public bool AllowAutoRedirect { get; private set; } + + /// + /// Specify is handler has to use a cookie container + /// + public bool UseCookieContainer { get; private set; } + } +} diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index 2b8734c4..cfc8b9ba 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -29,7 +29,8 @@ namespace Ocelot.Configuration bool isQos, QoSOptions qosOptions, bool enableEndpointRateLimiting, - RateLimitOptions ratelimitOptions) + RateLimitOptions ratelimitOptions, + HttpHandlerOptions httpHandlerOptions) { ReRouteKey = reRouteKey; ServiceProviderConfiguraion = serviceProviderConfiguraion; @@ -58,6 +59,7 @@ namespace Ocelot.Configuration QosOptionsOptions = qosOptions; EnableEndpointEndpointRateLimiting = enableEndpointRateLimiting; RateLimitOptions = ratelimitOptions; + HttpHandlerOptions = httpHandlerOptions; } public string ReRouteKey {get;private set;} @@ -84,5 +86,6 @@ namespace Ocelot.Configuration public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; } public bool EnableEndpointEndpointRateLimiting { get; private set; } public RateLimitOptions RateLimitOptions { get; private set; } + public HttpHandlerOptions HttpHandlerOptions { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index d55a8573..08314b70 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -84,6 +84,7 @@ namespace Ocelot.DependencyInjection services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); + services.TryAddSingleton(); var identityServerConfiguration = IdentityServerConfigurationCreator.GetIdentityServerConfiguration(); diff --git a/src/Ocelot/Request/Builder/HttpRequestCreator.cs b/src/Ocelot/Request/Builder/HttpRequestCreator.cs index f95db4b9..8c3c9218 100644 --- a/src/Ocelot/Request/Builder/HttpRequestCreator.cs +++ b/src/Ocelot/Request/Builder/HttpRequestCreator.cs @@ -10,9 +10,11 @@ namespace Ocelot.Request.Builder public async Task> Build( HttpRequestMessage httpRequestMessage, bool isQos, - IQoSProvider qosProvider) + IQoSProvider qosProvider, + bool useCookieContainer, + bool allowAutoRedirect) { - return new OkResponse(new Request(httpRequestMessage, isQos, qosProvider)); + return new OkResponse(new Request(httpRequestMessage, isQos, qosProvider, useCookieContainer, allowAutoRedirect)); } } } \ No newline at end of file diff --git a/src/Ocelot/Request/Builder/IRequestCreator.cs b/src/Ocelot/Request/Builder/IRequestCreator.cs index 85fbfa8d..d290db4f 100644 --- a/src/Ocelot/Request/Builder/IRequestCreator.cs +++ b/src/Ocelot/Request/Builder/IRequestCreator.cs @@ -11,6 +11,8 @@ Task> Build( HttpRequestMessage httpRequestMessage, bool isQos, - IQoSProvider qosProvider); + IQoSProvider qosProvider, + bool useCookieContainer, + bool allowAutoRedirect); } } diff --git a/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs index c59af7a6..8e05f2ea 100644 --- a/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs @@ -46,7 +46,9 @@ namespace Ocelot.Request.Middleware var buildResult = await _requestCreator.Build( DownstreamRequest, DownstreamRoute.ReRoute.IsQos, - qosProvider.Data); + qosProvider.Data, + DownstreamRoute.ReRoute.HttpHandlerOptions.UseCookieContainer, + DownstreamRoute.ReRoute.HttpHandlerOptions.AllowAutoRedirect); if (buildResult.IsError) { diff --git a/src/Ocelot/Request/Request.cs b/src/Ocelot/Request/Request.cs index 3f1c654c..9f0b66e2 100644 --- a/src/Ocelot/Request/Request.cs +++ b/src/Ocelot/Request/Request.cs @@ -8,15 +8,21 @@ namespace Ocelot.Request public Request( HttpRequestMessage httpRequestMessage, bool isQos, - IQoSProvider qosProvider) + IQoSProvider qosProvider, + bool allowAutoRedirect, + bool useCookieContainer) { HttpRequestMessage = httpRequestMessage; IsQos = isQos; QosProvider = qosProvider; + AllowAutoRedirect = allowAutoRedirect; + UseCookieContainer = useCookieContainer; } public HttpRequestMessage HttpRequestMessage { get; private set; } public bool IsQos { get; private set; } public IQoSProvider QosProvider { get; private set; } + public bool AllowAutoRedirect { get; private set; } + public bool UseCookieContainer { get; private set; } } } diff --git a/src/Ocelot/Requester/HttpClientBuilder.cs b/src/Ocelot/Requester/HttpClientBuilder.cs index 141eab8b..83f475c2 100644 --- a/src/Ocelot/Requester/HttpClientBuilder.cs +++ b/src/Ocelot/Requester/HttpClientBuilder.cs @@ -20,9 +20,9 @@ namespace Ocelot.Requester return this; } - public IHttpClient Create() + public IHttpClient Create(bool useCookies, bool allowAutoRedirect) { - var httpclientHandler = new HttpClientHandler(); + var httpclientHandler = new HttpClientHandler { AllowAutoRedirect = allowAutoRedirect, UseCookies = useCookies}; var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler)); diff --git a/src/Ocelot/Requester/HttpClientHttpRequester.cs b/src/Ocelot/Requester/HttpClientHttpRequester.cs index 3f85af0c..a6a28915 100644 --- a/src/Ocelot/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot/Requester/HttpClientHttpRequester.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Net.Http; using System.Threading.Tasks; +using Ocelot.Configuration; using Ocelot.Logging; using Ocelot.Responses; using Polly.CircuitBreaker; @@ -14,7 +15,8 @@ namespace Ocelot.Requester private readonly IHttpClientCache _cacheHandlers; private readonly IOcelotLogger _logger; - public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, IHttpClientCache cacheHandlers) + public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, + IHttpClientCache cacheHandlers) { _logger = loggerFactory.CreateLogger(); _cacheHandlers = cacheHandlers; @@ -25,8 +27,8 @@ namespace Ocelot.Requester var builder = new HttpClientBuilder(); var cacheKey = GetCacheKey(request, builder); - - var httpClient = GetHttpClient(cacheKey, builder); + + var httpClient = GetHttpClient(cacheKey, builder, request.UseCookieContainer, request.AllowAutoRedirect); try { @@ -54,13 +56,13 @@ namespace Ocelot.Requester } - private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder) + private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder, bool useCookieContainer, bool allowAutoRedirect) { var httpClient = _cacheHandlers.Get(cacheKey); if (httpClient == null) { - httpClient = builder.Create(); + httpClient = builder.Create(useCookieContainer, allowAutoRedirect); } return httpClient; } diff --git a/src/Ocelot/Requester/IHttpClientBuilder.cs b/src/Ocelot/Requester/IHttpClientBuilder.cs index 832fd8d1..6de5f87a 100644 --- a/src/Ocelot/Requester/IHttpClientBuilder.cs +++ b/src/Ocelot/Requester/IHttpClientBuilder.cs @@ -15,11 +15,13 @@ namespace Ocelot.Requester /// /// Sets a PollyCircuitBreakingDelegatingHandler . /// - IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger); - - /// + IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger); + + /// /// Creates the - /// - IHttpClient Create(); + /// + /// Defines if http client should use cookie container + /// Defines if http client should allow auto redirect + IHttpClient Create(bool useCookies, bool allowAutoRedirect); } } diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index 4cb53118..252e6f11 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -45,6 +45,7 @@ namespace Ocelot.UnitTests.Configuration private Mock _fileReRouteOptionsCreator; private Mock _rateLimitOptions; private Mock _regionCreator; + private Mock _httpHandlerOptionsCreator; public FileConfigurationCreatorTests() { @@ -66,6 +67,7 @@ namespace Ocelot.UnitTests.Configuration _fileReRouteOptionsCreator = new Mock(); _rateLimitOptions = new Mock(); _regionCreator = new Mock(); + _httpHandlerOptionsCreator = new Mock(); _ocelotConfigurationCreator = new FileOcelotConfigurationCreator( _fileConfig.Object, _validator.Object, _logger.Object, @@ -73,7 +75,7 @@ namespace Ocelot.UnitTests.Configuration _qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object, _authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object, _serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object, - _rateLimitOptions.Object, _regionCreator.Object); + _rateLimitOptions.Object, _regionCreator.Object, _httpHandlerOptionsCreator.Object); } [Fact] @@ -444,6 +446,45 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } + [Fact] + public void should_call_httpHandler_creator() + { + var reRouteOptions = new ReRouteOptionsBuilder() + .Build(); + var httpHandlerOptions = new HttpHandlerOptions(true, true); + + this.Given(x => x.GivenTheConfigIs(new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamHost = "127.0.0.1", + UpstreamPathTemplate = "/api/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", + UpstreamHttpMethod = new List { "Get" } + } + }, + })) + .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) + .And(x => x.GivenTheConfigIsValid()) + .And(x => x.GivenTheFollowingHttpHandlerOptionsAreReturned(httpHandlerOptions)) + .When(x => x.WhenICreateTheConfig()) + .Then(x => x.ThenTheHttpHandlerOptionsCreatorIsCalledCorrectly()) + .BDDfy(); + } + + private void GivenTheFollowingHttpHandlerOptionsAreReturned(HttpHandlerOptions httpHandlerOptions) + { + _httpHandlerOptionsCreator.Setup(x => x.Create(It.IsAny())) + .Returns(httpHandlerOptions); + } + + private void ThenTheHttpHandlerOptionsCreatorIsCalledCorrectly() + { + _httpHandlerOptionsCreator.Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once()); + } + [Theory] [MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))] public void should_create_with_headers_to_extract(string provider, IAuthenticationConfig config, FileConfiguration fileConfig) diff --git a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs new file mode 100644 index 00000000..69f414e5 --- /dev/null +++ b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs @@ -0,0 +1,71 @@ +using Ocelot.Configuration; +using Ocelot.Configuration.Creator; +using Ocelot.Configuration.File; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Configuration +{ + + public class HttpHandlerOptionsCreatorTests + { + private readonly IHttpHandlerOptionsCreator _httpHandlerOptionsCreator; + private FileReRoute _fileReRoute; + private HttpHandlerOptions _httpHandlerOptions; + + public HttpHandlerOptionsCreatorTests() + { + _httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(); + } + + [Fact] + public void should_create_options_with_useCookie_and_allowAutoRedirect_true_as_default() + { + var fileReRoute = new FileReRoute(); + var expectedOptions = new HttpHandlerOptions(true, true); + + this.Given(x => GivenTheFollowing(fileReRoute)) + .When(x => WhenICreateHttpHandlerOptions()) + .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) + .BDDfy(); + } + + [Fact] + public void should_create_options_with_specified_useCookie_and_allowAutoRedirect() + { + var fileReRoute = new FileReRoute + { + HttpHandlerOptions = new FileHttpHandlerOptions + { + AllowAutoRedirect = false, + UseCookieContainer = false + } + }; + + var expectedOptions = new HttpHandlerOptions(false, false); + + this.Given(x => GivenTheFollowing(fileReRoute)) + .When(x => WhenICreateHttpHandlerOptions()) + .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) + .BDDfy(); + } + + private void GivenTheFollowing(FileReRoute fileReRoute) + { + _fileReRoute = fileReRoute; + } + + private void WhenICreateHttpHandlerOptions() + { + _httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileReRoute); + } + + private void ThenTheFollowingOptionsReturned(HttpHandlerOptions options) + { + _httpHandlerOptions.ShouldNotBeNull(); + _httpHandlerOptions.AllowAutoRedirect.ShouldBe(options.AllowAutoRedirect); + _httpHandlerOptions.UseCookieContainer.ShouldBe(options.UseCookieContainer); + } + } +} diff --git a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs index 02f2b208..807c35a5 100644 --- a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs @@ -15,8 +15,9 @@ using TestStack.BDDfy; using Xunit; using Ocelot.Requester.QoS; - using Microsoft.AspNetCore.Builder; - + using Ocelot.Configuration; + using Microsoft.AspNetCore.Builder; + public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _requestBuilder; @@ -50,12 +51,13 @@ new ReRouteBuilder() .WithRequestIdKey("LSRequestId") .WithUpstreamHttpMethod(new List { "Get" }) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true)) .Build()); this.Given(x => x.GivenTheDownStreamUrlIs("any old string")) .And(x => x.GivenTheQosProviderHouseReturns(new OkResponse(new NoQoSProvider()))) .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider()))) + .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .BDDfy(); @@ -103,7 +105,11 @@ _request = new OkResponse(request); _requestBuilder - .Setup(x => x.Build(It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.Build(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) .ReturnsAsync(_request); } diff --git a/test/Ocelot.UnitTests/Request/HttpRequestCreatorTests.cs b/test/Ocelot.UnitTests/Request/HttpRequestCreatorTests.cs index d831aed9..f4f67ca0 100644 --- a/test/Ocelot.UnitTests/Request/HttpRequestCreatorTests.cs +++ b/test/Ocelot.UnitTests/Request/HttpRequestCreatorTests.cs @@ -15,6 +15,9 @@ private readonly bool _isQos; private readonly IQoSProvider _qoSProvider; private readonly HttpRequestMessage _requestMessage; + private readonly bool _useCookieContainer; + private readonly bool _allowAutoRedirect; + private Response _response; public HttpRequestCreatorTests() @@ -22,6 +25,9 @@ _requestCreator = new HttpRequestCreator(); _isQos = true; _qoSProvider = new NoQoSProvider(); + _useCookieContainer = false; + _allowAutoRedirect = false; + _requestMessage = new HttpRequestMessage(); } @@ -30,12 +36,19 @@ { this.When(x => x.WhenIBuildARequest()) .Then(x => x.ThenTheRequestContainsTheRequestMessage()) + .Then(x => x.ThenTheRequestContainsTheIsQos()) + .Then(x => x.ThenTheRequestContainsTheQosProvider()) + .Then(x => x.ThenTheRequestContainsUseCookieContainer()) + .Then(x => x.ThenTheRequestContainsAllowAutoRedirect()) .BDDfy(); } private void WhenIBuildARequest() { - _response = _requestCreator.Build(_requestMessage, _isQos, _qoSProvider).GetAwaiter().GetResult(); + _response = _requestCreator.Build(_requestMessage, + _isQos, _qoSProvider, _useCookieContainer, _allowAutoRedirect) + .GetAwaiter() + .GetResult(); } private void ThenTheRequestContainsTheRequestMessage() @@ -52,5 +65,15 @@ { _response.Data.QosProvider.ShouldBe(_qoSProvider); } + + private void ThenTheRequestContainsUseCookieContainer() + { + _response.Data.UseCookieContainer.ShouldBe(_useCookieContainer); + } + + private void ThenTheRequestContainsAllowAutoRedirect() + { + _response.Data.AllowAutoRedirect.ShouldBe(_allowAutoRedirect); + } } } diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index f5570f15..45aafecd 100644 --- a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -28,7 +28,7 @@ [Fact] public void should_call_scoped_data_repository_correctly() { - this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider()))) + this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider(), false, false))) .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage())) .And(x => x.GivenTheScopedRepoReturns()) .When(x => x.WhenICallTheMiddleware()) From 7ac6df71fbd9c9b31da01c7e14eba6a53d274278 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Mon, 9 Oct 2017 11:21:19 +0100 Subject: [PATCH 02/17] fixed build --- build.cake | 3 +- build.ps1 | 121 +++++++++++++++++++++++++++++------------- tools/packages.config | 2 +- 3 files changed, 86 insertions(+), 40 deletions(-) diff --git a/build.cake b/build.cake index 9960c588..f64519bd 100644 --- a/build.cake +++ b/build.cake @@ -1,6 +1,7 @@ #tool "nuget:?package=GitVersion.CommandLine" #tool "nuget:?package=GitReleaseNotes" -#addin "nuget:?package=Cake.Json" +#addin nuget:?package=Cake.Json +#addin nuget:?package=Newtonsoft.Json&version=9.0.1 #tool "nuget:?package=OpenCover" #tool "nuget:?package=ReportGenerator" #tool coveralls.net diff --git a/build.ps1 b/build.ps1 index 44de5793..265bd123 100644 --- a/build.ps1 +++ b/build.ps1 @@ -21,34 +21,35 @@ The build script target to run. The build configuration to use. .PARAMETER Verbosity Specifies the amount of information to be displayed. +.PARAMETER ShowDescription +Shows description about tasks. +.PARAMETER DryRun +Performs a dry run. .PARAMETER Experimental -Tells Cake to use the latest Roslyn release. -.PARAMETER WhatIf -Performs a dry run of the build script. -No tasks will be executed. +Uses the nightly builds of the Roslyn script engine. .PARAMETER Mono -Tells Cake to use the Mono scripting engine. +Uses the Mono Compiler rather than the Roslyn script engine. .PARAMETER SkipToolPackageRestore Skips restoring of packages. .PARAMETER ScriptArgs Remaining arguments are added here. .LINK -http://cakebuild.net +https://cakebuild.net #> [CmdletBinding()] Param( [string]$Script = "build.cake", - [string]$Target = "Default", - [ValidateSet("Release", "Debug")] - [string]$Configuration = "Release", + [string]$Target, + [string]$Configuration, [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] - [string]$Verbosity = "Verbose", + [string]$Verbosity, + [switch]$ShowDescription, + [Alias("WhatIf", "Noop")] + [switch]$DryRun, [switch]$Experimental, - [Alias("DryRun","Noop")] - [switch]$WhatIf, [switch]$Mono, [switch]$SkipToolPackageRestore, [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] @@ -80,6 +81,15 @@ function MD5HashFile([string] $filePath) } } +function GetProxyEnabledWebClient +{ + $wc = New-Object System.Net.WebClient + $proxy = [System.Net.WebRequest]::GetSystemWebProxy() + $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials + $wc.Proxy = $proxy + return $wc +} + Write-Host "Preparing to run build script..." if(!$PSScriptRoot){ @@ -87,31 +97,15 @@ if(!$PSScriptRoot){ } $TOOLS_DIR = Join-Path $PSScriptRoot "tools" +$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" +$MODULES_DIR = Join-Path $TOOLS_DIR "Modules" $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" $NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" $PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" $PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" - -# Should we use mono? -$UseMono = ""; -if($Mono.IsPresent) { - Write-Verbose -Message "Using the Mono based scripting engine." - $UseMono = "-mono" -} - -# Should we use the new Roslyn? -$UseExperimental = ""; -if($Experimental.IsPresent -and !($Mono.IsPresent)) { - Write-Verbose -Message "Using experimental version of Roslyn." - $UseExperimental = "-experimental" -} - -# Is this a dry run? -$UseDryRun = ""; -if($WhatIf.IsPresent) { - $UseDryRun = "-dryrun" -} +$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" +$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" # Make sure tools folder exists if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { @@ -121,8 +115,10 @@ if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { # Make sure that packages.config exist. if (!(Test-Path $PACKAGES_CONFIG)) { - Write-Verbose -Message "Downloading packages.config..." - try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { + Write-Verbose -Message "Downloading packages.config..." + try { + $wc = GetProxyEnabledWebClient + $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { Throw "Could not download packages.config." } } @@ -130,7 +126,7 @@ if (!(Test-Path $PACKAGES_CONFIG)) { # Try find NuGet.exe in path if not exists if (!(Test-Path $NUGET_EXE)) { Write-Verbose -Message "Trying to find nuget.exe in PATH..." - $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } + $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." @@ -142,7 +138,8 @@ if (!(Test-Path $NUGET_EXE)) { if (!(Test-Path $NUGET_EXE)) { Write-Verbose -Message "Downloading NuGet.exe..." try { - (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) + $wc = GetProxyEnabledWebClient + $wc.DownloadFile($NUGET_URL, $NUGET_EXE) } catch { Throw "Could not download NuGet.exe." } @@ -175,6 +172,41 @@ if(-Not $SkipToolPackageRestore.IsPresent) { $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" } Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Restore addins from NuGet +if (Test-Path $ADDINS_PACKAGES_CONFIG) { + Push-Location + Set-Location $ADDINS_DIR + + Write-Verbose -Message "Restoring addins from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet addins." + } + + Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Restore modules from NuGet +if (Test-Path $MODULES_PACKAGES_CONFIG) { + Push-Location + Set-Location $MODULES_DIR + + Write-Verbose -Message "Restoring modules from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet modules." + } + + Write-Verbose -Message ($NuGetOutput | out-string) + Pop-Location } @@ -183,7 +215,20 @@ if (!(Test-Path $CAKE_EXE)) { Throw "Could not find Cake.exe at $CAKE_EXE" } + + +# Build Cake arguments +$cakeArguments = @("$Script"); +if ($Target) { $cakeArguments += "-target=$Target" } +if ($Configuration) { $cakeArguments += "-configuration=$Configuration" } +if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" } +if ($ShowDescription) { $cakeArguments += "-showdescription" } +if ($DryRun) { $cakeArguments += "-dryrun" } +if ($Experimental) { $cakeArguments += "-experimental" } +if ($Mono) { $cakeArguments += "-mono" } +$cakeArguments += $ScriptArgs + # Start Cake Write-Host "Running build script..." -Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" -exit $LASTEXITCODE \ No newline at end of file +&$CAKE_EXE $cakeArguments +exit $LASTEXITCODE diff --git a/tools/packages.config b/tools/packages.config index 70a1e599..e0dd39bd 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - + From 68466b2193154b65e25ba6c8b0c586e223635241 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Mon, 9 Oct 2017 17:06:05 +0100 Subject: [PATCH 03/17] updated ensure stable release --- build.cake | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index f64519bd..bc6773c0 100644 --- a/build.cake +++ b/build.cake @@ -261,11 +261,19 @@ Task("ReleasePackagesToUnstableFeed") Task("EnsureStableReleaseRequirements") .Does(() => { + Information("Check if stable release..."); + if (!AppVeyor.IsRunningOnAppVeyor) { throw new Exception("Stable release should happen via appveyor"); } - + + Information("Running on AppVeyor..."); + + Information("IsTag = " + AppVeyor.Environment.Repository.Tag.IsTag); + + Information("Name = " + AppVeyor.Environment.Repository.Tag.Name); + var isTag = AppVeyor.Environment.Repository.Tag.IsTag && !string.IsNullOrWhiteSpace(AppVeyor.Environment.Repository.Tag.Name); @@ -274,6 +282,8 @@ Task("EnsureStableReleaseRequirements") { throw new Exception("Stable release should happen from a published GitHub release"); } + + Information("Release is stable..."); }); Task("UpdateVersionInfo") From b0131bb264da692d549d91705d16a699cc1dbd7b Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Tue, 10 Oct 2017 16:35:08 +0100 Subject: [PATCH 04/17] more logging to see whats wrong --- build.cake | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index bc6773c0..9394f275 100644 --- a/build.cake +++ b/build.cake @@ -298,17 +298,28 @@ Task("DownloadGitHubReleaseArtifacts") .IsDependentOn("UpdateVersionInfo") .Does(() => { + Information("DownloadGitHubReleaseArtifacts"); + EnsureDirectoryExists(packagesDir); + Information("Directory exists..."); + var releaseUrl = tagsUrl + releaseTag; + + Information("Release url " + releaseUrl); + var assets_url = ParseJson(GetResource(releaseUrl)) .GetValue("assets_url") .Value(); + Information("Assets url " + assets_url); + foreach(var asset in DeserializeJson(GetResource(assets_url))) { var file = packagesDir + File(asset.Value("name")); + Information("Downloading " + file); + DownloadFile(asset.Value("browser_download_url"), file); } }); @@ -416,7 +427,11 @@ private string GetResource(string url) { var assetsStream = assetsResponse.GetResponseStream(); var assetsReader = new StreamReader(assetsStream); - return assetsReader.ReadToEnd(); + var response = assetsReader.ReadToEnd(); + + Information("Response is " + response); + + return response; } } From 261f6130c8482d8e106ceab73d3064cf97c29958 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Tue, 10 Oct 2017 17:01:59 +0100 Subject: [PATCH 05/17] more logging --- build.cake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.cake b/build.cake index 9394f275..f2c471ff 100644 --- a/build.cake +++ b/build.cake @@ -316,12 +316,16 @@ Task("DownloadGitHubReleaseArtifacts") foreach(var asset in DeserializeJson(GetResource(assets_url))) { + Information("In the loop.."); + var file = packagesDir + File(asset.Value("name")); Information("Downloading " + file); DownloadFile(asset.Value("browser_download_url"), file); } + + Information("Out of the loop..."); }); Task("ReleasePackagesToStableFeed") From d4f972125e69e2ccd475eebbab697dc44bef9cdd Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Tue, 10 Oct 2017 17:33:42 +0100 Subject: [PATCH 06/17] try catch to tryand see error?? --- build.cake | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/build.cake b/build.cake index f2c471ff..6141ee21 100644 --- a/build.cake +++ b/build.cake @@ -420,23 +420,31 @@ private void PublishPackages(ConvertableDirectoryPath packagesDir, ConvertableFi /// gets the resource from the specified url private string GetResource(string url) { - Information("Getting resource from " + url); + try + { + Information("Getting resource from " + url); - var assetsRequest = System.Net.WebRequest.CreateHttp(url); - assetsRequest.Method = "GET"; - assetsRequest.Accept = "application/vnd.github.v3+json"; - assetsRequest.UserAgent = "BuildScript"; + var assetsRequest = System.Net.WebRequest.CreateHttp(url); + assetsRequest.Method = "GET"; + assetsRequest.Accept = "application/vnd.github.v3+json"; + assetsRequest.UserAgent = "BuildScript"; - using (var assetsResponse = assetsRequest.GetResponse()) - { - var assetsStream = assetsResponse.GetResponseStream(); - var assetsReader = new StreamReader(assetsStream); - var response = assetsReader.ReadToEnd(); + using (var assetsResponse = assetsRequest.GetResponse()) + { + var assetsStream = assetsResponse.GetResponseStream(); + var assetsReader = new StreamReader(assetsStream); + var response = assetsReader.ReadToEnd(); - Information("Response is " + response); - - return response; - } + Information("Response is " + response); + + return response; + } + } + catch(Exception exception) + { + Information("There was an exception " + exception); + throw; + } } private bool ShouldPublishToUnstableFeed(string filter, string branchName) From 4d3a7ae5e10497ca2e3a802705a21f3bdb8fb8ac Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Tue, 10 Oct 2017 17:52:38 +0100 Subject: [PATCH 07/17] another script change to find error --- build.cake | 44 ++++++++++++--------- test/Ocelot.AcceptanceTests/RoutingTests.cs | 41 +++++++++++++++++++ 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/build.cake b/build.cake index 6141ee21..20d40a4e 100644 --- a/build.cake +++ b/build.cake @@ -298,34 +298,42 @@ Task("DownloadGitHubReleaseArtifacts") .IsDependentOn("UpdateVersionInfo") .Does(() => { - Information("DownloadGitHubReleaseArtifacts"); + try + { + Information("DownloadGitHubReleaseArtifacts"); - EnsureDirectoryExists(packagesDir); + EnsureDirectoryExists(packagesDir); - Information("Directory exists..."); + Information("Directory exists..."); - var releaseUrl = tagsUrl + releaseTag; + var releaseUrl = tagsUrl + releaseTag; - Information("Release url " + releaseUrl); + Information("Release url " + releaseUrl); - var assets_url = ParseJson(GetResource(releaseUrl)) - .GetValue("assets_url") - .Value(); + var assets_url = ParseJson(GetResource(releaseUrl)) + .GetValue("assets_url") + .Value(); - Information("Assets url " + assets_url); + Information("Assets url " + assets_url); - foreach(var asset in DeserializeJson(GetResource(assets_url))) - { - Information("In the loop.."); + foreach(var asset in DeserializeJson(GetResource(assets_url))) + { + Information("In the loop.."); - var file = packagesDir + File(asset.Value("name")); + var file = packagesDir + File(asset.Value("name")); - Information("Downloading " + file); - - DownloadFile(asset.Value("browser_download_url"), file); - } + Information("Downloading " + file); + + DownloadFile(asset.Value("browser_download_url"), file); + } - Information("Out of the loop..."); + Information("Out of the loop..."); + } + catch(Exception exception) + { + Information("There was an exception " + exception); + throw; + } }); Task("ReleasePackagesToStableFeed") diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index fbdf57e1..648cbd71 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -61,6 +61,47 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void bug() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/api/v1/vacancy", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, + UpstreamPathTemplate = "/vacancy/", + UpstreamHttpMethod = new List { "Options", "Put", "Get", "Post", "Delete" }, + ServiceName = "botCore", + LoadBalancer = "LeastConnection" + }, + new FileReRoute + { + DownstreamPathTemplate = "/api/v1/vacancy/{vacancyId}", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, + UpstreamPathTemplate = "/vacancy/{vacancyId}", + UpstreamHttpMethod = new List { "Options", "Put", "Get", "Post", "Delete" }, + ServiceName = "botCore", + LoadBalancer = "LeastConnection" + } + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/v1/vacancy/1", 200, "Hello from Laura")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/vacancy/1")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + [Fact] public void should_return_response_200_when_path_missing_forward_slash_as_first_char() { From d0d74f08866f9aa1d746a015cfe8d930d6177f32 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Thu, 12 Oct 2017 19:03:20 +0100 Subject: [PATCH 08/17] match whole input with regex --- .../Creator/UpstreamTemplatePatternCreator.cs | 4 +- test/Ocelot.AcceptanceTests/QoSTests.cs | 2 +- test/Ocelot.AcceptanceTests/RoutingTests.cs | 42 ++++++++++++++++++- .../UpstreamTemplatePatternCreatorTests.cs | 10 ++--- .../UrlMatcher/RegExUrlMatcherTests.cs | 36 ++++++++++------ 5 files changed, 72 insertions(+), 22 deletions(-) diff --git a/src/Ocelot/Configuration/Creator/UpstreamTemplatePatternCreator.cs b/src/Ocelot/Configuration/Creator/UpstreamTemplatePatternCreator.cs index 95b339a9..4e02a158 100644 --- a/src/Ocelot/Configuration/Creator/UpstreamTemplatePatternCreator.cs +++ b/src/Ocelot/Configuration/Creator/UpstreamTemplatePatternCreator.cs @@ -41,8 +41,8 @@ namespace Ocelot.Configuration.Creator } var route = reRoute.ReRouteIsCaseSensitive - ? $"{upstreamTemplate}{RegExMatchEndString}" - : $"{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}"; + ? $"^{upstreamTemplate}{RegExMatchEndString}" + : $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}"; return route; } diff --git a/test/Ocelot.AcceptanceTests/QoSTests.cs b/test/Ocelot.AcceptanceTests/QoSTests.cs index 8825b75b..e8a8e6a1 100644 --- a/test/Ocelot.AcceptanceTests/QoSTests.cs +++ b/test/Ocelot.AcceptanceTests/QoSTests.cs @@ -98,7 +98,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", DownstreamPort = 51880, - UpstreamPathTemplate = "working", + UpstreamPathTemplate = "/working", UpstreamHttpMethod = new List { "Get" }, } } diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index fbdf57e1..f327a606 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -402,6 +402,46 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_404_when_calling_upstream_route_with_no_matching_downstream_re_route_github_issue_134() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/api/v1/vacancy", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, + UpstreamPathTemplate = "/vacancy/", + UpstreamHttpMethod = new List { "Options", "Put", "Get", "Post", "Delete" }, + ServiceName = "botCore", + LoadBalancer = "LeastConnection" + }, + new FileReRoute + { + DownstreamPathTemplate = "/api/v1/vacancy/{vacancyId}", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, + UpstreamPathTemplate = "/vacancy/{vacancyId}", + UpstreamHttpMethod = new List { "Options", "Put", "Get", "Post", "Delete" }, + ServiceName = "botCore", + LoadBalancer = "LeastConnection" + } + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/v1/vacancy/1", 200, "Hello from Laura")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("api/vacancy/1")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) + .BDDfy(); + } + private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { _builder = new WebHostBuilder() @@ -412,7 +452,7 @@ namespace Ocelot.AcceptanceTests .Configure(app => { app.Run(async context => - { + { _downstreamPath = context.Request.PathBase.Value; context.Response.StatusCode = statusCode; await context.Response.WriteAsync(responseBody); diff --git a/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs index 34db1232..21c5be38 100644 --- a/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs @@ -28,7 +28,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("(?i)/PRODUCTS/.*/$")) + .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS/.*/$")) .BDDfy(); } @@ -42,7 +42,7 @@ namespace Ocelot.UnitTests.Configuration }; this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("/PRODUCTS/.*/$")) + .Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/.*/$")) .BDDfy(); } @@ -57,7 +57,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("/api/products/.*/$")) + .Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/$")) .BDDfy(); } @@ -72,7 +72,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("/api/products/.*/variants/.*/$")) + .Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/variants/.*/$")) .BDDfy(); } [Fact] @@ -86,7 +86,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("/api/products/.*/variants/.*/$")) + .Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/variants/.*/$")) .BDDfy(); } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs index 70dd747d..9f76228b 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs @@ -28,6 +28,16 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher .BDDfy(); } + [Fact] + public void should_not_match_issue_134() + { + this.Given(x => x.GivenIHaveAUpstreamPath("/api/vacancy/1/")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)/vacancy/.*/$")) + .When(x => x.WhenIMatchThePaths()) + .And(x => x.ThenTheResultIsFalse()) + .BDDfy(); + } + [Fact] public void should_match_forward_slash_only_regex() { @@ -42,7 +52,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void should_find_match_when_template_smaller_than_valid_path() { this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("/api/products/.*$")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/api/products/.*$")) .When(x => x.WhenIMatchThePaths()) .And(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -52,7 +62,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void should_not_find_match() { this.Given(x => x.GivenIHaveAUpstreamPath("/api/values")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("/$")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/$")) .When(x => x.WhenIMatchThePaths()) .And(x => x.ThenTheResultIsFalse()) .BDDfy(); @@ -62,7 +72,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void can_match_down_stream_url() { this.Given(x => x.GivenIHaveAUpstreamPath("")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("$")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^$")) .When(x => x.WhenIMatchThePaths()) .And(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -72,7 +82,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void can_match_down_stream_url_with_no_slash() { this.Given(x => x.GivenIHaveAUpstreamPath("api")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api$")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -82,7 +92,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void can_match_down_stream_url_with_one_slash() { this.Given(x => x.GivenIHaveAUpstreamPath("api/")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/$")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -92,7 +102,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void can_match_down_stream_url_with_downstream_template() { this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/$")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -102,7 +112,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() { this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*$")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -112,7 +122,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() { this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/.*$")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/.*$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -122,7 +132,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() { this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*$")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -132,7 +142,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() { this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/.*$")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*/variant/.*$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -142,7 +152,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() { this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/$")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*/variant/$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -152,7 +162,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void should_ignore_case_sensitivity() { this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("(?i)api/product/products/.*/categories/.*/variant/$")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)api/product/products/.*/categories/.*/variant/$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .BDDfy(); @@ -162,7 +172,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher public void should_respect_case_sensitivity() { this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/$")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*/variant/$")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsFalse()) .BDDfy(); From c660c1575e9d717ef232e5833d696c3d03a19c06 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 13 Oct 2017 08:26:39 +0100 Subject: [PATCH 09/17] change to fix publish --- build.cake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index 9394f275..66242c12 100644 --- a/build.cake +++ b/build.cake @@ -308,8 +308,10 @@ Task("DownloadGitHubReleaseArtifacts") Information("Release url " + releaseUrl); - var assets_url = ParseJson(GetResource(releaseUrl)) - .GetValue("assets_url") + var assets_url = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl)); + + //var assets_url = ParseJson(GetResource(releaseUrl)) + assets_url.GetValue("assets_url") .Value(); Information("Assets url " + assets_url); From d5ff0b10d805faa15eff40dd62ccf75946fe996f Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 13 Oct 2017 08:32:10 +0100 Subject: [PATCH 10/17] another fix --- build.cake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index be56fa3f..2ef3ee25 100644 --- a/build.cake +++ b/build.cake @@ -310,10 +310,10 @@ Task("DownloadGitHubReleaseArtifacts") Information("Release url " + releaseUrl); - var assets_url = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl)); + var releaseJson = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl)); //todo - remove when publish working..var assets_url = ParseJson(GetResource(releaseUrl)) - assets_url.GetValue("assets_url").Value(); + assets_url = releaseJson.GetValue("assets_url").Value(); Information("Assets url " + assets_url); From f646f1c40ecbf055a89790cd322b951ec116dff8 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 13 Oct 2017 08:33:31 +0100 Subject: [PATCH 11/17] another.. --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 2ef3ee25..59e9aa3a 100644 --- a/build.cake +++ b/build.cake @@ -313,7 +313,7 @@ Task("DownloadGitHubReleaseArtifacts") var releaseJson = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl)); //todo - remove when publish working..var assets_url = ParseJson(GetResource(releaseUrl)) - assets_url = releaseJson.GetValue("assets_url").Value(); + var assets_url = releaseJson.GetValue("assets_url").Value(); Information("Assets url " + assets_url); From 53bb712957bf03594cb31e0528b0b71b38fbca00 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Fri, 13 Oct 2017 09:24:09 +0100 Subject: [PATCH 12/17] another try.. --- build.cake | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build.cake b/build.cake index 59e9aa3a..3be1841f 100644 --- a/build.cake +++ b/build.cake @@ -1,7 +1,7 @@ #tool "nuget:?package=GitVersion.CommandLine" #tool "nuget:?package=GitReleaseNotes" #addin nuget:?package=Cake.Json -#addin nuget:?package=Newtonsoft.Json&version=9.0.1 +#addin nuget:?package=Newtonsoft.Json #tool "nuget:?package=OpenCover" #tool "nuget:?package=ReportGenerator" #tool coveralls.net @@ -310,10 +310,11 @@ Task("DownloadGitHubReleaseArtifacts") Information("Release url " + releaseUrl); - var releaseJson = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl)); + //var releaseJson = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl)); - //todo - remove when publish working..var assets_url = ParseJson(GetResource(releaseUrl)) - var assets_url = releaseJson.GetValue("assets_url").Value(); + var assets_url = ParseJson(GetResource(releaseUrl)) + .GetValue("assets_url") + .Value(); Information("Assets url " + assets_url); From 0286956c3e6575865107f557a3d8eced892c6b6a Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Fri, 13 Oct 2017 09:45:38 +0100 Subject: [PATCH 13/17] try with ltest version of json.net --- tools/packages.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packages.config b/tools/packages.config index e0dd39bd..747e13e6 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - + From a16c56248335cbe888310fbdce6f51b310199f6a Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Fri, 13 Oct 2017 10:22:13 +0100 Subject: [PATCH 14/17] sigh.. --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 3be1841f..7eb30fd7 100644 --- a/build.cake +++ b/build.cake @@ -1,7 +1,7 @@ #tool "nuget:?package=GitVersion.CommandLine" #tool "nuget:?package=GitReleaseNotes" #addin nuget:?package=Cake.Json -#addin nuget:?package=Newtonsoft.Json +#addin nuget:?package=Newtonsoft.Json&version=9.0.1 #tool "nuget:?package=OpenCover" #tool "nuget:?package=ReportGenerator" #tool coveralls.net From 0b382ad3405ccf6c836b3c23e7a31c16a35de21e Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Fri, 13 Oct 2017 10:23:59 +0100 Subject: [PATCH 15/17] sigh part 2 --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 7eb30fd7..99dcdeb6 100644 --- a/build.cake +++ b/build.cake @@ -312,7 +312,7 @@ Task("DownloadGitHubReleaseArtifacts") //var releaseJson = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl)); - var assets_url = ParseJson(GetResource(releaseUrl)) + var assets_url = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl)) .GetValue("assets_url") .Value(); From 5ac6ae662bf12a74ff4af20d4d598fb5a1513ada Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Fri, 13 Oct 2017 10:35:36 +0100 Subject: [PATCH 16/17] another attempt --- build.cake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 99dcdeb6..e988060e 100644 --- a/build.cake +++ b/build.cake @@ -318,7 +318,11 @@ Task("DownloadGitHubReleaseArtifacts") Information("Assets url " + assets_url); - foreach(var asset in DeserializeJson(GetResource(assets_url))) + var assets = GetResource(assets_url); + + Information("Assets " + assets_url); + + foreach(var asset in Newtonsoft.Json.JsonConvert.DeserializeObject(assets)) { Information("In the loop.."); From ed94764420cb88aa2f3251d052c33fd0b6e0463a Mon Sep 17 00:00:00 2001 From: yuchen1030 <283434325@qq.com> Date: Thu, 26 Oct 2017 20:11:14 +0800 Subject: [PATCH 17/17] Update Program.cs Solving the problems that project cannot be run on IIS. --- test/Ocelot.ManualTest/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Ocelot.ManualTest/Program.cs b/test/Ocelot.ManualTest/Program.cs index a545819a..78c336d6 100644 --- a/test/Ocelot.ManualTest/Program.cs +++ b/test/Ocelot.ManualTest/Program.cs @@ -16,8 +16,8 @@ namespace Ocelot.ManualTest builder.UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup(); - + .UseIISIntegration() + .UseStartup(); var host = builder.Build(); host.Run();