Affects: 6.0.x, 6.1.x (list is not exhaustive)

When using HeaderWriterFilter and controller methods that return StreamingResponseBody, headers may be set twice.

The following two things happen in parallel:

  • The asynchronous processing of the StreamingResponseBody. If enough data is transferred to the response body, the response is forcefully committed. This causes the HeaderWriterFilter to write headers from the asynchronous thread.
  • The synchronous execution of the HeaderWriterFilter, which will write headers from the request handling thread.

Both threads may successfully pass the isDisableOnResponseCommitted() check in HeaderWriterFilter.HeaderWriterResponse#writeHeaders, causing the HeaderWriters to be invoked twice. This alone may already cause duplicate headers.

It gets even worse: The implementation of HttpServletResponse is not guaranteed to be thread safe according to the Servlet Spec.

When using Apache Tomcat, adding headers in parallel causes nasty race conditions (visible as NullPointerExceptions) that (because of garbage avoidance) may permanently break the inner workings of their org.apache.tomcat.util.http.MimeHeaders class, leading to strange errors in threads that use recycled response instances.

My current workaround: Write all headers and flush the response in the handler method.

Comment From: snicoll

Thanks for the report and the analysis. HeaderWriterFilter is part of Spring Security, did you mean to report the issue there? If not, we'd need a small sample that reproduces what you've described.

You can attach a zip here with instructions to reproduce or push the code with a readme on a GitHub repository. Thank you.

Comment From: chschu

You're right, I simply didn't notice that HeaderWriterFilter is located in Spring Security. I'll report the issue there.

Comment From: chschu

Reported as https://github.com/spring-projects/spring-security/issues/15510 with additional information and a reproducer.