From 6e88fb19dbefe65e55f5a2a3307d113c0174ead9 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 26 Jan 2021 21:51:32 +0100 Subject: [PATCH] Test big asset --- .../ApiModelValidationAttribute.cs | 12 +++++++ .../IdentityServer/Views/Account/Login.cshtml | 1 - .../TestSuite.ApiTests/AssetTests.cs | 16 ++++++++- .../TestSuite.ApiTests/ContentQueryTests.cs | 1 - .../TestSuite.Shared/Fixtures/AssetFixture.cs | 34 ++++++++++++++++--- 5 files changed, 57 insertions(+), 7 deletions(-) diff --git a/backend/src/Squidex.Web/ApiModelValidationAttribute.cs b/backend/src/Squidex.Web/ApiModelValidationAttribute.cs index 5b9f67e4a..7260355cf 100644 --- a/backend/src/Squidex.Web/ApiModelValidationAttribute.cs +++ b/backend/src/Squidex.Web/ApiModelValidationAttribute.cs @@ -5,7 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; using Newtonsoft.Json; @@ -16,6 +19,7 @@ namespace Squidex.Web { public sealed class ApiModelValidationAttribute : ActionFilterAttribute { + private const string RequestBodyTooLarge = "Request body too large."; private readonly bool allErrors; public ApiModelValidationAttribute(bool allErrors) @@ -33,6 +37,14 @@ namespace Squidex.Web { if (value.ValidationState == ModelValidationState.Invalid) { + foreach (var error in value.Errors) + { + if (error.ErrorMessage?.Contains(RequestBodyTooLarge, StringComparison.OrdinalIgnoreCase) == true) + { + throw new BadHttpRequestException(error.ErrorMessage, 413); + } + } + if (string.IsNullOrWhiteSpace(key)) { errors.Add(new ValidationError(T.Get("common.httpInvalidRequestFormat"))); diff --git a/backend/src/Squidex/Areas/IdentityServer/Views/Account/Login.cshtml b/backend/src/Squidex/Areas/IdentityServer/Views/Account/Login.cshtml index 669a6fa1e..4707bea2b 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Views/Account/Login.cshtml +++ b/backend/src/Squidex/Areas/IdentityServer/Views/Account/Login.cshtml @@ -2,7 +2,6 @@ @{ ViewBag.ThemeColor = "white"; - ViewBag.ThemeSize = "profile-lg"; var action = Model.IsLogin ? T.Get("common.login") : T.Get("common.signup"); diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs index 45a33771a..cec5ed88d 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs @@ -70,6 +70,20 @@ namespace TestSuite.ApiTests Assert.Equal(409, ex.StatusCode); } + [Fact] + public async Task Should_not_create_very_big_asset() + { + // STEP 1: Create small asset + await _.UploadFileAsync(1_000_000); + + + // STEP 2: Create big asset + var ex = await Assert.ThrowsAsync(() => _.UploadFileAsync(10_000_000)); + + // Client library cannot catch this exception properly. + Assert.Null(ex.StatusCode); + } + [Fact] public async Task Should_replace_asset() { @@ -307,7 +321,7 @@ namespace TestSuite.ApiTests // STEP 5: Wait for recursive deleter to delete the asset. await Task.Delay(5000); - var ex = await Assert.ThrowsAnyAsync(() => _.Assets.GetAssetAsync(_.AppName, asset_1.Id.ToString())); + var ex = await Assert.ThrowsAnyAsync(() => _.Assets.GetAssetAsync(_.AppName, asset_1.Id)); Assert.Equal(404, ex.StatusCode); } diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs index ae5f24bb2..60a400bc6 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs @@ -16,7 +16,6 @@ using TestSuite.Fixtures; using TestSuite.Model; using Xunit; -#pragma warning disable SA1507 // Code should not contain multiple blank lines in a row #pragma warning disable SA1300 // Element should begin with upper-case letter namespace TestSuite.ApiTests diff --git a/backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs b/backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs index 817c8efc7..5091f1a0e 100644 --- a/backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs +++ b/backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs @@ -49,7 +49,7 @@ namespace TestSuite.Fixtures using (var stream = fileInfo.OpenRead()) { - var upload = new FileParameter(stream, fileName ?? RandomName(fileInfo), asset.MimeType); + var upload = new FileParameter(stream, fileName ?? RandomName(fileInfo.Extension), asset.MimeType); return await Assets.PutAssetContentAsync(AppName, asset.Id, upload); } @@ -61,15 +61,41 @@ namespace TestSuite.Fixtures using (var stream = fileInfo.OpenRead()) { - var upload = new FileParameter(stream, fileName ?? RandomName(fileInfo), mimeType); + var upload = new FileParameter(stream, fileName ?? RandomName(fileInfo.Extension), mimeType); return await Assets.PostAssetAsync(AppName, parentId, id, true, upload); } } - private static string RandomName(FileInfo fileInfo) + public async Task UploadFileAsync(int size, string fileName = null, string parentId = null, string id = null) { - var fileName = $"{Guid.NewGuid()}{fileInfo.Extension}"; + using (var stream = RandomAsset(size)) + { + var upload = new FileParameter(stream, fileName ?? RandomName(".txt"), "text/csv"); + + return await Assets.PostAssetAsync(AppName, parentId, id, true, upload); + } + } + + private static MemoryStream RandomAsset(int length) + { + var stream = new MemoryStream(length); + + var random = new Random(); + + for (var i = 0; i < length; i++) + { + stream.WriteByte((byte)random.Next()); + } + + stream.Position = 0; + + return stream; + } + + private static string RandomName(string extension) + { + var fileName = $"{Guid.NewGuid()}{extension}"; return fileName; }