diff --git a/src/Http/Headers/src/HeaderUtilities.cs b/src/Http/Headers/src/HeaderUtilities.cs
index 59e62d1b56f3..4e44ae480dc4 100644
--- a/src/Http/Headers/src/HeaderUtilities.cs
+++ b/src/Http/Headers/src/HeaderUtilities.cs
@@ -403,8 +403,8 @@ public static bool TryParseNonNegativeInt64(StringSegment value, out long result
return long.TryParse(value.AsSpan(), NumberStyles.None, NumberFormatInfo.InvariantInfo, out result);
}
- // Strict and fast RFC7231 5.3.1 Quality value parser (and without memory allocation)
- // See https://tools.ietf.org/html/rfc7231#section-5.3.1
+ // Strict and fast RFC9110 12.4.2 Quality value parser (and without memory allocation)
+ // See https://tools.ietf.org/html/rfc9110#section-12.4.2
// Check is made to verify if the value is between 0 and 1 (and it returns False if the check fails).
internal static bool TryParseQualityDouble(StringSegment input, int startIndex, out double quality, out int length)
{
diff --git a/src/Http/Http.Abstractions/test/HttpValidationProblemDetailsJsonConverterTest.cs b/src/Http/Http.Abstractions/test/HttpValidationProblemDetailsJsonConverterTest.cs
index ab4408dd7561..06ca5f330c07 100644
--- a/src/Http/Http.Abstractions/test/HttpValidationProblemDetailsJsonConverterTest.cs
+++ b/src/Http/Http.Abstractions/test/HttpValidationProblemDetailsJsonConverterTest.cs
@@ -15,7 +15,7 @@ public class HttpValidationProblemDetailsJsonConverterTest
public void Read_Works()
{
// Arrange
- var type = "https://tools.ietf.org/html/rfc7231#section-6.5.4";
+ var type = "https://tools.ietf.org/html/rfc9110#section-15.5.5";
var title = "Not found";
var status = 404;
var detail = "Product not found";
@@ -60,7 +60,7 @@ public void Read_Works()
public void Read_WithSomeMissingValues_Works()
{
// Arrange
- var type = "https://tools.ietf.org/html/rfc7231#section-6.5.4";
+ var type = "https://tools.ietf.org/html/rfc9110#section-15.5.5";
var title = "Not found";
var status = 404;
var traceId = "|37dd3dd5-4a9619f953c40a16.";
@@ -101,7 +101,7 @@ public void Read_WithSomeMissingValues_Works()
public void ReadUsingJsonSerializerWorks()
{
// Arrange
- var type = "https://tools.ietf.org/html/rfc7231#section-6.5.4";
+ var type = "https://tools.ietf.org/html/rfc9110#section-15.5.5";
var title = "Not found";
var status = 404;
var traceId = "|37dd3dd5-4a9619f953c40a16.";
diff --git a/src/Http/Http.Abstractions/test/ProblemDetailsJsonConverterTest.cs b/src/Http/Http.Abstractions/test/ProblemDetailsJsonConverterTest.cs
index 995655ba2947..81e4abee0635 100644
--- a/src/Http/Http.Abstractions/test/ProblemDetailsJsonConverterTest.cs
+++ b/src/Http/Http.Abstractions/test/ProblemDetailsJsonConverterTest.cs
@@ -32,7 +32,7 @@ public void Read_ThrowsIfJsonIsIncomplete()
public void Read_Works()
{
// Arrange
- var type = "https://tools.ietf.org/html/rfc7231#section-6.5.4";
+ var type = "https://tools.ietf.org/html/rfc9110#section-15.5.5";
var title = "Not found";
var status = 404;
var detail = "Product not found";
@@ -65,7 +65,7 @@ public void Read_Works()
public void Read_UsingJsonSerializerWorks()
{
// Arrange
- var type = "https://tools.ietf.org/html/rfc7231#section-6.5.4";
+ var type = "https://tools.ietf.org/html/rfc9110#section-15.5.5";
var title = "Not found";
var status = 404;
var detail = "Product not found";
@@ -96,7 +96,7 @@ public void Read_UsingJsonSerializerWorks()
public void Read_WithSomeMissingValues_Works()
{
// Arrange
- var type = "https://tools.ietf.org/html/rfc7231#section-6.5.4";
+ var type = "https://tools.ietf.org/html/rfc9110#section-15.5.5";
var title = "Not found";
var status = 404;
var traceId = "|37dd3dd5-4a9619f953c40a16.";
@@ -129,7 +129,7 @@ public void Write_Works()
var value = new ProblemDetails
{
Title = "Not found",
- Type = "https://tools.ietf.org/html/rfc7231#section-6.5.4",
+ Type = "https://tools.ietf.org/html/rfc9110#section-15.5.5",
Status = 404,
Detail = "Product not found",
Instance = "http://example.com/products/14",
@@ -161,7 +161,7 @@ public void Write_WithSomeMissingContent_Works()
var value = new ProblemDetails
{
Title = "Not found",
- Type = "https://tools.ietf.org/html/rfc7231#section-6.5.4",
+ Type = "https://tools.ietf.org/html/rfc9110#section-15.5.5",
Status = 404,
};
var expected = $"{{\"type\":\"{JsonEncodedText.Encode(value.Type)}\",\"title\":\"{value.Title}\",\"status\":{value.Status}}}";
diff --git a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj
index ed2fbb631a9b..2e682a849df8 100644
--- a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj
+++ b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj
@@ -24,6 +24,7 @@
+
diff --git a/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs b/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs
index 997641d42f44..371b94d4ea59 100644
--- a/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs
+++ b/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs
@@ -24,7 +24,7 @@ public async Task WriteAsync_Works()
Detail = "Custom Bad Request",
Instance = "Custom Bad Request",
Status = StatusCodes.Status400BadRequest,
- Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1-custom",
+ Type = "https://tools.ietf.org/html/rfc9110#section-15.5.1-custom",
Title = "Custom Bad Request",
};
var problemDetailsContext = new ProblemDetailsContext()
@@ -100,7 +100,7 @@ public async Task WriteAsync_Applies_Defaults()
var problemDetails = await JsonSerializer.DeserializeAsync(stream);
Assert.NotNull(problemDetails);
Assert.Equal(StatusCodes.Status500InternalServerError, problemDetails.Status);
- Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.6.1", problemDetails.Type);
+ Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.6.1", problemDetails.Type);
Assert.Equal("An error occurred while processing your request.", problemDetails.Title);
}
@@ -133,13 +133,19 @@ await writer.WriteAsync(new ProblemDetailsContext()
var problemDetails = await JsonSerializer.DeserializeAsync(stream);
Assert.NotNull(problemDetails);
Assert.Equal(StatusCodes.Status406NotAcceptable, problemDetails.Status);
- Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.5.1", problemDetails.Type);
+ Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.5.1", problemDetails.Type);
Assert.Equal("Custom Title", problemDetails.Title);
Assert.Contains("new-extension", problemDetails.Extensions);
}
- [Fact]
- public async Task WriteAsync_UsesStatusCode_FromProblemDetails_WhenSpecified()
+ [Theory]
+ [InlineData(StatusCodes.Status400BadRequest, "Bad Request", "https://tools.ietf.org/html/rfc9110#section-15.5.1")]
+ [InlineData(StatusCodes.Status418ImATeapot, "I'm a teapot", null)]
+ [InlineData(499, null, null)]
+ public async Task WriteAsync_UsesStatusCode_FromProblemDetails_WhenSpecified(
+ int statusCode,
+ string title,
+ string type)
{
// Arrange
var writer = GetWriter();
@@ -150,16 +156,16 @@ public async Task WriteAsync_UsesStatusCode_FromProblemDetails_WhenSpecified()
await writer.WriteAsync(new ProblemDetailsContext()
{
HttpContext = context,
- ProblemDetails = { Status = StatusCodes.Status400BadRequest }
+ ProblemDetails = { Status = statusCode }
});
//Assert
stream.Position = 0;
var problemDetails = await JsonSerializer.DeserializeAsync(stream);
Assert.NotNull(problemDetails);
- Assert.Equal(StatusCodes.Status400BadRequest, problemDetails.Status);
- Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.5.1", problemDetails.Type);
- Assert.Equal("Bad Request", problemDetails.Title);
+ Assert.Equal(statusCode, problemDetails.Status);
+ Assert.Equal(type, problemDetails.Type);
+ Assert.Equal(title, problemDetails.Title);
}
[Theory]
diff --git a/src/Http/Http.Results/test/JsonResultTests.cs b/src/Http/Http.Results/test/JsonResultTests.cs
index af600b795ae3..9ee546119010 100644
--- a/src/Http/Http.Results/test/JsonResultTests.cs
+++ b/src/Http/Http.Results/test/JsonResultTests.cs
@@ -131,7 +131,7 @@ public async Task ExecuteAsync_UsesDefaults_ForProblemDetails()
Assert.Equal(StatusCodes.Status500InternalServerError, httpContext.Response.StatusCode);
stream.Position = 0;
var responseDetails = JsonSerializer.Deserialize(stream);
- Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.6.1", responseDetails.Type);
+ Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.6.1", responseDetails.Type);
Assert.Equal("An error occurred while processing your request.", responseDetails.Title);
Assert.Equal(StatusCodes.Status500InternalServerError, responseDetails.Status);
}
@@ -160,11 +160,43 @@ public async Task ExecuteAsync_UsesDefaults_ForValidationProblemDetails()
Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode);
stream.Position = 0;
var responseDetails = JsonSerializer.Deserialize(stream);
- Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.5.1", responseDetails.Type);
+ Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.5.1", responseDetails.Type);
Assert.Equal("One or more validation errors occurred.", responseDetails.Title);
Assert.Equal(StatusCodes.Status400BadRequest, responseDetails.Status);
}
+ [Fact]
+ public async Task ExecuteAsync_UsesDefaults_HttpStatusCodesWithoutTypes()
+ {
+ // Arrange
+ var details = new ProblemDetails()
+ {
+ Status = StatusCodes.Status418ImATeapot,
+ };
+
+ var result = new ProblemHttpResult(details);
+ var stream = new MemoryStream();
+ var httpContext = new DefaultHttpContext()
+ {
+ RequestServices = CreateServices(),
+ Response =
+ {
+ Body = stream,
+ },
+ };
+
+ // Act
+ await result.ExecuteAsync(httpContext);
+
+ // Assert
+ Assert.Equal(StatusCodes.Status418ImATeapot, httpContext.Response.StatusCode);
+ stream.Position = 0;
+ var responseDetails = JsonSerializer.Deserialize(stream);
+ Assert.Null(responseDetails.Type);
+ Assert.Equal("I'm a teapot", responseDetails.Title);
+ Assert.Equal(StatusCodes.Status418ImATeapot, responseDetails.Status);
+ }
+
[Fact]
public async Task ExecuteAsync_SetsProblemDetailsStatus_ForValidationProblemDetails()
{
diff --git a/src/Http/Http.Results/test/OkResultTests.cs b/src/Http/Http.Results/test/OkResultTests.cs
index 4d3add27c9ec..ab3e9e8f2398 100644
--- a/src/Http/Http.Results/test/OkResultTests.cs
+++ b/src/Http/Http.Results/test/OkResultTests.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Reflection;
-using System.Text;
using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -43,7 +42,7 @@ public async Task OkObjectResult_ExecuteAsync_SetsStatusCode()
public void PopulateMetadata_AddsResponseTypeMetadata()
{
// Arrange
- Ok MyApi() { throw new NotImplementedException(); }
+ static Ok MyApi() { throw new NotImplementedException(); }
var metadata = new List