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:
Tom Pallister 2018-06-20 20:44:38 +01:00 committed by GitHub
parent b5a827cf70
commit e636cefdb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 366 additions and 199 deletions

View File

@ -48,6 +48,7 @@ namespace Ocelot.DependencyInjection
using ServiceDiscovery.Providers;
using Steeltoe.Common.Discovery;
using Pivotal.Discovery.Client;
using Ocelot.Request.Creator;
public class OcelotBuilder : IOcelotBuilder
{
@ -161,6 +162,8 @@ namespace Ocelot.DependencyInjection
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
_services.TryAddSingleton<IResponseAggregatorFactory, InMemoryResponseAggregatorFactory>();
_services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
_services.TryAddSingleton<IDownstreamRequestCreator, DownstreamRequestCreator>();
_services.TryAddSingleton<IFrameworkDescription, FrameworkDescription>();
}
public IOcelotAdministrationBuilder AddAdministration(string path, string secret)

View File

@ -0,0 +1,12 @@
using System.Runtime.InteropServices;
namespace Ocelot.Infrastructure
{
public class FrameworkDescription : IFrameworkDescription
{
public string Get()
{
return RuntimeInformation.FrameworkDescription;
}
}
}

View File

@ -0,0 +1,7 @@
namespace Ocelot.Infrastructure
{
public interface IFrameworkDescription
{
string Get();
}
}

View 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);
}
}
}

View File

@ -0,0 +1,10 @@
namespace Ocelot.Request.Creator
{
using System.Net.Http;
using Ocelot.Request.Middleware;
public interface IDownstreamRequestCreator
{
DownstreamRequest Create(HttpRequestMessage request);
}
}

View File

@ -48,22 +48,6 @@ namespace Ocelot.Request.Middleware
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;
return _request;
}

View File

@ -1,25 +1,28 @@
namespace Ocelot.Request.Middleware
{
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging;
using Ocelot.Middleware;
using Ocelot.Request.Creator;
public class DownstreamRequestInitialiserMiddleware : OcelotMiddleware
{
private readonly OcelotRequestDelegate _next;
private readonly Mapper.IRequestMapper _requestMapper;
private readonly IDownstreamRequestCreator _creator;
public DownstreamRequestInitialiserMiddleware(OcelotRequestDelegate next,
IOcelotLoggerFactory loggerFactory,
Mapper.IRequestMapper requestMapper)
Mapper.IRequestMapper requestMapper,
IDownstreamRequestCreator creator)
:base(loggerFactory.CreateLogger<DownstreamRequestInitialiserMiddleware>())
{
_next = next;
_requestMapper = requestMapper;
_creator = creator;
}
public async Task Invoke(DownstreamContext context)
@ -31,7 +34,7 @@ namespace Ocelot.Request.Middleware
return;
}
context.DownstreamRequest = new DownstreamRequest(downstreamRequest.Data);
context.DownstreamRequest = _creator.Create(downstreamRequest.Data);
await _next.Invoke(context);
}

View File

@ -114,7 +114,8 @@
"HttpHandlerOptions": {
"AllowAutoRedirect": true,
"UseCookieContainer": true,
"UseTracing": true
"UseTracing": true,
"UseProxy": true
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,

View File

@ -28,6 +28,15 @@
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="idsrv3test.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.8" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.3" />

View File

@ -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();
}
}
}

View File

@ -14,6 +14,8 @@ namespace Ocelot.UnitTests.Request
using Ocelot.Responses;
using Ocelot.DownstreamRouteFinder.Middleware;
using Shouldly;
using Ocelot.Request.Creator;
using Ocelot.Infrastructure;
public class DownstreamRequestInitialiserMiddlewareTests
{
@ -50,7 +52,8 @@ namespace Ocelot.UnitTests.Request
_middleware = new DownstreamRequestInitialiserMiddleware(
_next.Object,
_loggerFactory.Object,
_requestMapper.Object);
_requestMapper.Object,
new DownstreamRequestCreator(new FrameworkDescription()));
_downstreamContext = new DownstreamContext(_httpContext.Object);
}

Binary file not shown.