Skip to content

Commit f81b581

Browse files
committed
Cache headers only if no cache headers set
Fixes: gh-5005
1 parent 0e02b48 commit f81b581

File tree

4 files changed

+108
-26
lines changed

4 files changed

+108
-26
lines changed

config/src/test/java/org/springframework/security/config/annotation/web/HttpSecurityHeadersTests.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ public void headerWhenSpringMvcResourceThenCacheRelatedHeadersReset() throws Exc
7171
mockMvc.perform(get("/resources/file.js"))
7272
.andExpect(status().isOk())
7373
.andExpect(header().string(HttpHeaders.CACHE_CONTROL,"max-age=12345"))
74-
.andExpect(header().string(HttpHeaders.PRAGMA, ""))
75-
.andExpect(header().string(HttpHeaders.EXPIRES, ""));
74+
.andExpect(header().doesNotExist(HttpHeaders.PRAGMA))
75+
.andExpect(header().doesNotExist(HttpHeaders.EXPIRES));
7676
}
7777

7878
@Test

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

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

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

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

2830
/**
2931
* Filter implementation to add headers to the current response. Can be useful to add
@@ -56,12 +58,52 @@ public HeaderWriterFilter(List<HeaderWriter> headerWriters) {
5658
@Override
5759
protected void doFilterInternal(HttpServletRequest request,
5860
HttpServletResponse response, FilterChain filterChain)
59-
throws ServletException, IOException {
61+
throws ServletException, IOException {
6062

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

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+
}
67109
}

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

+43-7
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,32 @@
1515
*/
1616
package org.springframework.security.web.header;
1717

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

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+
2430
import org.junit.Test;
2531
import org.junit.runner.RunWith;
2632
import org.mockito.Mock;
2733
import org.mockito.runners.MockitoJUnitRunner;
34+
2835
import org.springframework.mock.web.MockFilterChain;
2936
import org.springframework.mock.web.MockHttpServletRequest;
3037
import org.springframework.mock.web.MockHttpServletResponse;
31-
import org.springframework.security.web.header.HeaderWriter;
32-
import org.springframework.security.web.header.HeaderWriterFilter;
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;
3344

3445
/**
3546
* Tests for the {@code HeadersFilter}
@@ -71,9 +82,34 @@ public void additionalHeadersShouldBeAddedToTheResponse() throws Exception {
7182

7283
filter.doFilter(request, response, filterChain);
7384

74-
verify(writer1).writeHeaders(request, response);
75-
verify(writer2).writeHeaders(request, response);
85+
verify(this.writer1).writeHeaders(request, response);
86+
verify(this.writer2).writeHeaders(request, response);
7687
assertThat(filterChain.getRequest()).isEqualTo(request); // verify the filterChain
7788
// continued
7889
}
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+
}
79115
}

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

+13-9
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ public void setup() {
6060
public void writeHeaders() {
6161
this.writer.writeHeaders(this.request, this.response);
6262

63-
assertThat(this.response.getHeaderNames()).hasSize(3);
64-
assertThat(this.response.getHeaderValues("Cache-Control")).containsExactly(
63+
assertThat(this.response.getHeaderNames().size()).isEqualTo(3);
64+
assertThat(this.response.getHeaderValues("Cache-Control")).containsOnly(
6565
"no-cache, no-store, max-age=0, must-revalidate");
66-
assertThat(this.response.getHeaderValues("Pragma")).containsOnly("no-cache");
67-
assertThat(this.response.getHeaderValues("Expires")).containsOnly("0");
66+
assertThat(this.response.getHeaderValues("Pragma"))
67+
.containsOnly("no-cache");
68+
assertThat(this.response.getHeaderValues("Expires"))
69+
.containsOnly("0");
6870
}
6971

7072
@Test
@@ -78,11 +80,13 @@ public void writeHeadersServlet25() {
7880

7981
this.writer.writeHeaders(this.request, this.response);
8082

81-
assertThat(this.response.getHeaderNames()).hasSize(3);
82-
assertThat(this.response.getHeaderValues("Cache-Control")).containsExactly(
83-
"no-cache, no-store, max-age=0, must-revalidate");
84-
assertThat(this.response.getHeaderValues("Pragma")).containsOnly("no-cache");
85-
assertThat(this.response.getHeaderValues("Expires")).containsOnly("0");
83+
assertThat(this.response.getHeaderNames().size()).isEqualTo(3);
84+
assertThat(this.response.getHeaderValues("Cache-Control"))
85+
.containsOnly("no-cache, no-store, max-age=0, must-revalidate");
86+
assertThat(this.response.getHeaderValues("Pragma"))
87+
.containsOnly("no-cache");
88+
assertThat(this.response.getHeaderValues("Expires"))
89+
.containsOnly("0");
8690
}
8791

8892
// gh-2953

0 commit comments

Comments
 (0)