Flush of underlying response in ContentCachingResponseWrapper
Prior to this commit, when adding a ShallowEtagHeaderFilter to an application, the ServletResponse would be wrapped by a ContentCachingResponseWrapper. When any part of the Spring infrastructure calls `flushBuffer` on the wrapped response, the call is delegated to the actual response, which is committed. It's not possible to alter the response (headers, content) anymore - the ETag filter can't act. This change prevents the `flushBuffer` call to be delegated and only commits the underlying response once the cached content is copied to the actual response stream. Issue: SPR-13717
This commit is contained in:
@@ -21,6 +21,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
@@ -121,6 +122,11 @@ public class ContentCachingResponseWrapper extends HttpServletResponseWrapper {
|
||||
return this.writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushBuffer() throws IOException {
|
||||
// do not flush the underlying response as the content as not been copied to it yet
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(int len) {
|
||||
if (len > this.content.size()) {
|
||||
@@ -178,7 +184,7 @@ public class ContentCachingResponseWrapper extends HttpServletResponseWrapper {
|
||||
* Return an {@link InputStream} to the cached content.
|
||||
* @since 4.2
|
||||
*/
|
||||
public InputStream getContentInputStream(){
|
||||
public InputStream getContentInputStream() {
|
||||
return this.content.getInputStream();
|
||||
}
|
||||
|
||||
@@ -186,7 +192,7 @@ public class ContentCachingResponseWrapper extends HttpServletResponseWrapper {
|
||||
* Return the current size of the cached content.
|
||||
* @since 4.2
|
||||
*/
|
||||
public int getContentSize(){
|
||||
public int getContentSize() {
|
||||
return this.content.size();
|
||||
}
|
||||
|
||||
@@ -207,12 +213,15 @@ public class ContentCachingResponseWrapper extends HttpServletResponseWrapper {
|
||||
protected void copyBodyToResponse(boolean complete) throws IOException {
|
||||
if (this.content.size() > 0) {
|
||||
HttpServletResponse rawResponse = (HttpServletResponse) getResponse();
|
||||
if ((complete || this.contentLength != null) && !rawResponse.isCommitted()){
|
||||
if ((complete || this.contentLength != null) && !rawResponse.isCommitted()) {
|
||||
rawResponse.setContentLength(complete ? this.content.size() : this.contentLength);
|
||||
this.contentLength = null;
|
||||
}
|
||||
this.content.writeTo(rawResponse.getOutputStream());
|
||||
this.content.reset();
|
||||
if (complete) {
|
||||
super.flushBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -197,4 +197,25 @@ public class ShallowEtagHeaderFilterTests {
|
||||
assertEquals("Invalid redirect URL", "http://www.google.com", response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
// SPR-13717
|
||||
@Test
|
||||
public void filterFlushResponse() throws Exception {
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
final byte[] responseBody = "Hello World".getBytes("UTF-8");
|
||||
FilterChain filterChain = (filterRequest, filterResponse) -> {
|
||||
assertEquals("Invalid request passed", request, filterRequest);
|
||||
((HttpServletResponse) filterResponse).setStatus(HttpServletResponse.SC_OK);
|
||||
FileCopyUtils.copy(responseBody, filterResponse.getOutputStream());
|
||||
filterResponse.flushBuffer();
|
||||
};
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
||||
assertEquals("Invalid status", 200, response.getStatus());
|
||||
assertEquals("Invalid ETag header", "\"0b10a8db164e0754105b7a99be72e3fe5\"", response.getHeader("ETag"));
|
||||
assertTrue("Invalid Content-Length header", response.getContentLength() > 0);
|
||||
assertArrayEquals("Invalid content", responseBody, response.getContentAsByteArray());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user