From 432cd04cffab02880cf7ffed82d610587c621c87 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sat, 29 Jun 2024 17:16:35 +0100 Subject: [PATCH] Amortise Content-Type arrays - Amortise arrays used for `TypedResults`' metadata. - Use `ProducesResponseTypeMetadata.CreateUnvalidated` to bypass `Content-Type` validation for static values. - Add and use constant for `application/octet-stream`. --- .../src/Microsoft.AspNetCore.Http.Abstractions.csproj | 1 + src/Http/Http.Results/src/AcceptedAtRouteOfT.cs | 2 +- src/Http/Http.Results/src/AcceptedOfT.cs | 2 +- src/Http/Http.Results/src/BadRequestOfT.cs | 2 +- src/Http/Http.Results/src/ConflictOfT.cs | 2 +- src/Http/Http.Results/src/CreatedAtRouteOfT.cs | 2 +- src/Http/Http.Results/src/CreatedOfT.cs | 2 +- src/Http/Http.Results/src/FileContentHttpResult.cs | 2 +- src/Http/Http.Results/src/FileStreamHttpResult.cs | 2 +- src/Http/Http.Results/src/HttpResultsHelper.cs | 6 ++++++ src/Http/Http.Results/src/InternalServerErrorOfT.cs | 2 +- src/Http/Http.Results/src/NotFoundOfT.cs | 2 +- src/Http/Http.Results/src/OkOfT.cs | 2 +- src/Http/Http.Results/src/PhysicalFileHttpResult.cs | 2 +- src/Http/Http.Results/src/ProblemHttpResult.cs | 2 +- src/Http/Http.Results/src/UnprocessableEntityOfT.cs | 2 +- src/Http/Http.Results/src/ValidationProblem.cs | 4 ++-- src/Http/Http.Results/src/VirtualFileHttpResult.cs | 2 +- 18 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj b/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj index 9d36a6bffdb8..d76abad9b241 100644 --- a/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj +++ b/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj @@ -37,6 +37,7 @@ Microsoft.AspNetCore.Http.HttpResponse + diff --git a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs index eee96dbb54a5..e01be31eca3b 100644 --- a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs @@ -122,6 +122,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status202Accepted, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status202Accepted, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/AcceptedOfT.cs b/src/Http/Http.Results/src/AcceptedOfT.cs index 0fcd1676f8fe..939f45f19e92 100644 --- a/src/Http/Http.Results/src/AcceptedOfT.cs +++ b/src/Http/Http.Results/src/AcceptedOfT.cs @@ -100,6 +100,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status202Accepted, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status202Accepted, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/BadRequestOfT.cs b/src/Http/Http.Results/src/BadRequestOfT.cs index 76d2da6f09aa..d28929f595af 100644 --- a/src/Http/Http.Results/src/BadRequestOfT.cs +++ b/src/Http/Http.Results/src/BadRequestOfT.cs @@ -65,6 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status400BadRequest, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status400BadRequest, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/ConflictOfT.cs b/src/Http/Http.Results/src/ConflictOfT.cs index 1bfa6f07c954..325ba7a90b89 100644 --- a/src/Http/Http.Results/src/ConflictOfT.cs +++ b/src/Http/Http.Results/src/ConflictOfT.cs @@ -65,6 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status409Conflict, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status409Conflict, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs index 3c7ec16337f6..28fd3dc69162 100644 --- a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs @@ -125,6 +125,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status201Created, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status201Created, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/CreatedOfT.cs b/src/Http/Http.Results/src/CreatedOfT.cs index d89ba7fb4ea1..beda8bd77995 100644 --- a/src/Http/Http.Results/src/CreatedOfT.cs +++ b/src/Http/Http.Results/src/CreatedOfT.cs @@ -99,6 +99,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status201Created, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status201Created, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/FileContentHttpResult.cs b/src/Http/Http.Results/src/FileContentHttpResult.cs index b8496be0752d..f60e4d7d0b3f 100644 --- a/src/Http/Http.Results/src/FileContentHttpResult.cs +++ b/src/Http/Http.Results/src/FileContentHttpResult.cs @@ -61,7 +61,7 @@ internal FileContentHttpResult( { FileContents = fileContents; FileLength = fileContents.Length; - ContentType = contentType ?? "application/octet-stream"; + ContentType = contentType ?? HttpResultsHelper.BinaryContentType; FileDownloadName = fileDownloadName; EnableRangeProcessing = enableRangeProcessing; LastModified = lastModified; diff --git a/src/Http/Http.Results/src/FileStreamHttpResult.cs b/src/Http/Http.Results/src/FileStreamHttpResult.cs index 12266995a453..e5ca5d76c918 100644 --- a/src/Http/Http.Results/src/FileStreamHttpResult.cs +++ b/src/Http/Http.Results/src/FileStreamHttpResult.cs @@ -67,7 +67,7 @@ internal FileStreamHttpResult( FileLength = fileStream.Length; } - ContentType = contentType ?? "application/octet-stream"; + ContentType = contentType ?? HttpResultsHelper.BinaryContentType; FileDownloadName = fileDownloadName; EnableRangeProcessing = enableRangeProcessing; LastModified = lastModified; diff --git a/src/Http/Http.Results/src/HttpResultsHelper.cs b/src/Http/Http.Results/src/HttpResultsHelper.cs index 1bf697ea55a5..a7a9de11661e 100644 --- a/src/Http/Http.Results/src/HttpResultsHelper.cs +++ b/src/Http/Http.Results/src/HttpResultsHelper.cs @@ -17,7 +17,13 @@ namespace Microsoft.AspNetCore.Http; internal static partial class HttpResultsHelper { + internal const string BinaryContentType = "application/octet-stream"; internal const string DefaultContentType = "text/plain; charset=utf-8"; + internal const string ProblemDetailsContentType = "application/problem+json"; + + internal static IEnumerable ApplicationJsonContentTypes { get; } = ["application/json"]; + internal static IEnumerable ProblemDetailsContentTypes { get; } = [ProblemDetailsContentType]; + private static readonly Encoding DefaultEncoding = Encoding.UTF8; [UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", diff --git a/src/Http/Http.Results/src/InternalServerErrorOfT.cs b/src/Http/Http.Results/src/InternalServerErrorOfT.cs index 5776accbf75e..85493f1957df 100644 --- a/src/Http/Http.Results/src/InternalServerErrorOfT.cs +++ b/src/Http/Http.Results/src/InternalServerErrorOfT.cs @@ -65,6 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status500InternalServerError, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status500InternalServerError, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/NotFoundOfT.cs b/src/Http/Http.Results/src/NotFoundOfT.cs index 87bc178baa91..c803b2067530 100644 --- a/src/Http/Http.Results/src/NotFoundOfT.cs +++ b/src/Http/Http.Results/src/NotFoundOfT.cs @@ -64,6 +64,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status404NotFound, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status404NotFound, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/OkOfT.cs b/src/Http/Http.Results/src/OkOfT.cs index e85dc889ab4d..ba5efa0c2319 100644 --- a/src/Http/Http.Results/src/OkOfT.cs +++ b/src/Http/Http.Results/src/OkOfT.cs @@ -64,6 +64,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status200OK, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status200OK, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/PhysicalFileHttpResult.cs b/src/Http/Http.Results/src/PhysicalFileHttpResult.cs index 7b44bd6c1bc3..aa8cadf5e71f 100644 --- a/src/Http/Http.Results/src/PhysicalFileHttpResult.cs +++ b/src/Http/Http.Results/src/PhysicalFileHttpResult.cs @@ -58,7 +58,7 @@ internal PhysicalFileHttpResult( EntityTagHeaderValue? entityTag = null) { FileName = fileName; - ContentType = contentType ?? "application/octet-stream"; + ContentType = contentType ?? HttpResultsHelper.BinaryContentType; FileDownloadName = fileDownloadName; EnableRangeProcessing = enableRangeProcessing; LastModified = lastModified; diff --git a/src/Http/Http.Results/src/ProblemHttpResult.cs b/src/Http/Http.Results/src/ProblemHttpResult.cs index 4cea9e33ff43..9eec49a20642 100644 --- a/src/Http/Http.Results/src/ProblemHttpResult.cs +++ b/src/Http/Http.Results/src/ProblemHttpResult.cs @@ -36,7 +36,7 @@ internal ProblemHttpResult(ProblemDetails problemDetails) /// /// Gets the value for the Content-Type header: application/problem+json /// - public string ContentType => "application/problem+json"; + public string ContentType => HttpResultsHelper.ProblemDetailsContentType; /// /// Gets the HTTP status code. diff --git a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs index 3193ab69d674..764ed15514ac 100644 --- a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs +++ b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs @@ -65,6 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status422UnprocessableEntity, typeof(TValue), new[] { "application/json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status422UnprocessableEntity, HttpResultsHelper.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/ValidationProblem.cs b/src/Http/Http.Results/src/ValidationProblem.cs index eaecf6bb72ac..653ac7bfe1c3 100644 --- a/src/Http/Http.Results/src/ValidationProblem.cs +++ b/src/Http/Http.Results/src/ValidationProblem.cs @@ -39,7 +39,7 @@ internal ValidationProblem(HttpValidationProblemDetails problemDetails) /// /// Gets the value for the Content-Type header: application/problem+json. /// - public string ContentType => "application/problem+json"; + public string ContentType => HttpResultsHelper.ProblemDetailsContentType; /// /// Gets the HTTP status code: @@ -76,6 +76,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status400BadRequest, typeof(HttpValidationProblemDetails), new[] { "application/problem+json" })); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(HttpValidationProblemDetails), StatusCodes.Status400BadRequest, HttpResultsHelper.ProblemDetailsContentTypes)); } } diff --git a/src/Http/Http.Results/src/VirtualFileHttpResult.cs b/src/Http/Http.Results/src/VirtualFileHttpResult.cs index e3107f4b7929..10e677e1247f 100644 --- a/src/Http/Http.Results/src/VirtualFileHttpResult.cs +++ b/src/Http/Http.Results/src/VirtualFileHttpResult.cs @@ -63,7 +63,7 @@ internal VirtualFileHttpResult( EntityTagHeaderValue? entityTag = null) { FileName = fileName; - ContentType = contentType ?? "application/octet-stream"; + ContentType = contentType ?? HttpResultsHelper.BinaryContentType; FileDownloadName = fileDownloadName; EnableRangeProcessing = enableRangeProcessing; LastModified = lastModified;