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:
Brian Clozel
2015-11-24 17:19:16 +01:00
parent bf1afdfdc9
commit 9d9433a6eb
2 changed files with 33 additions and 3 deletions

View File

@@ -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();
}
}
}