Skip to content

Commit f1b42b7

Browse files
committed
ContentCachingResponseWrapper defensively applies content length in case of sendError/sendRedirect
Issue: SPR-13004 (cherry picked from commit 4facb2f)
1 parent 3d131c9 commit f1b42b7

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

spring-web/src/main/java/org/springframework/web/util/ContentCachingResponseWrapper.java

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public class ContentCachingResponseWrapper extends HttpServletResponseWrapper {
4848

4949
private int statusCode = HttpServletResponse.SC_OK;
5050

51+
private Integer contentLength;
52+
5153

5254
/**
5355
* Create a new ContentCachingResponseWrapper for the given servlet response.
@@ -74,14 +76,27 @@ public void setStatus(int sc, String sm) {
7476
@Override
7577
public void sendError(int sc) throws IOException {
7678
copyBodyToResponse();
77-
super.sendError(sc);
79+
try {
80+
super.sendError(sc);
81+
}
82+
catch (IllegalStateException ex) {
83+
// Possibly on Tomcat when called too late: fall back to silent setStatus
84+
super.setStatus(sc);
85+
}
7886
this.statusCode = sc;
7987
}
8088

8189
@Override
90+
@SuppressWarnings("deprecation")
8291
public void sendError(int sc, String msg) throws IOException {
8392
copyBodyToResponse();
84-
super.sendError(sc, msg);
93+
try {
94+
super.sendError(sc, msg);
95+
}
96+
catch (IllegalStateException ex) {
97+
// Possibly on Tomcat when called too late: fall back to silent setStatus
98+
super.setStatus(sc, msg);
99+
}
85100
this.statusCode = sc;
86101
}
87102

@@ -111,6 +126,7 @@ public void setContentLength(int len) {
111126
if (len > this.content.capacity()) {
112127
this.content.resize(len);
113128
}
129+
this.contentLength = len;
114130
}
115131

116132
// Overrides Servlet 3.1 setContentLengthLong(long) at runtime
@@ -119,9 +135,11 @@ public void setContentLengthLong(long len) {
119135
throw new IllegalArgumentException("Content-Length exceeds ShallowEtagHeaderFilter's maximum (" +
120136
Integer.MAX_VALUE + "): " + len);
121137
}
122-
if (len > this.content.capacity()) {
123-
this.content.resize((int) len);
138+
int lenInt = (int) len;
139+
if (lenInt > this.content.capacity()) {
140+
this.content.resize(lenInt);
124141
}
142+
this.contentLength = lenInt;
125143
}
126144

127145
@Override
@@ -158,7 +176,10 @@ public byte[] getContentAsByteArray() {
158176

159177
private void copyBodyToResponse() throws IOException {
160178
if (this.content.size() > 0) {
161-
getResponse().setContentLength(this.content.size());
179+
if (this.contentLength != null) {
180+
getResponse().setContentLength(this.contentLength);
181+
this.contentLength = null;
182+
}
162183
StreamUtils.copy(this.content.toByteArray(), getResponse().getOutputStream());
163184
this.content.reset();
164185
}

spring-web/src/test/java/org/springframework/web/filter/ShallowEtagHeaderFilterTests.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@ public void isEligibleForEtag() {
5858
assertFalse(filter.isEligibleForEtag(request, response, 200, new byte[0]));
5959

6060
request = new MockHttpServletRequest("POST", "/hotels");
61-
request.addHeader("Cache-Control","must-revalidate, no-store");
61+
request.addHeader("Cache-Control", "must-revalidate, no-store");
6262
assertFalse(filter.isEligibleForEtag(request, response, 200, new byte[0]));
6363
}
6464

@@ -146,6 +146,7 @@ public void filterSendError() throws Exception {
146146
public void doFilter(ServletRequest filterRequest, ServletResponse filterResponse)
147147
throws IOException, ServletException {
148148
assertEquals("Invalid request passed", request, filterRequest);
149+
response.setContentLength(100);
149150
FileCopyUtils.copy(responseBody, filterResponse.getOutputStream());
150151
((HttpServletResponse) filterResponse).sendError(HttpServletResponse.SC_FORBIDDEN);
151152
}
@@ -154,7 +155,7 @@ public void doFilter(ServletRequest filterRequest, ServletResponse filterRespons
154155

155156
assertEquals("Invalid status", 403, response.getStatus());
156157
assertNull("Invalid ETag header", response.getHeader("ETag"));
157-
assertTrue("Invalid Content-Length header", response.getContentLength() > 0);
158+
assertEquals("Invalid Content-Length header", 100, response.getContentLength());
158159
assertArrayEquals("Invalid content", responseBody, response.getContentAsByteArray());
159160
}
160161

@@ -169,6 +170,7 @@ public void filterSendErrorMessage() throws Exception {
169170
public void doFilter(ServletRequest filterRequest, ServletResponse filterResponse)
170171
throws IOException, ServletException {
171172
assertEquals("Invalid request passed", request, filterRequest);
173+
response.setContentLength(100);
172174
FileCopyUtils.copy(responseBody, filterResponse.getOutputStream());
173175
((HttpServletResponse) filterResponse).sendError(HttpServletResponse.SC_FORBIDDEN, "ERROR");
174176
}
@@ -177,7 +179,7 @@ public void doFilter(ServletRequest filterRequest, ServletResponse filterRespons
177179

178180
assertEquals("Invalid status", 403, response.getStatus());
179181
assertNull("Invalid ETag header", response.getHeader("ETag"));
180-
assertTrue("Invalid Content-Length header", response.getContentLength() > 0);
182+
assertEquals("Invalid Content-Length header", 100, response.getContentLength());
181183
assertArrayEquals("Invalid content", responseBody, response.getContentAsByteArray());
182184
assertEquals("Invalid error message", "ERROR", response.getErrorMessage());
183185
}
@@ -193,6 +195,7 @@ public void filterSendRedirect() throws Exception {
193195
public void doFilter(ServletRequest filterRequest, ServletResponse filterResponse)
194196
throws IOException, ServletException {
195197
assertEquals("Invalid request passed", request, filterRequest);
198+
response.setContentLength(100);
196199
FileCopyUtils.copy(responseBody, filterResponse.getOutputStream());
197200
((HttpServletResponse) filterResponse).sendRedirect("http://www.google.com");
198201
}
@@ -201,7 +204,7 @@ public void doFilter(ServletRequest filterRequest, ServletResponse filterRespons
201204

202205
assertEquals("Invalid status", 302, response.getStatus());
203206
assertNull("Invalid ETag header", response.getHeader("ETag"));
204-
assertTrue("Invalid Content-Length header", response.getContentLength() > 0);
207+
assertEquals("Invalid Content-Length header", 100, response.getContentLength());
205208
assertArrayEquals("Invalid content", responseBody, response.getContentAsByteArray());
206209
assertEquals("Invalid redirect URL", "http://www.google.com", response.getRedirectedUrl());
207210
}

0 commit comments

Comments
 (0)