From 09a8f8a062d081d627761879e769df40e66be2d7 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 27 Dec 2018 11:46:09 +0100 Subject: [PATCH] Etag fixed. --- .../ETagCommandMiddleware.cs | 2 +- src/Squidex/Pipeline/ETagFilter.cs | 20 +++-- .../language-selector.component.html | 2 +- .../language-selector.component.scss | 3 + .../ETagCommandMiddlewareTests.cs | 10 +-- .../Squidex.Tests/Pipeline/ETagFilterTests.cs | 88 +++++++++++++++++++ 6 files changed, 109 insertions(+), 16 deletions(-) create mode 100644 tests/Squidex.Tests/Pipeline/ETagFilterTests.cs diff --git a/src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs b/src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs index 9b17bfc41..fb4c74dfa 100644 --- a/src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs +++ b/src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs @@ -37,7 +37,7 @@ namespace Squidex.Pipeline.CommandMiddlewares var headers = httpContextAccessor.HttpContext.Request.Headers; - if (headers.TryGetValue(HeaderNames.ETag, out var etag) && !string.IsNullOrWhiteSpace(etag)) + if (headers.TryGetValue(HeaderNames.IfMatch, out var etag) && !string.IsNullOrWhiteSpace(etag)) { var etagValue = etag.ToString(); diff --git a/src/Squidex/Pipeline/ETagFilter.cs b/src/Squidex/Pipeline/ETagFilter.cs index 587060944..d14561734 100644 --- a/src/Squidex/Pipeline/ETagFilter.cs +++ b/src/Squidex/Pipeline/ETagFilter.cs @@ -29,21 +29,23 @@ namespace Squidex.Pipeline var httpContext = context.HttpContext; - if (HttpMethods.IsGet(httpContext.Request.Method) && - httpContext.Response.StatusCode == 200 && - httpContext.Response.Headers.TryGetValue(HeaderNames.ETag, out var etag) && !string.IsNullOrWhiteSpace(etag)) + if (httpContext.Response.Headers.TryGetValue(HeaderNames.ETag, out var etag) && !string.IsNullOrWhiteSpace(etag)) { + string etagValue = etag; + if (!options.Strong) { - httpContext.Response.Headers[HeaderNames.ETag] = "W/" + etag; + etagValue = "W/" + etag; + + httpContext.Response.Headers[HeaderNames.ETag] = etagValue; } - if (httpContext.Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var noneMatch) && !string.IsNullOrWhiteSpace(noneMatch)) + if (HttpMethods.IsGet(httpContext.Request.Method) && + httpContext.Response.StatusCode == 200 && + httpContext.Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var noneMatch) && !string.IsNullOrWhiteSpace(noneMatch) && + string.Equals(etagValue, noneMatch, System.StringComparison.Ordinal)) { - if (string.Equals(etag, noneMatch, System.StringComparison.Ordinal)) - { - resultContext.Result = new StatusCodeResult(304); - } + resultContext.Result = new StatusCodeResult(304); } } } diff --git a/src/Squidex/app/shared/components/language-selector.component.html b/src/Squidex/app/shared/components/language-selector.component.html index 9e80798dc..4215489e6 100644 --- a/src/Squidex/app/shared/components/language-selector.component.html +++ b/src/Squidex/app/shared/components/language-selector.component.html @@ -10,7 +10,7 @@ \ No newline at end of file diff --git a/src/Squidex/app/shared/components/language-selector.component.scss b/src/Squidex/app/shared/components/language-selector.component.scss index 10a1d636a..9568206f2 100644 --- a/src/Squidex/app/shared/components/language-selector.component.scss +++ b/src/Squidex/app/shared/components/language-selector.component.scss @@ -7,6 +7,9 @@ .iso-code { font-family: monospace; +} + +.iso-code-dropdown { display: inline-block; min-width: 40px; max-width: 60px; diff --git a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs index 043f6ee59..359147278 100644 --- a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs +++ b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs @@ -20,13 +20,13 @@ namespace Squidex.Pipeline.CommandMiddlewares { private readonly IHttpContextAccessor httpContextAccessor = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly IHeaderDictionary requestHeaders = new HeaderDictionary(); + private readonly HttpContext httpContext = new DefaultHttpContext(); private readonly ETagCommandMiddleware sut; public ETagCommandMiddlewareTests() { - A.CallTo(() => httpContextAccessor.HttpContext.Request.Headers) - .Returns(requestHeaders); + A.CallTo(() => httpContextAccessor.HttpContext) + .Returns(httpContext); sut = new ETagCommandMiddleware(httpContextAccessor); } @@ -48,7 +48,7 @@ namespace Squidex.Pipeline.CommandMiddlewares [Fact] public async Task Should_add_expected_version_to_command() { - requestHeaders[HeaderNames.ETag] = "13"; + httpContext.Request.Headers[HeaderNames.IfMatch] = "13"; var command = new CreateContent(); var context = new CommandContext(command, commandBus); @@ -61,7 +61,7 @@ namespace Squidex.Pipeline.CommandMiddlewares [Fact] public async Task Should_add_weak_etag_as_expected_version_to_command() { - requestHeaders[HeaderNames.ETag] = "W/13"; + httpContext.Request.Headers[HeaderNames.IfMatch] = "W/13"; var command = new CreateContent(); var context = new CommandContext(command, commandBus); diff --git a/tests/Squidex.Tests/Pipeline/ETagFilterTests.cs b/tests/Squidex.Tests/Pipeline/ETagFilterTests.cs new file mode 100644 index 000000000..6e923b253 --- /dev/null +++ b/tests/Squidex.Tests/Pipeline/ETagFilterTests.cs @@ -0,0 +1,88 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using System.Threading.Tasks; +using FakeItEasy; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Squidex.Pipeline +{ + public class ETagFilterTests + { + private readonly HttpContext httpContext = new DefaultHttpContext(); + private readonly ActionExecutingContext executingContext; + private readonly ActionExecutedContext executedContext; + private readonly ETagFilter sut = new ETagFilter(Options.Create(new ETagOptions())); + + public ETagFilterTests() + { + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + var filters = new List(); + + executingContext = new ActionExecutingContext(actionContext, filters, new Dictionary(), this); + executedContext = new ActionExecutedContext(actionContext, filters, this) + { + Result = new OkResult() + }; + } + + [Fact] + public async Task Should_convert_strong_to_weak_tag() + { + httpContext.Response.Headers[HeaderNames.ETag] = "13"; + + await sut.OnActionExecutionAsync(executingContext, () => Task.FromResult(executedContext)); + + Assert.Equal("W/13", httpContext.Response.Headers[HeaderNames.ETag]); + } + + [Fact] + public async Task Should_not_convert_empty_strong_to_weak_tag() + { + httpContext.Response.Headers[HeaderNames.ETag] = string.Empty; + + await sut.OnActionExecutionAsync(executingContext, () => Task.FromResult(executedContext)); + + Assert.Null((string)httpContext.Response.Headers[HeaderNames.ETag]); + } + + [Fact] + public async Task Should_return_304_for_same_etags() + { + httpContext.Request.Method = HttpMethods.Get; + httpContext.Request.Headers[HeaderNames.IfNoneMatch] = "W/13"; + + httpContext.Response.Headers[HeaderNames.ETag] = "13"; + + await sut.OnActionExecutionAsync(executingContext, () => Task.FromResult(executedContext)); + + Assert.Equal(304, (executedContext.Result as StatusCodeResult).StatusCode); + } + + [Fact] + public async Task Should_not_return_304_for_different_etags() + { + httpContext.Request.Method = HttpMethods.Get; + httpContext.Request.Headers[HeaderNames.IfNoneMatch] = "W/11"; + + httpContext.Response.Headers[HeaderNames.ETag] = "13"; + + await sut.OnActionExecutionAsync(executingContext, () => Task.FromResult(executedContext)); + + Assert.Equal(200, (executedContext.Result as StatusCodeResult).StatusCode); + } + } +}