Using Spring Boot 2.3.2, I have the following MockMvc setup:
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(springSecurityFilterChain)
.addFilter((request, response, chain) -> {
chain.doFilter(request, response);
response.setCharacterEncoding("UTF-8");
}, "/*").build()
In debugging, I can see this calls MockHttpServletResponse::updateContentTypeHeader and correctly falls through the code and replaces the content type header in this.headers, but it is not updating this.contentType, so any JUnit calls to content().contentType() will return the unaltered version which will lead to unexpected results.
Comment From: sbrannen
We have a test in place that explicitly verifies this behavior:
https://github.com/spring-projects/spring-framework/blob/1dcaa0422462aa07003419e26a500a23bb1b6da6/spring-test/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java#L143-L150
However, the Javadoc for javax.servlet.ServletResponse.setCharacterEncoding(String) states the following.
Sets the character encoding (MIME charset) of the response being sent to the client, for example, to UTF-8. If the response character encoding has already been set by the ServletContext.setResponseCharacterEncoding, deployment descriptor, or using the setContentType() or setLocale() methods, the value set in this method overrides any of those values. Calling setContentType with the String of text/html and calling this method with the String of UTF-8 is equivalent with calling setContentType with the String of text/html; charset=UTF-8.
Thus, the implementation in MockHttpServletResponse seems to contradict the part about "If the response character encoding has already been set ... using ... setContentType() ... , the value set in this method overrides any of those values."
In light of that, I would consider the current behavior a bug; however, making a change would likely break existing tests.
@rstoyanchev, @jhoeller, @bclozel, what are your thoughts on "fixing" this?
Comment From: jhoeller
According to the Servlet 2.4 getContentType() javadoc:
If a content type has been specified, and a character encoding has been explicitly or implicitly specified as described in getCharacterEncoding or getWriter has been called, the charset parameter is included in the string returned. If no character encoding has been specified, the charset parameter is omitted.
So we're indeed violating the spec there. Let's fix this for 5.3, even if some test assertions might have to be updated then.
(This probably dates back to pre-Servlet-2.4 times where our getContentType() was simply an accessor for whatever was set through setContentType and not following any other rules, retrofitted into an interface-declared Servlet API method in 2.4.)
Comment From: sbrannen
This has been fixed in master and will be available for testing in upcoming 5.3 snapshots as well as the 5.3 M2 release.