Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
The DefaultProblemDetailsWriter
is meant to support clients that specify a media type in the Accept
header field that is compatible application/json
or application/problem+json
:
The matching logic, however, is inverted:
The correct logic should be:
if (acceptHeaderValue.IsSubsetOf(_jsonMediaType) ||
acceptHeaderValue.IsSubsetOf(_problemDetailsJsonMediaType))
{
return true;
}
Expected Behavior
A client that specifies a more specific media type should be matched by DefaultProblemDetailsWriter.CanWrite
. This happens because MediaTypeHeaderValue.IsSubsetOf
considers media type parameters:
The source code cites RFC 2068 §14.1 which has been superseded by RFC 2616, RFC 7230, and is currently defined by RFC 9110 §12.5.1. A media type is identified by <type>/<subtype>[+<suffix>]*
. The documentation for MediaTypeHeaderValue.IsSubsetOf
also states:
For example "multipart/mixed; boundary=1234" is a subset of "multipart/mixed; boundary=1234", "multipart/mixed", "multipart/", and "/*" but not "multipart/mixed; boundary=2345" or "multipart/message; boundary=1234".
This means that:
application/json; charset=utf-8
application/json; v=1.0
should be considered subsets of application/json
. Currently, they are not because the logic is inverted. These scenarios were missed because the test cases do not include a variant which includes a media type parameter:
Steps To Reproduce
The following scenarios assume that a problem has occurred on the server.
Example 1
Although not officially supported as part of application/json
, it is commonplace for message exchanges to use the media type parameter charset=utf-8
as opposed to Accept-Charset
, which is arguably the correct approach. If a problem occurs, no problem details are reported as a result.
POST /example HTTP/2
Host: localhost
Accept: application/json; charset=utf-8
Content-Type: application/json; charset=uft-8
Content-Length: 42
{"test": true, "message": "Why, hello there!"}
HTTP/2 400 Bad Request
Example 2
A truly RESTful API would version itself using media type negotiation, which might be achieved using a media type parameter. If a problem occurs or the version is not supported, no problem details are reported.
POST /example HTTP/2
Host: localhost
Accept: application/json; v=42.0
Content-Type: application/json; v=42.0
Content-Length: 42
{"test": true, "message": "Why, hello there!"}
HTTP/2 415 Unsupported Media Type
Exceptions (if any)
InvalidationOperationException
is IProblemDetailsService.WriteAsync
is used versus IProblemDetailsService.TryWriteAsync
.
.NET Version
8.0.100
Anything else?
- This issue affects the .NET 8 and .NET 7 implementations (all versions)
- This issue is discussed in Enable Option to Use Content Negotiation for ProblemDetails #45159, but the feature didn't make the cut for .NET 8 and was neither fixed
- This issue was identified and fixed with internal hackery in Rfc7231ProblemDetailsWriter.CanWrite Logic Is Inverted aspnet-api-versioning#1015
- If the issue is accepted as a bug, I'm happy to put up a PR