-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cache by header value: a new Header property in (File)CacheOptions co…
…nfiguration of a route (#1172) @EngRajabi, Mohsen Rajabi (7): add header to file cache option fix private set fix <none> <none> fix build fail fix: fix review comment. add unit test for change @raman-m, Raman Maksimchuk (1): Update caching.rst @raman-m (7): Fix errors Fix errors Fix styling warnings Refactor tests Add Delimiter Refactor generator Add unit tests
- Loading branch information
Showing
12 changed files
with
187 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,43 @@ | ||
using Ocelot.Request.Middleware; | ||
using Ocelot.Configuration; | ||
using Ocelot.Request.Middleware; | ||
|
||
namespace Ocelot.Cache | ||
{ | ||
public class CacheKeyGenerator : ICacheKeyGenerator | ||
{ | ||
public string GenerateRequestCacheKey(DownstreamRequest downstreamRequest) | ||
private const char Delimiter = '-'; | ||
|
||
public async ValueTask<string> GenerateRequestCacheKey(DownstreamRequest downstreamRequest, DownstreamRoute downstreamRoute) | ||
{ | ||
var downStreamUrlKeyBuilder = new StringBuilder($"{downstreamRequest.Method}-{downstreamRequest.OriginalString}"); | ||
if (downstreamRequest.Content != null) | ||
var builder = new StringBuilder() | ||
.Append(downstreamRequest.Method) | ||
.Append(Delimiter) | ||
.Append(downstreamRequest.OriginalString); | ||
|
||
var cacheOptionsHeader = downstreamRoute?.CacheOptions?.Header; | ||
if (!string.IsNullOrEmpty(cacheOptionsHeader)) | ||
{ | ||
var header = downstreamRequest.Headers | ||
.FirstOrDefault(r => r.Key.Equals(cacheOptionsHeader, StringComparison.OrdinalIgnoreCase)) | ||
.Value?.FirstOrDefault(); | ||
|
||
if (!string.IsNullOrEmpty(header)) | ||
{ | ||
builder.Append(Delimiter) | ||
.Append(header); | ||
} | ||
} | ||
|
||
if (!downstreamRequest.HasContent) | ||
{ | ||
var requestContentString = Task.Run(async () => await downstreamRequest.Content.ReadAsStringAsync()).Result; | ||
downStreamUrlKeyBuilder.Append(requestContentString); | ||
return MD5Helper.GenerateMd5(builder.ToString()); | ||
} | ||
|
||
var hashedContent = MD5Helper.GenerateMd5(downStreamUrlKeyBuilder.ToString()); | ||
return hashedContent; | ||
var requestContentString = await downstreamRequest.ReadContentAsync(); | ||
builder.Append(Delimiter) | ||
.Append(requestContentString); | ||
|
||
return MD5Helper.GenerateMd5(builder.ToString()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
using Ocelot.Request.Middleware; | ||
using Ocelot.Configuration; | ||
using Ocelot.Request.Middleware; | ||
|
||
namespace Ocelot.Cache | ||
{ | ||
public interface ICacheKeyGenerator | ||
{ | ||
string GenerateRequestCacheKey(DownstreamRequest downstreamRequest); | ||
ValueTask<string> GenerateRequestCacheKey(DownstreamRequest downstreamRequest, DownstreamRoute downstreamRoute); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,122 @@ | ||
using Ocelot.Cache; | ||
using Ocelot.Configuration; | ||
using Ocelot.Configuration.Builder; | ||
using Ocelot.Request.Middleware; | ||
using System.Net.Http.Headers; | ||
|
||
namespace Ocelot.UnitTests.Cache | ||
{ | ||
public class CacheKeyGeneratorTests | ||
{ | ||
private readonly ICacheKeyGenerator _cacheKeyGenerator; | ||
private readonly DownstreamRequest _downstreamRequest; | ||
private readonly Mock<DownstreamRequest> _downstreamRequest; | ||
|
||
private const string verb = "GET"; | ||
private const string url = "https://some.url/blah?abcd=123"; | ||
private const string header = nameof(CacheKeyGeneratorTests); | ||
private const string headerName = "auth"; | ||
|
||
public CacheKeyGeneratorTests() | ||
{ | ||
_cacheKeyGenerator = new CacheKeyGenerator(); | ||
_cacheKeyGenerator = new CacheKeyGenerator(); | ||
_downstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123")); | ||
|
||
_downstreamRequest = new Mock<DownstreamRequest>(); | ||
_downstreamRequest.SetupGet(x => x.Method).Returns(verb); | ||
_downstreamRequest.SetupGet(x => x.OriginalString).Returns(url); | ||
|
||
var headers = new HttpHeadersStub | ||
{ | ||
{ headerName, header }, | ||
}; | ||
_downstreamRequest.SetupGet(x => x.Headers).Returns(headers); | ||
} | ||
|
||
[Fact] | ||
public void should_generate_cache_key_with_request_content() | ||
{ | ||
const string content = nameof(should_generate_cache_key_with_request_content); | ||
|
||
_downstreamRequest.SetupGet(x => x.HasContent).Returns(true); | ||
_downstreamRequest.Setup(x => x.ReadContentAsync()).ReturnsAsync(content); | ||
|
||
var cachekey = MD5Helper.GenerateMd5($"{verb}-{url}-{content}"); | ||
|
||
this.Given(x => x.GivenDownstreamRoute(null)) | ||
.When(x => x.WhenGenerateRequestCacheKey()) | ||
.Then(x => x.ThenGeneratedCacheKeyIs(cachekey)) | ||
.BDDfy(); | ||
} | ||
|
||
[Fact] | ||
public void should_generate_cache_key_without_request_content() | ||
{ | ||
_downstreamRequest.SetupGet(x => x.HasContent).Returns(false); | ||
|
||
CacheOptions options = null; | ||
var cachekey = MD5Helper.GenerateMd5($"{verb}-{url}"); | ||
|
||
this.Given(x => x.GivenDownstreamRoute(options)) | ||
.When(x => x.WhenGenerateRequestCacheKey()) | ||
.Then(x => x.ThenGeneratedCacheKeyIs(cachekey)) | ||
.BDDfy(); | ||
} | ||
|
||
[Fact] | ||
public void should_generate_cache_key_with_cache_options_header() | ||
{ | ||
_downstreamRequest.SetupGet(x => x.HasContent).Returns(false); | ||
|
||
CacheOptions options = new CacheOptions(100, "region", headerName); | ||
var cachekey = MD5Helper.GenerateMd5($"{verb}-{url}-{header}"); | ||
|
||
this.Given(x => x.GivenDownstreamRoute(options)) | ||
.When(x => x.WhenGenerateRequestCacheKey()) | ||
.Then(x => x.ThenGeneratedCacheKeyIs(cachekey)) | ||
.BDDfy(); | ||
} | ||
|
||
[Fact] | ||
public void should_generate_cache_key_from_context() | ||
public void should_generate_cache_key_happy_path() | ||
{ | ||
this.Given(x => x.GivenCacheKeyFromContext(_downstreamRequest)) | ||
const string content = nameof(should_generate_cache_key_happy_path); | ||
|
||
_downstreamRequest.SetupGet(x => x.HasContent).Returns(true); | ||
_downstreamRequest.Setup(x => x.ReadContentAsync()).ReturnsAsync(content); | ||
|
||
CacheOptions options = new CacheOptions(100, "region", headerName); | ||
var cachekey = MD5Helper.GenerateMd5($"{verb}-{url}-{header}-{content}"); | ||
|
||
this.Given(x => x.GivenDownstreamRoute(options)) | ||
.When(x => x.WhenGenerateRequestCacheKey()) | ||
.Then(x => x.ThenGeneratedCacheKeyIs(cachekey)) | ||
.BDDfy(); | ||
} | ||
|
||
private void GivenCacheKeyFromContext(DownstreamRequest downstreamRequest) | ||
private DownstreamRoute _downstreamRoute; | ||
|
||
private void GivenDownstreamRoute(CacheOptions options) | ||
{ | ||
_downstreamRoute = new DownstreamRouteBuilder() | ||
.WithKey("key1") | ||
.WithCacheOptions(options) | ||
.Build(); | ||
} | ||
|
||
private string _generatedCacheKey; | ||
|
||
private async Task WhenGenerateRequestCacheKey() | ||
{ | ||
_generatedCacheKey = await _cacheKeyGenerator.GenerateRequestCacheKey(_downstreamRequest.Object, _downstreamRoute); | ||
} | ||
|
||
private void ThenGeneratedCacheKeyIs(string expected) | ||
{ | ||
var generatedCacheKey = _cacheKeyGenerator.GenerateRequestCacheKey(downstreamRequest); | ||
var cachekey = MD5Helper.GenerateMd5("GET-https://some.url/blah?abcd=123"); | ||
generatedCacheKey.ShouldBe(cachekey); | ||
_generatedCacheKey.ShouldBe(expected); | ||
} | ||
} | ||
|
||
internal class HttpHeadersStub : HttpHeaders | ||
{ | ||
public HttpHeadersStub() : base() { } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.