Skip to content

DefaultProblemDetailsWriter Doesn't Handle Media Type Subsets #52577

Open
@commonsensesoftware

Description

@commonsensesoftware

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:

private static readonly MediaTypeHeaderValue _jsonMediaType = new("application/json");

The matching logic, however, is inverted:

if (_jsonMediaType.IsSubsetOf(acceptHeaderValue) ||

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:

public bool IsSubsetOf(MediaTypeHeaderValue otherMediaType)

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:

public void CanWrite_ReturnsTrue_WhenJsonAccepted(string contentType)

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionshelp wantedUp for grabs. We would accept a PR to help resolve this issue

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions