An HTTP request can include an Accept
header, indicating the media type(s) of responses that the client will find acceptable. The server should honour the request by providing a response that has a Content-Type
that matches (one of) the requested media type(s). A media type may include parameters. Does HTTP require that this process of content-negotiation respect parameters?
That is, if the client requests
Accept: application/vnd.example; version=2
(here the version
parameter has a value of 2
), and the server can serve media-type application/vnd.example; version=1
, but not application/vnd.example; version=2
, is it OK for the server to provide a response with
Content-Type: application/vnd.example; version=1
Is it OK for the server to provide a response labelled
Content-Type: application/vnd.example; version=2
but for the body of the response to actually be encoded as media-type application/vnd.example; version=1
? That is, for the parameters of the media-type of a response to be an inaccurate description of the body of the response?
It seems that Spring MVC 4.1.0 does not respect media-type parameters when doing content negotiation, and gives responses for which the parameters of the media-type of the response are an inaccurate description of the body of the response. This seems to be because the org.springframework.util.MimeType.isCompatibleWith(MimeType)
method does not examine the parameters of the MimeType
objects.
The relevant spec for content negotiation in HTTP/1.1 is RFC2616, Section 14.1.
It contains the following example, relevant to your question:
and gives the precedence as
So I think it is safe to say that
text/html;level=1
andtext/html
are different media types. I would also considertext/html;level=1
andtext/html;level=2
as different.So in your example I think it would be correct to respond with a 406 error and not respond with a different media type.
The relevant standard, RFC 7231 section 3.1.1.1, says the following about media-types:
So,
Accept
andContent-Type
headers may contain media type parameters. It adds:That suggests that the server code that uses parameter types should pay attention to them, and not simply discard them, because for some media types they will be significant. It has to implement some smarts in whether to consider whether the media type parameters are significant.
Spring MVC 4.1.0 therefore seems to be wrong to completely ignore the parameters when doing content negotiation: the class
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor
is incorrect to useorg.springframework.util.MimeType.isCompatibleWith(MimeType)
, or thatMimeType.isCompatibleWith(MimeType)
method is incorrect. If you provide Spring with several HTTP message converters that differ only in the parameters of their supported media type, Spring will not reliably choose the HTTP message converter that has the media type that exactly matches the requested media type.In section 3.1.1.5, where it describes the
Content-Type
header, it says:As the parameters of a media type in general could vary the data format, the behaviour of Spring MVC 4.1.0 is wrong, in providing parameters that are an inaccurate description of the body of the response: the method
AbstractMessageConverterMethodProcessor.getMostSpecificMediaType(MediaType, MediaType)
is wrong to return theacceptType
rather than theproduceTypeToUse
when the two types are equally specific.However, section 3.4.1, which discusses content negotiation (Proactive Negotiation), notes:
So the server is permitted to give a response that does not exactly match the media-type parameters requested, as a fall-back when it can not provide an exact match. That is, it may choose to respond with a
application/vnd.example; version=1
response body, with aContent-Type: application/vnd.example; version=1
header, despite the request sayingAccept: application/vnd.example; version=2
, if, and only if generating a validapplication/vnd.example; version=2
response would be impossible.This apparently incorrect behaviour of Spring already has a Spring bug report, SPR-10903. The Spring developers closed it as "Works as Designed", noting