Ignore flush calls on ServletServerHttpResponse body outputstream

Related to #35427 and recent performance optimizations like #36334

Currently the OutputStream returned by ServletServerHttpResponse#getBody is passed to infrastructure components like HttpMessageConverter so that they can write to the response body. As seen in #36383, performing multiple flushes on the server side leads to performance degradation as it forces the Servlet container to actually flush the buffered content to the network.

We could consider more generally decoupling the flush operations from the HttpMessageConverter implementations (see #35427), but this has broader implications because message converters can be used in many places, not just server side applications. Instead, we want to make flush operations no-ops on the output stream returned by ServletServerHttpResponse#getBody. This means that the Servlet container is in the best position to flush at the optimal time and apply optimizations. Other HttpMessageConverter usage (like on the client) will not be affected. Also, specific cases like SSE and streaming do require manual flush calls and ServletServerHttpResponse#flush will keep its existing behavior.

We expect minimal disruption from this change, but applications can expect the following:

  • HTTP response headers might change from chunked bodies (Transfer-Encoding: chunked) to known content length (Content-Length: 1234) as the server might optimize this if the buffered content is smaller than the max size configured.
  • Runtime behavior might change with longer "time to first byte" but with faster responses (time to complete) and lower latency

The Spring Framework team does not consider those behavior changes as regressions or unexpected, but does provide a Spring property to undo this change with "spring.http.response.flush.enabled". Setting this property to true will revert to the previous behavior. Note that we provide this property to be a temporary measure and we fully expect to make the new behavior final.