Feature/dont validate cached content headers (#406)

* #372 use period timespan to decide when client can make requests again

* #400 dont validate cached body headers
This commit is contained in:
Tom Pallister 2018-06-15 20:30:25 +01:00 committed by GitHub
parent 9979f8a4b8
commit 8e1a5ce827
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 505 additions and 435 deletions

View File

@ -88,7 +88,7 @@ namespace Ocelot.Cache.Middleware
foreach (var header in cached.ContentHeaders) foreach (var header in cached.ContentHeaders)
{ {
streamContent.Headers.Add(header.Key, header.Value); streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
} }
return new DownstreamResponse(streamContent, cached.StatusCode, cached.Headers.ToList()); return new DownstreamResponse(streamContent, cached.StatusCode, cached.Headers.ToList());

View File

@ -51,7 +51,7 @@ namespace Ocelot.AcceptanceTests
} }
}; };
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura")) this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
@ -65,6 +65,50 @@ namespace Ocelot.AcceptanceTests
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_return_cached_response_with_expires_header()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 52839,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
FileCacheOptions = new FileCacheOptions
{
TtlSeconds = 100
}
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:52839", 200, "Hello from Laura", "Expires", "-1"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.Given(x => x.GivenTheServiceNowReturns("http://localhost:52839", 200, "Hello from Tom"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => _steps.ThenTheContentLengthIs(16))
.And(x => _steps.ThenTheResponseBodyHeaderIs("Expires", "-1"))
.BDDfy();
}
[Fact] [Fact]
public void should_return_cached_response_when_using_jsonserialized_cache() public void should_return_cached_response_when_using_jsonserialized_cache()
{ {
@ -94,7 +138,7 @@ namespace Ocelot.AcceptanceTests
} }
}; };
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura")) this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingJsonSerializedCache()) .And(x => _steps.GivenOcelotIsRunningUsingJsonSerializedCache())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
@ -136,7 +180,7 @@ namespace Ocelot.AcceptanceTests
} }
}; };
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura")) this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
@ -158,10 +202,10 @@ namespace Ocelot.AcceptanceTests
private void GivenTheServiceNowReturns(string url, int statusCode, string responseBody) private void GivenTheServiceNowReturns(string url, int statusCode, string responseBody)
{ {
_builder.Dispose(); _builder.Dispose();
GivenThereIsAServiceRunningOn(url, statusCode, responseBody); GivenThereIsAServiceRunningOn(url, statusCode, responseBody, null, null);
} }
private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody, string key, string value)
{ {
_builder = new WebHostBuilder() _builder = new WebHostBuilder()
.UseUrls(url) .UseUrls(url)
@ -173,6 +217,10 @@ namespace Ocelot.AcceptanceTests
{ {
app.Run(async context => app.Run(async context =>
{ {
if(!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(key))
{
context.Response.Headers.Add(key, value);
}
context.Response.StatusCode = statusCode; context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody); await context.Response.WriteAsync(responseBody);
}); });

View File

@ -392,6 +392,12 @@ namespace Ocelot.AcceptanceTests
header.First().ShouldBe(value); header.First().ShouldBe(value);
} }
public void ThenTheResponseBodyHeaderIs(string key, string value)
{
var header = _response.Content.Headers.GetValues(key);
header.First().ShouldBe(value);
}
public void ThenTheTraceHeaderIsSet(string key) public void ThenTheTraceHeaderIsSet(string key)
{ {
var header = _response.Headers.GetValues(key); var header = _response.Headers.GetValues(key);

View File

@ -63,10 +63,26 @@
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_returned_cached_item_when_it_is_in_cache_expires_header()
{
var contentHeaders = new Dictionary<string, IEnumerable<string>>
{
{ "Expires", new List<string> { "-1" } }
};
var cachedResponse = new CachedResponse(HttpStatusCode.OK, new Dictionary<string, IEnumerable<string>>(), "", contentHeaders);
this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
.And(x => x.GivenTheDownstreamRouteIs())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheCacheGetIsCalledCorrectly())
.BDDfy();
}
[Fact] [Fact]
public void should_continue_with_pipeline_and_cache_response() public void should_continue_with_pipeline_and_cache_response()
{ {
this.Given(x => x.GivenResponseIsNotCached()) this.Given(x => x.GivenResponseIsNotCached(new HttpResponseMessage()))
.And(x => x.GivenTheDownstreamRouteIs()) .And(x => x.GivenTheDownstreamRouteIs())
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheCacheAddIsCalledCorrectly()) .Then(x => x.ThenTheCacheAddIsCalledCorrectly())
@ -87,9 +103,9 @@
.Returns(_response); .Returns(_response);
} }
private void GivenResponseIsNotCached() private void GivenResponseIsNotCached(HttpResponseMessage responseMessage)
{ {
_downstreamContext.DownstreamResponse = new DownstreamResponse(new HttpResponseMessage()); _downstreamContext.DownstreamResponse = new DownstreamResponse(responseMessage);
} }
private void GivenTheDownstreamRouteIs() private void GivenTheDownstreamRouteIs()