Skip to content

Commit 57d7ad0

Browse files
author
Rob Winch
committed
Revert "Cache Control only written if not set"
This reverts commit 242b831. Spring MVC fixed the issue we were working around and the changes in Spring Security were unreliable. Fixes gh-3975
1 parent e62596f commit 57d7ad0

File tree

4 files changed

+35
-217
lines changed

4 files changed

+35
-217
lines changed

web/src/main/java/org/springframework/security/web/header/HeaderWriterFilter.java

Lines changed: 8 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,15 @@
1515
*/
1616
package org.springframework.security.web.header;
1717

18-
import java.io.IOException;
19-
import java.util.List;
18+
import org.springframework.util.Assert;
19+
import org.springframework.web.filter.OncePerRequestFilter;
2020

2121
import javax.servlet.FilterChain;
2222
import javax.servlet.ServletException;
2323
import javax.servlet.http.HttpServletRequest;
2424
import javax.servlet.http.HttpServletResponse;
25-
26-
import org.springframework.security.web.util.OnCommittedResponseWrapper;
27-
import org.springframework.util.Assert;
28-
import org.springframework.web.filter.OncePerRequestFilter;
25+
import java.io.IOException;
26+
import java.util.*;
2927

3028
/**
3129
* Filter implementation to add headers to the current response. Can be useful to add
@@ -58,52 +56,12 @@ public HeaderWriterFilter(List<HeaderWriter> headerWriters) {
5856
@Override
5957
protected void doFilterInternal(HttpServletRequest request,
6058
HttpServletResponse response, FilterChain filterChain)
61-
throws ServletException, IOException {
59+
throws ServletException, IOException {
6260

63-
HeaderWriterResponse headerWriterResponse = new HeaderWriterResponse(request,
64-
response, this.headerWriters);
65-
try {
66-
filterChain.doFilter(request, headerWriterResponse);
67-
}
68-
finally {
69-
headerWriterResponse.writeHeaders();
61+
for (HeaderWriter headerWriter : headerWriters) {
62+
headerWriter.writeHeaders(request, response);
7063
}
64+
filterChain.doFilter(request, response);
7165
}
7266

73-
static class HeaderWriterResponse extends OnCommittedResponseWrapper {
74-
private final HttpServletRequest request;
75-
private final List<HeaderWriter> headerWriters;
76-
77-
HeaderWriterResponse(HttpServletRequest request, HttpServletResponse response,
78-
List<HeaderWriter> headerWriters) {
79-
super(response);
80-
this.request = request;
81-
this.headerWriters = headerWriters;
82-
}
83-
84-
/*
85-
* (non-Javadoc)
86-
*
87-
* @see org.springframework.security.web.util.OnCommittedResponseWrapper#
88-
* onResponseCommitted()
89-
*/
90-
@Override
91-
protected void onResponseCommitted() {
92-
writeHeaders();
93-
this.disableOnResponseCommitted();
94-
}
95-
96-
protected void writeHeaders() {
97-
if (isDisableOnResponseCommitted()) {
98-
return;
99-
}
100-
for (HeaderWriter headerWriter : this.headerWriters) {
101-
headerWriter.writeHeaders(this.request, getHttpResponse());
102-
}
103-
}
104-
105-
private HttpServletResponse getHttpResponse() {
106-
return (HttpServletResponse) getResponse();
107-
}
108-
}
10967
}

web/src/main/java/org/springframework/security/web/header/writers/CacheControlHeadersWriter.java

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,14 @@
1515
*/
1616
package org.springframework.security.web.header.writers;
1717

18-
import java.lang.reflect.Method;
1918
import java.util.ArrayList;
2019
import java.util.List;
2120

22-
import javax.servlet.http.HttpServletRequest;
23-
import javax.servlet.http.HttpServletResponse;
24-
2521
import org.springframework.security.web.header.Header;
26-
import org.springframework.security.web.header.HeaderWriter;
27-
import org.springframework.util.ReflectionUtils;
2822

2923
/**
30-
* Inserts headers to prevent caching if no cache control headers have been specified.
31-
* Specifically it adds the following headers:
24+
* A {@link StaticHeadersWriter} that inserts headers to prevent caching. Specifically it
25+
* adds the following headers:
3226
* <ul>
3327
* <li>Cache-Control: no-cache, no-store, max-age=0, must-revalidate</li>
3428
* <li>Pragma: no-cache</li>
@@ -38,47 +32,21 @@
3832
* @author Rob Winch
3933
* @since 3.2
4034
*/
41-
public final class CacheControlHeadersWriter implements HeaderWriter {
42-
private static final String EXPIRES = "Expires";
43-
private static final String PRAGMA = "Pragma";
44-
private static final String CACHE_CONTROL = "Cache-Control";
45-
46-
private final Method getHeaderMethod;
47-
48-
private final HeaderWriter delegate;
35+
public final class CacheControlHeadersWriter extends StaticHeadersWriter {
4936

5037
/**
5138
* Creates a new instance
5239
*/
5340
public CacheControlHeadersWriter() {
54-
this.delegate = new StaticHeadersWriter(createHeaders());
55-
this.getHeaderMethod = ReflectionUtils.findMethod(HttpServletResponse.class,
56-
"getHeader", String.class);
57-
}
58-
59-
@Override
60-
public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
61-
if (hasHeader(response, CACHE_CONTROL) || hasHeader(response, EXPIRES)
62-
|| hasHeader(response, PRAGMA)) {
63-
return;
64-
}
65-
this.delegate.writeHeaders(request, response);
66-
}
67-
68-
private boolean hasHeader(HttpServletResponse response, String headerName) {
69-
if (this.getHeaderMethod == null) {
70-
return false;
71-
}
72-
return ReflectionUtils.invokeMethod(this.getHeaderMethod, response,
73-
headerName) != null;
41+
super(createHeaders());
7442
}
7543

7644
private static List<Header> createHeaders() {
7745
List<Header> headers = new ArrayList<Header>(2);
78-
headers.add(new Header(CACHE_CONTROL,
46+
headers.add(new Header("Cache-Control",
7947
"no-cache, no-store, max-age=0, must-revalidate"));
80-
headers.add(new Header(PRAGMA, "no-cache"));
81-
headers.add(new Header(EXPIRES, "0"));
48+
headers.add(new Header("Pragma", "no-cache"));
49+
headers.add(new Header("Expires", "0"));
8250
return headers;
8351
}
8452
}

web/src/test/java/org/springframework/security/web/header/HeaderWriterFilterTests.java

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,21 @@
1515
*/
1616
package org.springframework.security.web.header;
1717

18-
import java.io.IOException;
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.mockito.Mockito.verify;
20+
1921
import java.util.ArrayList;
20-
import java.util.Arrays;
2122
import java.util.List;
2223

23-
import javax.servlet.FilterChain;
24-
import javax.servlet.ServletException;
25-
import javax.servlet.ServletRequest;
26-
import javax.servlet.ServletResponse;
27-
import javax.servlet.http.HttpServletRequest;
28-
import javax.servlet.http.HttpServletResponse;
29-
3024
import org.junit.Test;
3125
import org.junit.runner.RunWith;
3226
import org.mockito.Mock;
3327
import org.mockito.runners.MockitoJUnitRunner;
34-
3528
import org.springframework.mock.web.MockFilterChain;
3629
import org.springframework.mock.web.MockHttpServletRequest;
3730
import org.springframework.mock.web.MockHttpServletResponse;
38-
39-
import static org.assertj.core.api.Assertions.assertThat;
40-
import static org.mockito.Matchers.any;
41-
import static org.mockito.Mockito.verify;
42-
import static org.mockito.Mockito.verifyNoMoreInteractions;
43-
import static org.mockito.Mockito.verifyZeroInteractions;
31+
import org.springframework.security.web.header.HeaderWriter;
32+
import org.springframework.security.web.header.HeaderWriterFilter;
4433

4534
/**
4635
* Tests for the {@code HeadersFilter}
@@ -71,8 +60,8 @@ public void constructorNullWriters() throws Exception {
7160
@Test
7261
public void additionalHeadersShouldBeAddedToTheResponse() throws Exception {
7362
List<HeaderWriter> headerWriters = new ArrayList<HeaderWriter>();
74-
headerWriters.add(this.writer1);
75-
headerWriters.add(this.writer2);
63+
headerWriters.add(writer1);
64+
headerWriters.add(writer2);
7665

7766
HeaderWriterFilter filter = new HeaderWriterFilter(headerWriters);
7867

@@ -82,34 +71,9 @@ public void additionalHeadersShouldBeAddedToTheResponse() throws Exception {
8271

8372
filter.doFilter(request, response, filterChain);
8473

85-
verify(this.writer1).writeHeaders(request, response);
86-
verify(this.writer2).writeHeaders(request, response);
74+
verify(writer1).writeHeaders(request, response);
75+
verify(writer2).writeHeaders(request, response);
8776
assertThat(filterChain.getRequest()).isEqualTo(request); // verify the filterChain
8877
// continued
8978
}
90-
91-
// gh-2953
92-
@Test
93-
public void headersDelayed() throws Exception {
94-
HeaderWriterFilter filter = new HeaderWriterFilter(
95-
Arrays.<HeaderWriter>asList(this.writer1));
96-
97-
MockHttpServletRequest request = new MockHttpServletRequest();
98-
MockHttpServletResponse response = new MockHttpServletResponse();
99-
100-
filter.doFilter(request, response, new FilterChain() {
101-
@Override
102-
public void doFilter(ServletRequest request, ServletResponse response)
103-
throws IOException, ServletException {
104-
verifyZeroInteractions(HeaderWriterFilterTests.this.writer1);
105-
106-
response.flushBuffer();
107-
108-
verify(HeaderWriterFilterTests.this.writer1).writeHeaders(
109-
any(HttpServletRequest.class), any(HttpServletResponse.class));
110-
}
111-
});
112-
113-
verifyNoMoreInteractions(this.writer1);
114-
}
11579
}

web/src/test/java/org/springframework/security/web/header/writers/CacheControlHeadersWriterTests.java

Lines changed: 11 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,19 @@
1515
*/
1616
package org.springframework.security.web.header.writers;
1717

18-
import java.util.Arrays;
18+
import static org.assertj.core.api.Assertions.assertThat;
1919

20-
import javax.servlet.http.HttpServletResponse;
20+
import java.util.Arrays;
2121

2222
import org.junit.Before;
2323
import org.junit.Test;
24-
import org.junit.runner.RunWith;
25-
import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
26-
import org.powermock.modules.junit4.PowerMockRunner;
27-
2824
import org.springframework.mock.web.MockHttpServletRequest;
2925
import org.springframework.mock.web.MockHttpServletResponse;
30-
import org.springframework.util.ReflectionUtils;
31-
32-
import static org.assertj.core.api.Assertions.assertThat;
33-
import static org.mockito.Matchers.anyString;
34-
import static org.mockito.Mockito.doThrow;
35-
import static org.mockito.Mockito.when;
36-
import static org.powermock.api.mockito.PowerMockito.spy;
3726

3827
/**
3928
* @author Rob Winch
4029
*
4130
*/
42-
@RunWith(PowerMockRunner.class)
43-
@PrepareOnlyThisForTest(ReflectionUtils.class)
4431
public class CacheControlHeadersWriterTests {
4532

4633
private MockHttpServletRequest request;
@@ -51,79 +38,20 @@ public class CacheControlHeadersWriterTests {
5138

5239
@Before
5340
public void setup() {
54-
this.request = new MockHttpServletRequest();
55-
this.response = new MockHttpServletResponse();
56-
this.writer = new CacheControlHeadersWriter();
41+
request = new MockHttpServletRequest();
42+
response = new MockHttpServletResponse();
43+
writer = new CacheControlHeadersWriter();
5744
}
5845

5946
@Test
6047
public void writeHeaders() {
61-
this.writer.writeHeaders(this.request, this.response);
62-
63-
assertThat(this.response.getHeaderNames().size()).isEqualTo(3);
64-
assertThat(this.response.getHeaderValues("Cache-Control")).isEqualTo(
65-
Arrays.asList("no-cache, no-store, max-age=0, must-revalidate"));
66-
assertThat(this.response.getHeaderValues("Pragma"))
67-
.isEqualTo(Arrays.asList("no-cache"));
68-
assertThat(this.response.getHeaderValues("Expires"))
69-
.isEqualTo(Arrays.asList("0"));
70-
}
71-
72-
@Test
73-
public void writeHeadersServlet25() {
74-
spy(ReflectionUtils.class);
75-
when(ReflectionUtils.findMethod(HttpServletResponse.class, "getHeader",
76-
String.class)).thenReturn(null);
77-
this.response = spy(this.response);
78-
doThrow(NoSuchMethodError.class).when(this.response).getHeader(anyString());
79-
this.writer = new CacheControlHeadersWriter();
48+
writer.writeHeaders(request, response);
8049

81-
this.writer.writeHeaders(this.request, this.response);
82-
83-
assertThat(this.response.getHeaderNames().size()).isEqualTo(3);
84-
assertThat(this.response.getHeaderValues("Cache-Control")).isEqualTo(
50+
assertThat(response.getHeaderNames().size()).isEqualTo(3);
51+
assertThat(response.getHeaderValues("Cache-Control")).isEqualTo(
8552
Arrays.asList("no-cache, no-store, max-age=0, must-revalidate"));
86-
assertThat(this.response.getHeaderValues("Pragma"))
87-
.isEqualTo(Arrays.asList("no-cache"));
88-
assertThat(this.response.getHeaderValues("Expires"))
89-
.isEqualTo(Arrays.asList("0"));
90-
}
91-
92-
// gh-2953
93-
@Test
94-
public void writeHeadersDisabledIfCacheControl() {
95-
this.response.setHeader("Cache-Control", "max-age: 123");
96-
97-
this.writer.writeHeaders(this.request, this.response);
98-
99-
assertThat(this.response.getHeaderNames()).hasSize(1);
100-
assertThat(this.response.getHeaderValues("Cache-Control"))
101-
.containsOnly("max-age: 123");
102-
assertThat(this.response.getHeaderValue("Pragma")).isNull();
103-
assertThat(this.response.getHeaderValue("Expires")).isNull();
104-
}
105-
106-
@Test
107-
public void writeHeadersDisabledIfPragma() {
108-
this.response.setHeader("Pragma", "mock");
109-
110-
this.writer.writeHeaders(this.request, this.response);
111-
112-
assertThat(this.response.getHeaderNames()).hasSize(1);
113-
assertThat(this.response.getHeaderValues("Pragma")).containsOnly("mock");
114-
assertThat(this.response.getHeaderValue("Expires")).isNull();
115-
assertThat(this.response.getHeaderValue("Cache-Control")).isNull();
116-
}
117-
118-
@Test
119-
public void writeHeadersDisabledIfExpires() {
120-
this.response.setHeader("Expires", "mock");
121-
122-
this.writer.writeHeaders(this.request, this.response);
123-
124-
assertThat(this.response.getHeaderNames()).hasSize(1);
125-
assertThat(this.response.getHeaderValues("Expires")).containsOnly("mock");
126-
assertThat(this.response.getHeaderValue("Cache-Control")).isNull();
127-
assertThat(this.response.getHeaderValue("Pragma")).isNull();
53+
assertThat(response.getHeaderValues("Pragma")).isEqualTo(
54+
Arrays.asList("no-cache"));
55+
assertThat(response.getHeaderValues("Expires")).isEqualTo(Arrays.asList("0"));
12856
}
12957
}

0 commit comments

Comments
 (0)