mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 18:32:51 +08:00
check which version of .net framework before creating http handler (#412)
* #405 needto check which version of .net we are using but cannot use compiler directives * #405 started puttig abstraction around static method to get frameworks so we can test this logic * #405 added test for all methods and tidied up tests * #405 made contains as ms docs are wrong, thanks to davidni for the heads up
This commit is contained in:
parent
b5a827cf70
commit
e636cefdb1
@ -48,6 +48,7 @@ namespace Ocelot.DependencyInjection
|
|||||||
using ServiceDiscovery.Providers;
|
using ServiceDiscovery.Providers;
|
||||||
using Steeltoe.Common.Discovery;
|
using Steeltoe.Common.Discovery;
|
||||||
using Pivotal.Discovery.Client;
|
using Pivotal.Discovery.Client;
|
||||||
|
using Ocelot.Request.Creator;
|
||||||
|
|
||||||
public class OcelotBuilder : IOcelotBuilder
|
public class OcelotBuilder : IOcelotBuilder
|
||||||
{
|
{
|
||||||
@ -161,6 +162,8 @@ namespace Ocelot.DependencyInjection
|
|||||||
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
|
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
|
||||||
_services.TryAddSingleton<IResponseAggregatorFactory, InMemoryResponseAggregatorFactory>();
|
_services.TryAddSingleton<IResponseAggregatorFactory, InMemoryResponseAggregatorFactory>();
|
||||||
_services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
|
_services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
|
||||||
|
_services.TryAddSingleton<IDownstreamRequestCreator, DownstreamRequestCreator>();
|
||||||
|
_services.TryAddSingleton<IFrameworkDescription, FrameworkDescription>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
|
public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
|
||||||
|
12
src/Ocelot/Infrastructure/FrameworkDescription.cs
Normal file
12
src/Ocelot/Infrastructure/FrameworkDescription.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ocelot.Infrastructure
|
||||||
|
{
|
||||||
|
public class FrameworkDescription : IFrameworkDescription
|
||||||
|
{
|
||||||
|
public string Get()
|
||||||
|
{
|
||||||
|
return RuntimeInformation.FrameworkDescription;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
src/Ocelot/Infrastructure/IFrameworkDescription.cs
Normal file
7
src/Ocelot/Infrastructure/IFrameworkDescription.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Ocelot.Infrastructure
|
||||||
|
{
|
||||||
|
public interface IFrameworkDescription
|
||||||
|
{
|
||||||
|
string Get();
|
||||||
|
}
|
||||||
|
}
|
42
src/Ocelot/Request/Creator/DownstreamRequestCreator.cs
Normal file
42
src/Ocelot/Request/Creator/DownstreamRequestCreator.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
namespace Ocelot.Request.Creator
|
||||||
|
{
|
||||||
|
using System.Net.Http;
|
||||||
|
using Ocelot.Request.Middleware;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Ocelot.Infrastructure;
|
||||||
|
|
||||||
|
public class DownstreamRequestCreator : IDownstreamRequestCreator
|
||||||
|
{
|
||||||
|
private readonly IFrameworkDescription _framework;
|
||||||
|
private const string dotNetFramework = ".NET Framework";
|
||||||
|
|
||||||
|
public DownstreamRequestCreator(IFrameworkDescription framework)
|
||||||
|
{
|
||||||
|
_framework = framework;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DownstreamRequest Create(HttpRequestMessage request)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* According to https://tools.ietf.org/html/rfc7231
|
||||||
|
* GET,HEAD,DELETE,CONNECT,TRACE
|
||||||
|
* Can have body but server can reject the request.
|
||||||
|
* And MS HttpClient in Full Framework actually rejects it.
|
||||||
|
* see #366 issue
|
||||||
|
**/
|
||||||
|
|
||||||
|
if(_framework.Get().Contains(dotNetFramework))
|
||||||
|
{
|
||||||
|
if (request.Method == HttpMethod.Get ||
|
||||||
|
request.Method == HttpMethod.Head ||
|
||||||
|
request.Method == HttpMethod.Delete ||
|
||||||
|
request.Method == HttpMethod.Trace)
|
||||||
|
{
|
||||||
|
request.Content = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DownstreamRequest(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/Ocelot/Request/Creator/IDownstreamRequestCreator.cs
Normal file
10
src/Ocelot/Request/Creator/IDownstreamRequestCreator.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace Ocelot.Request.Creator
|
||||||
|
{
|
||||||
|
using System.Net.Http;
|
||||||
|
using Ocelot.Request.Middleware;
|
||||||
|
|
||||||
|
public interface IDownstreamRequestCreator
|
||||||
|
{
|
||||||
|
DownstreamRequest Create(HttpRequestMessage request);
|
||||||
|
}
|
||||||
|
}
|
@ -48,22 +48,6 @@ namespace Ocelot.Request.Middleware
|
|||||||
Scheme = Scheme
|
Scheme = Scheme
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* According to https://tools.ietf.org/html/rfc7231
|
|
||||||
* GET,HEAD,DELETE,CONNECT,TRACE
|
|
||||||
* Can have body but server can reject the request.
|
|
||||||
* And MS HttpClient in Full Framework actually rejects it.
|
|
||||||
* see #366 issue
|
|
||||||
**/
|
|
||||||
#if NET461 || NET462 || NET47 || NET471 || NET472
|
|
||||||
if (_request.Method == HttpMethod.Get ||
|
|
||||||
_request.Method == HttpMethod.Head ||
|
|
||||||
_request.Method == HttpMethod.Delete ||
|
|
||||||
_request.Method == HttpMethod.Trace)
|
|
||||||
{
|
|
||||||
_request.Content = null;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
_request.RequestUri = uriBuilder.Uri;
|
_request.RequestUri = uriBuilder.Uri;
|
||||||
return _request;
|
return _request;
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,28 @@
|
|||||||
namespace Ocelot.Request.Middleware
|
namespace Ocelot.Request.Middleware
|
||||||
{
|
{
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Request.Creator;
|
||||||
|
|
||||||
public class DownstreamRequestInitialiserMiddleware : OcelotMiddleware
|
public class DownstreamRequestInitialiserMiddleware : OcelotMiddleware
|
||||||
{
|
{
|
||||||
private readonly OcelotRequestDelegate _next;
|
private readonly OcelotRequestDelegate _next;
|
||||||
private readonly Mapper.IRequestMapper _requestMapper;
|
private readonly Mapper.IRequestMapper _requestMapper;
|
||||||
|
private readonly IDownstreamRequestCreator _creator;
|
||||||
|
|
||||||
public DownstreamRequestInitialiserMiddleware(OcelotRequestDelegate next,
|
public DownstreamRequestInitialiserMiddleware(OcelotRequestDelegate next,
|
||||||
IOcelotLoggerFactory loggerFactory,
|
IOcelotLoggerFactory loggerFactory,
|
||||||
Mapper.IRequestMapper requestMapper)
|
Mapper.IRequestMapper requestMapper,
|
||||||
|
IDownstreamRequestCreator creator)
|
||||||
:base(loggerFactory.CreateLogger<DownstreamRequestInitialiserMiddleware>())
|
:base(loggerFactory.CreateLogger<DownstreamRequestInitialiserMiddleware>())
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
_requestMapper = requestMapper;
|
_requestMapper = requestMapper;
|
||||||
|
_creator = creator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(DownstreamContext context)
|
public async Task Invoke(DownstreamContext context)
|
||||||
@ -31,7 +34,7 @@ namespace Ocelot.Request.Middleware
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.DownstreamRequest = new DownstreamRequest(downstreamRequest.Data);
|
context.DownstreamRequest = _creator.Create(downstreamRequest.Data);
|
||||||
|
|
||||||
await _next.Invoke(context);
|
await _next.Invoke(context);
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,8 @@
|
|||||||
"HttpHandlerOptions": {
|
"HttpHandlerOptions": {
|
||||||
"AllowAutoRedirect": true,
|
"AllowAutoRedirect": true,
|
||||||
"UseCookieContainer": true,
|
"UseCookieContainer": true,
|
||||||
"UseTracing": true
|
"UseTracing": true,
|
||||||
|
"UseProxy": true
|
||||||
},
|
},
|
||||||
"QoSOptions": {
|
"QoSOptions": {
|
||||||
"ExceptionsAllowedBeforeBreaking": 3,
|
"ExceptionsAllowedBeforeBreaking": 3,
|
||||||
|
@ -28,6 +28,15 @@
|
|||||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="idsrv3test.pfx">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.3" />
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Moq;
|
||||||
|
using Ocelot.Infrastructure;
|
||||||
|
using Ocelot.Request.Creator;
|
||||||
|
using Ocelot.Request.Middleware;
|
||||||
|
using Shouldly;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Request.Creator
|
||||||
|
{
|
||||||
|
public class DownstreamRequestCreatorTests
|
||||||
|
{
|
||||||
|
private Mock<IFrameworkDescription> _framework;
|
||||||
|
private DownstreamRequestCreator _downstreamRequestCreator;
|
||||||
|
private HttpRequestMessage _request;
|
||||||
|
private DownstreamRequest _result;
|
||||||
|
|
||||||
|
public DownstreamRequestCreatorTests()
|
||||||
|
{
|
||||||
|
_framework = new Mock<IFrameworkDescription>();
|
||||||
|
_downstreamRequestCreator = new DownstreamRequestCreator(_framework.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_create_downstream_request()
|
||||||
|
{
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, "http://www.test.com");
|
||||||
|
var content = new StringContent("test");
|
||||||
|
request.Content = content;
|
||||||
|
|
||||||
|
this.Given(_ => GivenTheFrameworkIs(""))
|
||||||
|
.And(_ => GivenTheRequestIs(request))
|
||||||
|
.When(_ => WhenICreate())
|
||||||
|
.Then(_ => ThenTheDownstreamRequestHasABody())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_remove_body_for_http_methods()
|
||||||
|
{
|
||||||
|
var methods = new List<HttpMethod> { HttpMethod.Get, HttpMethod.Head, HttpMethod.Delete, HttpMethod.Trace };
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, "http://www.test.com");
|
||||||
|
var content = new StringContent("test");
|
||||||
|
request.Content = content;
|
||||||
|
|
||||||
|
methods.ForEach(m => {
|
||||||
|
this.Given(_ => GivenTheFrameworkIs(".NET Framework"))
|
||||||
|
.And(_ => GivenTheRequestIs(request))
|
||||||
|
.When(_ => WhenICreate())
|
||||||
|
.Then(_ => ThenTheDownstreamRequestDoesNotHaveABody())
|
||||||
|
.BDDfy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheFrameworkIs(string framework)
|
||||||
|
{
|
||||||
|
_framework.Setup(x => x.Get()).Returns(framework);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheRequestIs(HttpRequestMessage request)
|
||||||
|
{
|
||||||
|
_request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenICreate()
|
||||||
|
{
|
||||||
|
_result = _downstreamRequestCreator.Create(_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ThenTheDownstreamRequestHasABody()
|
||||||
|
{
|
||||||
|
_result.ShouldNotBeNull();
|
||||||
|
_result.Method.ToLower().ShouldBe("get");
|
||||||
|
_result.Scheme.ToLower().ShouldBe("http");
|
||||||
|
_result.Host.ToLower().ShouldBe("www.test.com");
|
||||||
|
var resultContent = await _result.ToHttpRequestMessage().Content.ReadAsStringAsync();
|
||||||
|
resultContent.ShouldBe("test");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheDownstreamRequestDoesNotHaveABody()
|
||||||
|
{
|
||||||
|
_result.ShouldNotBeNull();
|
||||||
|
_result.Method.ToLower().ShouldBe("get");
|
||||||
|
_result.Scheme.ToLower().ShouldBe("http");
|
||||||
|
_result.Host.ToLower().ShouldBe("www.test.com");
|
||||||
|
_result.ToHttpRequestMessage().Content.ShouldBeNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,8 @@ namespace Ocelot.UnitTests.Request
|
|||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
|
using Ocelot.Request.Creator;
|
||||||
|
using Ocelot.Infrastructure;
|
||||||
|
|
||||||
public class DownstreamRequestInitialiserMiddlewareTests
|
public class DownstreamRequestInitialiserMiddlewareTests
|
||||||
{
|
{
|
||||||
@ -50,7 +52,8 @@ namespace Ocelot.UnitTests.Request
|
|||||||
_middleware = new DownstreamRequestInitialiserMiddleware(
|
_middleware = new DownstreamRequestInitialiserMiddleware(
|
||||||
_next.Object,
|
_next.Object,
|
||||||
_loggerFactory.Object,
|
_loggerFactory.Object,
|
||||||
_requestMapper.Object);
|
_requestMapper.Object,
|
||||||
|
new DownstreamRequestCreator(new FrameworkDescription()));
|
||||||
|
|
||||||
_downstreamContext = new DownstreamContext(_httpContext.Object);
|
_downstreamContext = new DownstreamContext(_httpContext.Object);
|
||||||
}
|
}
|
||||||
|
BIN
test/Ocelot.UnitTests/idsrv3test.pfx
Normal file
BIN
test/Ocelot.UnitTests/idsrv3test.pfx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user