mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-10-31 14:45:28 +08:00 
			
		
		
		
	Merge branch 'pitming-feature/MethodTransformer'
This commit is contained in:
		| @@ -24,6 +24,7 @@ Here is an example ReRoute configuration, You don't need to set all of these thi | |||||||
|             "UpstreamHttpMethod": [ |             "UpstreamHttpMethod": [ | ||||||
|                 "Get" |                 "Get" | ||||||
|             ], |             ], | ||||||
|  |             "DownstreamHttpMethod": "", | ||||||
|             "AddHeadersToRequest": {}, |             "AddHeadersToRequest": {}, | ||||||
|             "AddClaimsToRequest": {}, |             "AddClaimsToRequest": {}, | ||||||
|             "RouteClaimsRequirement": {}, |             "RouteClaimsRequirement": {}, | ||||||
|   | |||||||
							
								
								
									
										28
									
								
								docs/features/methodtransformation.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								docs/features/methodtransformation.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | HTTP Method Transformation | ||||||
|  | ========================== | ||||||
|  |  | ||||||
|  | Ocelot allows the user to change the HTTP request method that will be used when making a request to a downstream service. | ||||||
|  |  | ||||||
|  | This achieved by setting the following ReRoute configuration: | ||||||
|  |  | ||||||
|  | .. code-block:: json | ||||||
|  |  | ||||||
|  | { | ||||||
|  |     "DownstreamPathTemplate": "/{url}", | ||||||
|  |     "UpstreamPathTemplate": "/{url}", | ||||||
|  |     "UpstreamHttpMethod": [ | ||||||
|  |         "Get" | ||||||
|  |     ], | ||||||
|  |     "DownstreamHttpMethod": "POST", | ||||||
|  |     "DownstreamScheme": "http", | ||||||
|  |     "DownstreamHostAndPorts": [ | ||||||
|  |         { | ||||||
|  |             "Host": "localhost", | ||||||
|  |             "Port": 53271 | ||||||
|  |         } | ||||||
|  |     ], | ||||||
|  | } | ||||||
|  |  | ||||||
|  | The key property here is DownstreamHttpMethod which is set as POST and the ReRoute will only match on GET as set by UpstreamHttpMethod. | ||||||
|  |  | ||||||
|  | This feature can be useful when interacting with downstream apis that only support POST and you want to present some kind of RESTful interface. | ||||||
| @@ -1,6 +1,7 @@ | |||||||
| using Microsoft.AspNetCore.Builder; | using Microsoft.AspNetCore.Builder; | ||||||
| using Microsoft.AspNetCore.Hosting; | using Microsoft.AspNetCore.Hosting; | ||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
|  | using Microsoft.Extensions.Hosting; | ||||||
| using Ocelot.DependencyInjection; | using Ocelot.DependencyInjection; | ||||||
| using Ocelot.Middleware; | using Ocelot.Middleware; | ||||||
| using Ocelot.Provider.Kubernetes; | using Ocelot.Provider.Kubernetes; | ||||||
| @@ -18,7 +19,7 @@ namespace ApiGateway | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. |         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | ||||||
|         public void Configure(IApplicationBuilder app, IHostingEnvironment env) |         public void Configure(IApplicationBuilder app, IWebHostEnvironment env) | ||||||
|         { |         { | ||||||
|             if (env.IsDevelopment()) |             if (env.IsDevelopment()) | ||||||
|             { |             { | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Hosting; | |||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
| using Microsoft.Extensions.Configuration; | using Microsoft.Extensions.Configuration; | ||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
|  | using Microsoft.Extensions.Hosting; | ||||||
| using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||||
| using Microsoft.Extensions.Options; | using Microsoft.Extensions.Options; | ||||||
|  |  | ||||||
| @@ -28,7 +29,7 @@ namespace DownstreamService | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. |         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | ||||||
|         public void Configure(IApplicationBuilder app, IHostingEnvironment env) |         public void Configure(IApplicationBuilder app, IWebHostEnvironment env) | ||||||
|         { |         { | ||||||
|             if (env.IsDevelopment()) |             if (env.IsDevelopment()) | ||||||
|             { |             { | ||||||
|   | |||||||
| @@ -41,6 +41,7 @@ namespace Ocelot.Configuration.Builder | |||||||
|         private List<AddHeader> _addHeadersToUpstream; |         private List<AddHeader> _addHeadersToUpstream; | ||||||
|         private bool _dangerousAcceptAnyServerCertificateValidator; |         private bool _dangerousAcceptAnyServerCertificateValidator; | ||||||
|         private SecurityOptions _securityOptions; |         private SecurityOptions _securityOptions; | ||||||
|  |         private string _downstreamHttpMethod; | ||||||
|  |  | ||||||
|         public DownstreamReRouteBuilder() |         public DownstreamReRouteBuilder() | ||||||
|         { |         { | ||||||
| @@ -56,6 +57,12 @@ namespace Ocelot.Configuration.Builder | |||||||
|             return this; |             return this; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public DownstreamReRouteBuilder WithDownStreamHttpMethod(string method) | ||||||
|  |         { | ||||||
|  |             _downstreamHttpMethod = method; | ||||||
|  |             return this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         public DownstreamReRouteBuilder WithLoadBalancerOptions(LoadBalancerOptions loadBalancerOptions) |         public DownstreamReRouteBuilder WithLoadBalancerOptions(LoadBalancerOptions loadBalancerOptions) | ||||||
|         { |         { | ||||||
|             _loadBalancerOptions = loadBalancerOptions; |             _loadBalancerOptions = loadBalancerOptions; | ||||||
| @@ -282,7 +289,8 @@ namespace Ocelot.Configuration.Builder | |||||||
|                 _addHeadersToDownstream, |                 _addHeadersToDownstream, | ||||||
|                 _addHeadersToUpstream, |                 _addHeadersToUpstream, | ||||||
|                 _dangerousAcceptAnyServerCertificateValidator, |                 _dangerousAcceptAnyServerCertificateValidator, | ||||||
|                 _securityOptions); |                 _securityOptions, | ||||||
|  |                 _downstreamHttpMethod); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -138,6 +138,7 @@ namespace Ocelot.Configuration.Creator | |||||||
|                 .WithAddHeadersToUpstream(hAndRs.AddHeadersToUpstream) |                 .WithAddHeadersToUpstream(hAndRs.AddHeadersToUpstream) | ||||||
|                 .WithDangerousAcceptAnyServerCertificateValidator(fileReRoute.DangerousAcceptAnyServerCertificateValidator) |                 .WithDangerousAcceptAnyServerCertificateValidator(fileReRoute.DangerousAcceptAnyServerCertificateValidator) | ||||||
|                 .WithSecurityOptions(securityOptions) |                 .WithSecurityOptions(securityOptions) | ||||||
|  |                 .WithDownStreamHttpMethod(fileReRoute.DownstreamHttpMethod) | ||||||
|                 .Build(); |                 .Build(); | ||||||
|  |  | ||||||
|             return reRoute; |             return reRoute; | ||||||
|   | |||||||
| @@ -38,7 +38,8 @@ namespace Ocelot.Configuration | |||||||
|             List<AddHeader> addHeadersToDownstream, |             List<AddHeader> addHeadersToDownstream, | ||||||
|             List<AddHeader> addHeadersToUpstream, |             List<AddHeader> addHeadersToUpstream, | ||||||
|             bool dangerousAcceptAnyServerCertificateValidator, |             bool dangerousAcceptAnyServerCertificateValidator, | ||||||
|             SecurityOptions securityOptions) |             SecurityOptions securityOptions, | ||||||
|  |             string downstreamHttpMethod) | ||||||
|         { |         { | ||||||
|             DangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator; |             DangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator; | ||||||
|             AddHeadersToDownstream = addHeadersToDownstream; |             AddHeadersToDownstream = addHeadersToDownstream; | ||||||
| @@ -72,6 +73,7 @@ namespace Ocelot.Configuration | |||||||
|             LoadBalancerKey = loadBalancerKey; |             LoadBalancerKey = loadBalancerKey; | ||||||
|             AddHeadersToUpstream = addHeadersToUpstream; |             AddHeadersToUpstream = addHeadersToUpstream; | ||||||
|             SecurityOptions = securityOptions; |             SecurityOptions = securityOptions; | ||||||
|  |             DownstreamHttpMethod = downstreamHttpMethod; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public string Key { get; } |         public string Key { get; } | ||||||
| @@ -106,5 +108,6 @@ namespace Ocelot.Configuration | |||||||
|         public List<AddHeader> AddHeadersToUpstream { get; } |         public List<AddHeader> AddHeadersToUpstream { get; } | ||||||
|         public bool DangerousAcceptAnyServerCertificateValidator { get; } |         public bool DangerousAcceptAnyServerCertificateValidator { get; } | ||||||
|         public SecurityOptions SecurityOptions { get; } |         public SecurityOptions SecurityOptions { get; } | ||||||
|  |         public string DownstreamHttpMethod { get; } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ namespace Ocelot.Configuration.File | |||||||
|         public string DownstreamPathTemplate { get; set; } |         public string DownstreamPathTemplate { get; set; } | ||||||
|         public string UpstreamPathTemplate { get; set; } |         public string UpstreamPathTemplate { get; set; } | ||||||
|         public List<string> UpstreamHttpMethod { get; set; } |         public List<string> UpstreamHttpMethod { get; set; } | ||||||
|  |         public string DownstreamHttpMethod { get; set; } | ||||||
|         public Dictionary<string, string> AddHeadersToRequest { get; set; } |         public Dictionary<string, string> AddHeadersToRequest { get; set; } | ||||||
|         public Dictionary<string, string> UpstreamHeaderTransform { get; set; } |         public Dictionary<string, string> UpstreamHeaderTransform { get; set; } | ||||||
|         public Dictionary<string, string> DownstreamHeaderTransform { get; set; } |         public Dictionary<string, string> DownstreamHeaderTransform { get; set; } | ||||||
|   | |||||||
| @@ -1,12 +1,13 @@ | |||||||
| namespace Ocelot.Request.Mapper | namespace Ocelot.Request.Mapper | ||||||
| { | { | ||||||
|     using Microsoft.AspNetCore.Http; |     using Microsoft.AspNetCore.Http; | ||||||
|  |     using Ocelot.Configuration; | ||||||
|     using Ocelot.Responses; |     using Ocelot.Responses; | ||||||
|     using System.Net.Http; |     using System.Net.Http; | ||||||
|     using System.Threading.Tasks; |     using System.Threading.Tasks; | ||||||
|  |  | ||||||
|     public interface IRequestMapper |     public interface IRequestMapper | ||||||
|     { |     { | ||||||
|         Task<Response<HttpRequestMessage>> Map(HttpRequest request); |         Task<Response<HttpRequestMessage>> Map(HttpRequest request, DownstreamReRoute downstreamReRoute); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
|     using Microsoft.AspNetCore.Http; |     using Microsoft.AspNetCore.Http; | ||||||
|     using Microsoft.AspNetCore.Http.Extensions; |     using Microsoft.AspNetCore.Http.Extensions; | ||||||
|     using Microsoft.Extensions.Primitives; |     using Microsoft.Extensions.Primitives; | ||||||
|  |     using Ocelot.Configuration; | ||||||
|     using Ocelot.Responses; |     using Ocelot.Responses; | ||||||
|     using System; |     using System; | ||||||
|     using System.Collections.Generic; |     using System.Collections.Generic; | ||||||
| @@ -15,14 +16,14 @@ | |||||||
|     { |     { | ||||||
|         private readonly string[] _unsupportedHeaders = { "host" }; |         private readonly string[] _unsupportedHeaders = { "host" }; | ||||||
|  |  | ||||||
|         public async Task<Response<HttpRequestMessage>> Map(HttpRequest request) |         public async Task<Response<HttpRequestMessage>> Map(HttpRequest request, DownstreamReRoute downstreamReRoute) | ||||||
|         { |         { | ||||||
|             try |             try | ||||||
|             { |             { | ||||||
|                 var requestMessage = new HttpRequestMessage() |                 var requestMessage = new HttpRequestMessage() | ||||||
|                 { |                 { | ||||||
|                     Content = await MapContent(request), |                     Content = await MapContent(request), | ||||||
|                     Method = MapMethod(request), |                     Method = MapMethod(request, downstreamReRoute), | ||||||
|                     RequestUri = MapUri(request) |                     RequestUri = MapUri(request) | ||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
| @@ -71,8 +72,13 @@ | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private HttpMethod MapMethod(HttpRequest request) |         private HttpMethod MapMethod(HttpRequest request, DownstreamReRoute downstreamReRoute) | ||||||
|         { |         { | ||||||
|  |             if (!string.IsNullOrEmpty(downstreamReRoute?.DownstreamHttpMethod)) | ||||||
|  |             { | ||||||
|  |                 return new HttpMethod(downstreamReRoute.DownstreamHttpMethod); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             return new HttpMethod(request.Method); |             return new HttpMethod(request.Method); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -52,6 +52,7 @@ namespace Ocelot.Request.Middleware | |||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             _request.RequestUri = uriBuilder.Uri; |             _request.RequestUri = uriBuilder.Uri; | ||||||
|  |             _request.Method = new HttpMethod(Method); | ||||||
|             return _request; |             return _request; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ namespace Ocelot.Request.Middleware | |||||||
|  |  | ||||||
|         public async Task Invoke(DownstreamContext context) |         public async Task Invoke(DownstreamContext context) | ||||||
|         { |         { | ||||||
|             var downstreamRequest = await _requestMapper.Map(context.HttpContext.Request); |             var downstreamRequest = await _requestMapper.Map(context.HttpContext.Request, context.DownstreamReRoute); | ||||||
|  |  | ||||||
|             if (downstreamRequest.IsError) |             if (downstreamRequest.IsError) | ||||||
|             { |             { | ||||||
|   | |||||||
| @@ -1,4 +1,3 @@ | |||||||
| using Microsoft.AspNetCore.Builder; |  | ||||||
| using Ocelot.Middleware.Pipeline; | using Ocelot.Middleware.Pipeline; | ||||||
|  |  | ||||||
| namespace Ocelot.Request.Middleware | namespace Ocelot.Request.Middleware | ||||||
|   | |||||||
							
								
								
									
										158
									
								
								test/Ocelot.AcceptanceTests/MethodTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								test/Ocelot.AcceptanceTests/MethodTests.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | |||||||
|  | namespace Ocelot.AcceptanceTests | ||||||
|  | { | ||||||
|  |     using Microsoft.AspNetCore.Http; | ||||||
|  |     using Ocelot.Configuration.File; | ||||||
|  |     using System; | ||||||
|  |     using System.Collections.Generic; | ||||||
|  |     using System.IO; | ||||||
|  |     using System.Net; | ||||||
|  |     using System.Net.Http; | ||||||
|  |     using TestStack.BDDfy; | ||||||
|  |     using Xunit; | ||||||
|  |  | ||||||
|  |     public class MethodTests : IDisposable | ||||||
|  |     { | ||||||
|  |         private readonly Steps _steps; | ||||||
|  |         private readonly ServiceHandler _serviceHandler; | ||||||
|  |  | ||||||
|  |         public MethodTests() | ||||||
|  |         { | ||||||
|  |             _serviceHandler = new ServiceHandler(); | ||||||
|  |             _steps = new Steps(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         [Fact] | ||||||
|  |         public void should_return_response_200_when_get_converted_to_post() | ||||||
|  |         { | ||||||
|  |             var configuration = new FileConfiguration | ||||||
|  |             { | ||||||
|  |                 ReRoutes = new List<FileReRoute> | ||||||
|  |                     { | ||||||
|  |                         new FileReRoute | ||||||
|  |                         { | ||||||
|  |                             DownstreamPathTemplate = "/{url}", | ||||||
|  |                             DownstreamScheme = "http", | ||||||
|  |                             UpstreamPathTemplate = "/{url}", | ||||||
|  |                             UpstreamHttpMethod = new List<string> { "Get" }, | ||||||
|  |                             DownstreamHostAndPorts = new List<FileHostAndPort> | ||||||
|  |                             { | ||||||
|  |                                 new FileHostAndPort | ||||||
|  |                                 { | ||||||
|  |                                     Host = "localhost", | ||||||
|  |                                     Port = 53171, | ||||||
|  |                                 }, | ||||||
|  |                             }, | ||||||
|  |                             DownstreamHttpMethod = "POST", | ||||||
|  |                         }, | ||||||
|  |                     }, | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:53171/", "/", "POST")) | ||||||
|  |                 .And(x => _steps.GivenThereIsAConfiguration(configuration)) | ||||||
|  |                 .And(x => _steps.GivenOcelotIsRunning()) | ||||||
|  |                 .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) | ||||||
|  |                 .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) | ||||||
|  |                 .BDDfy(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         [Fact] | ||||||
|  |         public void should_return_response_200_when_get_converted_to_post_with_content() | ||||||
|  |         { | ||||||
|  |             var configuration = new FileConfiguration | ||||||
|  |             { | ||||||
|  |                 ReRoutes = new List<FileReRoute> | ||||||
|  |                 { | ||||||
|  |                     new FileReRoute | ||||||
|  |                     { | ||||||
|  |                         DownstreamPathTemplate = "/{url}", | ||||||
|  |                         DownstreamScheme = "http", | ||||||
|  |                         UpstreamPathTemplate = "/{url}", | ||||||
|  |                         UpstreamHttpMethod = new List<string> { "Get" }, | ||||||
|  |                         DownstreamHostAndPorts = new List<FileHostAndPort> | ||||||
|  |                         { | ||||||
|  |                             new FileHostAndPort | ||||||
|  |                             { | ||||||
|  |                                 Host = "localhost", | ||||||
|  |                                 Port = 53271, | ||||||
|  |                             }, | ||||||
|  |                         }, | ||||||
|  |                         DownstreamHttpMethod = "POST", | ||||||
|  |                     }, | ||||||
|  |                 }, | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             const string expected = "here is some content"; | ||||||
|  |             var httpContent = new StringContent(expected); | ||||||
|  |  | ||||||
|  |             this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:53271/", "/", "POST")) | ||||||
|  |                 .And(x => _steps.GivenThereIsAConfiguration(configuration)) | ||||||
|  |                 .And(x => _steps.GivenOcelotIsRunning()) | ||||||
|  |                 .When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent)) | ||||||
|  |                 .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) | ||||||
|  |                 .And(_ => _steps.ThenTheResponseBodyShouldBe(expected)) | ||||||
|  |                 .BDDfy(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         [Fact] | ||||||
|  |         public void should_return_response_200_when_get_converted_to_get_with_content() | ||||||
|  |         { | ||||||
|  |             var configuration = new FileConfiguration | ||||||
|  |             { | ||||||
|  |                 ReRoutes = new List<FileReRoute> | ||||||
|  |                 { | ||||||
|  |                     new FileReRoute | ||||||
|  |                     { | ||||||
|  |                         DownstreamPathTemplate = "/{url}", | ||||||
|  |                         DownstreamScheme = "http", | ||||||
|  |                         UpstreamPathTemplate = "/{url}", | ||||||
|  |                         UpstreamHttpMethod = new List<string> { "Post" }, | ||||||
|  |                         DownstreamHostAndPorts = new List<FileHostAndPort> | ||||||
|  |                         { | ||||||
|  |                             new FileHostAndPort | ||||||
|  |                             { | ||||||
|  |                                 Host = "localhost", | ||||||
|  |                                 Port = 53272, | ||||||
|  |                             }, | ||||||
|  |                         }, | ||||||
|  |                         DownstreamHttpMethod = "GET", | ||||||
|  |                     }, | ||||||
|  |                 }, | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             const string expected = "here is some content"; | ||||||
|  |             var httpContent = new StringContent(expected); | ||||||
|  |  | ||||||
|  |             this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:53272/", "/", "GET")) | ||||||
|  |                 .And(x => _steps.GivenThereIsAConfiguration(configuration)) | ||||||
|  |                 .And(x => _steps.GivenOcelotIsRunning()) | ||||||
|  |                 .When(x => _steps.WhenIPostUrlOnTheApiGateway("/", httpContent)) | ||||||
|  |                 .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) | ||||||
|  |                 .And(_ => _steps.ThenTheResponseBodyShouldBe(expected)) | ||||||
|  |                 .BDDfy(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string expected) | ||||||
|  |         { | ||||||
|  |             _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context => | ||||||
|  |             { | ||||||
|  |                 if (context.Request.Method == expected) | ||||||
|  |                 { | ||||||
|  |                     context.Response.StatusCode = 200; | ||||||
|  |                     var reader = new StreamReader(context.Request.Body); | ||||||
|  |                     var body = await reader.ReadToEndAsync(); | ||||||
|  |                     await context.Response.WriteAsync(body); | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     context.Response.StatusCode = 500; | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public void Dispose() | ||||||
|  |         { | ||||||
|  |             _serviceHandler.Dispose(); | ||||||
|  |             _steps.Dispose(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -909,6 +909,18 @@ namespace Ocelot.AcceptanceTests | |||||||
|             _response = _ocelotClient.GetAsync(url).Result; |             _response = _ocelotClient.GetAsync(url).Result; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public void WhenIGetUrlOnTheApiGateway(string url, HttpContent content) | ||||||
|  |         { | ||||||
|  |             var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, url) {Content = content}; | ||||||
|  |             _response = _ocelotClient.SendAsync(httpRequestMessage).Result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public void WhenIPostUrlOnTheApiGateway(string url, HttpContent content) | ||||||
|  |         { | ||||||
|  |             var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, url) { Content = content }; | ||||||
|  |             _response = _ocelotClient.SendAsync(httpRequestMessage).Result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         public void WhenIGetUrlOnTheApiGateway(string url, string cookie, string value) |         public void WhenIGetUrlOnTheApiGateway(string url, string cookie, string value) | ||||||
|         { |         { | ||||||
|             var request = _ocelotServer.CreateRequest(url); |             var request = _ocelotServer.CreateRequest(url); | ||||||
|   | |||||||
| @@ -1,6 +1,4 @@ | |||||||
| using Ocelot.Middleware; | namespace Ocelot.UnitTests.Request | ||||||
|  |  | ||||||
| namespace Ocelot.UnitTests.Request |  | ||||||
| { | { | ||||||
|     using Microsoft.AspNetCore.Http; |     using Microsoft.AspNetCore.Http; | ||||||
|     using Moq; |     using Moq; | ||||||
| @@ -9,9 +7,12 @@ namespace Ocelot.UnitTests.Request | |||||||
|     using Ocelot.Request.Creator; |     using Ocelot.Request.Creator; | ||||||
|     using Ocelot.Request.Mapper; |     using Ocelot.Request.Mapper; | ||||||
|     using Ocelot.Request.Middleware; |     using Ocelot.Request.Middleware; | ||||||
|  |     using Ocelot.Configuration.Builder; | ||||||
|  |     using Ocelot.Middleware; | ||||||
|     using Ocelot.Responses; |     using Ocelot.Responses; | ||||||
|     using Shouldly; |     using Shouldly; | ||||||
|     using System.Net.Http; |     using System.Net.Http; | ||||||
|  |     using Ocelot.Configuration; | ||||||
|     using TestStack.BDDfy; |     using TestStack.BDDfy; | ||||||
|     using Xunit; |     using Xunit; | ||||||
|  |  | ||||||
| @@ -65,6 +66,20 @@ namespace Ocelot.UnitTests.Request | |||||||
|                 .Then(_ => ThenTheContexRequestIsMappedToADownstreamRequest()) |                 .Then(_ => ThenTheContexRequestIsMappedToADownstreamRequest()) | ||||||
|                 .And(_ => ThenTheDownstreamRequestIsStored()) |                 .And(_ => ThenTheDownstreamRequestIsStored()) | ||||||
|                 .And(_ => ThenTheNextMiddlewareIsInvoked()) |                 .And(_ => ThenTheNextMiddlewareIsInvoked()) | ||||||
|  |                 .And(_ => ThenTheDownstreamRequestMethodIs("GET")) | ||||||
|  |                 .BDDfy(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         [Fact] | ||||||
|  |         public void Should_map_downstream_reroute_method_to_downstream_request() | ||||||
|  |         { | ||||||
|  |             this.Given(_ => GivenTheHttpContextContainsARequest()) | ||||||
|  |                 .And(_ => GivenTheMapperWillReturnAMappedRequest()) | ||||||
|  |                 .When(_ => WhenTheMiddlewareIsInvoked()) | ||||||
|  |                 .Then(_ => ThenTheContexRequestIsMappedToADownstreamRequest()) | ||||||
|  |                 .And(_ => ThenTheDownstreamRequestIsStored()) | ||||||
|  |                 .And(_ => ThenTheNextMiddlewareIsInvoked()) | ||||||
|  |                 .And(_ => ThenTheDownstreamRequestMethodIs("GET")) | ||||||
|                 .BDDfy(); |                 .BDDfy(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -80,6 +95,11 @@ namespace Ocelot.UnitTests.Request | |||||||
|                 .BDDfy(); |                 .BDDfy(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         private void ThenTheDownstreamRequestMethodIs(string expected) | ||||||
|  |         { | ||||||
|  |             _downstreamContext.DownstreamRequest.Method.ShouldBe(expected); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         private void GivenTheHttpContextContainsARequest() |         private void GivenTheHttpContextContainsARequest() | ||||||
|         { |         { | ||||||
|             _httpContext |             _httpContext | ||||||
| @@ -92,7 +112,7 @@ namespace Ocelot.UnitTests.Request | |||||||
|             _mappedRequest = new OkResponse<HttpRequestMessage>(new HttpRequestMessage(HttpMethod.Get, "http://www.bbc.co.uk")); |             _mappedRequest = new OkResponse<HttpRequestMessage>(new HttpRequestMessage(HttpMethod.Get, "http://www.bbc.co.uk")); | ||||||
|  |  | ||||||
|             _requestMapper |             _requestMapper | ||||||
|                 .Setup(rm => rm.Map(It.IsAny<HttpRequest>())) |                 .Setup(rm => rm.Map(It.IsAny<HttpRequest>(), It.IsAny<DownstreamReRoute>())) | ||||||
|                 .ReturnsAsync(_mappedRequest); |                 .ReturnsAsync(_mappedRequest); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -101,7 +121,7 @@ namespace Ocelot.UnitTests.Request | |||||||
|             _mappedRequest = new ErrorResponse<HttpRequestMessage>(new UnmappableRequestError(new System.Exception("boooom!"))); |             _mappedRequest = new ErrorResponse<HttpRequestMessage>(new UnmappableRequestError(new System.Exception("boooom!"))); | ||||||
|  |  | ||||||
|             _requestMapper |             _requestMapper | ||||||
|                 .Setup(rm => rm.Map(It.IsAny<HttpRequest>())) |                 .Setup(rm => rm.Map(It.IsAny<HttpRequest>(), It.IsAny<DownstreamReRoute>())) | ||||||
|                 .ReturnsAsync(_mappedRequest); |                 .ReturnsAsync(_mappedRequest); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -112,7 +132,7 @@ namespace Ocelot.UnitTests.Request | |||||||
|  |  | ||||||
|         private void ThenTheContexRequestIsMappedToADownstreamRequest() |         private void ThenTheContexRequestIsMappedToADownstreamRequest() | ||||||
|         { |         { | ||||||
|             _requestMapper.Verify(rm => rm.Map(_httpRequest.Object), Times.Once); |             _requestMapper.Verify(rm => rm.Map(_httpRequest.Object, _downstreamContext.DownstreamReRoute), Times.Once); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private void ThenTheDownstreamRequestIsStored() |         private void ThenTheDownstreamRequestIsStored() | ||||||
|   | |||||||
| @@ -13,6 +13,8 @@ | |||||||
|     using System.Security.Cryptography; |     using System.Security.Cryptography; | ||||||
|     using System.Text; |     using System.Text; | ||||||
|     using System.Threading.Tasks; |     using System.Threading.Tasks; | ||||||
|  |     using Ocelot.Configuration; | ||||||
|  |     using Ocelot.Configuration.Builder; | ||||||
|     using TestStack.BDDfy; |     using TestStack.BDDfy; | ||||||
|     using Xunit; |     using Xunit; | ||||||
|  |  | ||||||
| @@ -27,6 +29,8 @@ | |||||||
|  |  | ||||||
|         private List<KeyValuePair<string, StringValues>> _inputHeaders = null; |         private List<KeyValuePair<string, StringValues>> _inputHeaders = null; | ||||||
|  |  | ||||||
|  |         private DownstreamReRoute _downstreamReRoute; | ||||||
|  |  | ||||||
|         public RequestMapperTests() |         public RequestMapperTests() | ||||||
|         { |         { | ||||||
|             _httpContext = new DefaultHttpContext(); |             _httpContext = new DefaultHttpContext(); | ||||||
| @@ -82,6 +86,21 @@ | |||||||
|                 .BDDfy(); |                 .BDDfy(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         [Theory] | ||||||
|  |         [InlineData("", "GET")] | ||||||
|  |         [InlineData(null, "GET")] | ||||||
|  |         [InlineData("POST", "POST")] | ||||||
|  |         public void Should_use_downstream_reroute_method_if_set(string input, string expected) | ||||||
|  |         { | ||||||
|  |             this.Given(_ => GivenTheInputRequestHasMethod("GET")) | ||||||
|  |                 .And(_ => GivenTheDownstreamReRouteMethodIs(input)) | ||||||
|  |                 .And(_ => GivenTheInputRequestHasAValidUri()) | ||||||
|  |                 .When(_ => WhenMapped()) | ||||||
|  |                 .Then(_ => ThenNoErrorIsReturned()) | ||||||
|  |                 .And(_ => ThenTheMappedRequestHasMethod(expected)) | ||||||
|  |                 .BDDfy(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         [Fact] |         [Fact] | ||||||
|         public void Should_map_all_headers() |         public void Should_map_all_headers() | ||||||
|         { |         { | ||||||
| @@ -154,16 +173,6 @@ | |||||||
|                 .BDDfy(); |                 .BDDfy(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private void GivenTheInputRequestHasNoContentLength() |  | ||||||
|         { |  | ||||||
|             _inputRequest.ContentLength = null; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void GivenTheInputRequestHasNoContentType() |  | ||||||
|         { |  | ||||||
|             _inputRequest.ContentType = null; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         [Fact] |         [Fact] | ||||||
|         public void Should_map_content_headers() |         public void Should_map_content_headers() | ||||||
|         { |         { | ||||||
| @@ -212,6 +221,22 @@ | |||||||
|                 .BDDfy(); |                 .BDDfy(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         private void GivenTheDownstreamReRouteMethodIs(string input) | ||||||
|  |         { | ||||||
|  |             _downstreamReRoute = new DownstreamReRouteBuilder().WithDownStreamHttpMethod(input).Build(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private void GivenTheInputRequestHasNoContentLength() | ||||||
|  |         { | ||||||
|  |             _inputRequest.ContentLength = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private void GivenTheInputRequestHasNoContentType() | ||||||
|  |         { | ||||||
|  |             _inputRequest.ContentType = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         private void ThenTheContentHeadersAreNotAddedToNonContentHeaders() |         private void ThenTheContentHeadersAreNotAddedToNonContentHeaders() | ||||||
|         { |         { | ||||||
|             _mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Disposition"); |             _mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Disposition"); | ||||||
| @@ -380,7 +405,7 @@ | |||||||
|  |  | ||||||
|         private async Task WhenMapped() |         private async Task WhenMapped() | ||||||
|         { |         { | ||||||
|             _mappedRequest = await _requestMapper.Map(_inputRequest); |             _mappedRequest = await _requestMapper.Map(_inputRequest, _downstreamReRoute); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private void ThenNoErrorIsReturned() |         private void ThenNoErrorIsReturned() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 TomPallister
					TomPallister