Browse Source

Weak Etag.

pull/342/head
Sebastian 7 years ago
parent
commit
1c5dbabb96
  1. 3
      src/Squidex/AppServices.cs
  2. 21
      src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs
  3. 27
      src/Squidex/Pipeline/ETagFilter.cs
  4. 14
      src/Squidex/Pipeline/ETagOptions.cs
  5. 7
      src/Squidex/appsettings.json
  6. 15
      tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs

3
src/Squidex/AppServices.cs

@ -19,6 +19,7 @@ using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Extensions.Actions.Twitter;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Diagnostics;
using Squidex.Pipeline;
using Squidex.Pipeline.Robots;
namespace Squidex
@ -60,6 +61,8 @@ namespace Squidex
config.GetSection("robots"));
services.Configure<GCHealthCheckOptions>(
config.GetSection("healthz:gc"));
services.Configure<ETagOptions>(
config.GetSection("etags"));
services.Configure<MyContentsControllerOptions>(
config.GetSection("contentsController"));

21
src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs

@ -33,16 +33,23 @@ namespace Squidex.Pipeline.CommandMiddlewares
return;
}
context.Command.ExpectedVersion = EtagVersion.Any;
var headers = httpContextAccessor.HttpContext.Request.Headers;
var headerMatch = headers[HeaderNames.IfMatch].ToString();
if (!string.IsNullOrWhiteSpace(headerMatch) && long.TryParse(headerMatch, NumberStyles.Any, CultureInfo.InvariantCulture, out var expectedVersion))
{
context.Command.ExpectedVersion = expectedVersion;
}
else
if (headers.TryGetValue(HeaderNames.ETag, out var etag) && !string.IsNullOrWhiteSpace(etag))
{
context.Command.ExpectedVersion = EtagVersion.Any;
var etagValue = etag.ToString();
if (etagValue.StartsWith("W/", StringComparison.OrdinalIgnoreCase))
{
etagValue = etagValue.Substring(2);
}
if (long.TryParse(etagValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var expectedVersion))
{
context.Command.ExpectedVersion = expectedVersion;
}
}
await next();

27
src/Squidex/Pipeline/ETagFilter.cs

@ -9,12 +9,20 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
namespace Squidex.Pipeline
{
public sealed class ETagFilter : IAsyncActionFilter
{
private readonly ETagOptions options;
public ETagFilter(IOptions<ETagOptions> options)
{
this.options = options.Value;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var resultContext = await next();
@ -22,14 +30,21 @@ namespace Squidex.Pipeline
var httpContext = context.HttpContext;
if (HttpMethods.IsGet(httpContext.Request.Method) &&
httpContext.Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var noneMatch) &&
httpContext.Response.StatusCode == 200 &&
httpContext.Response.Headers.TryGetValue(HeaderNames.ETag, out var etag) &&
!string.IsNullOrWhiteSpace(noneMatch) &&
!string.IsNullOrWhiteSpace(etag) &&
string.Equals(etag, noneMatch, System.StringComparison.Ordinal))
httpContext.Response.Headers.TryGetValue(HeaderNames.ETag, out var etag) && !string.IsNullOrWhiteSpace(etag))
{
resultContext.Result = new StatusCodeResult(304);
if (!options.Strong)
{
httpContext.Response.Headers[HeaderNames.ETag] = "W/" + etag;
}
if (httpContext.Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var noneMatch) && !string.IsNullOrWhiteSpace(noneMatch))
{
if (string.Equals(etag, noneMatch, System.StringComparison.Ordinal))
{
resultContext.Result = new StatusCodeResult(304);
}
}
}
}
}

14
src/Squidex/Pipeline/ETagOptions.cs

@ -0,0 +1,14 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Pipeline
{
public sealed class ETagOptions
{
public bool Strong { get; set; }
}
}

7
src/Squidex/appsettings.json

@ -18,6 +18,13 @@
"enforceHttps": false
},
"etags": {
/*
* Set to true, to use strong etags.
*/
"strong": false
},
"ui": {
/*
* Regex suggestions for the UI

15
tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs

@ -48,7 +48,20 @@ namespace Squidex.Pipeline.CommandMiddlewares
[Fact]
public async Task Should_add_expected_version_to_command()
{
requestHeaders["If-Match"] = "13";
requestHeaders[HeaderNames.ETag] = "13";
var command = new CreateContent();
var context = new CommandContext(command, commandBus);
await sut.HandleAsync(context);
Assert.Equal(13, context.Command.ExpectedVersion);
}
[Fact]
public async Task Should_add_weak_etag_as_expected_version_to_command()
{
requestHeaders[HeaderNames.ETag] = "W/13";
var command = new CreateContent();
var context = new CommandContext(command, commandBus);

Loading…
Cancel
Save