Skip to content

Commit 57a67a3

Browse files
committed
Header predicate option in AbstractRequestLoggingFilter
Closes gh-22244
1 parent 19c024f commit 57a67a3

File tree

2 files changed

+80
-34
lines changed

2 files changed

+80
-34
lines changed

spring-web/src/main/java/org/springframework/web/filter/AbstractRequestLoggingFilter.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -18,12 +18,15 @@
1818

1919
import java.io.IOException;
2020
import java.io.UnsupportedEncodingException;
21+
import java.util.Enumeration;
22+
import java.util.function.Predicate;
2123
import javax.servlet.FilterChain;
2224
import javax.servlet.ServletException;
2325
import javax.servlet.http.HttpServletRequest;
2426
import javax.servlet.http.HttpServletResponse;
2527
import javax.servlet.http.HttpSession;
2628

29+
import org.springframework.http.HttpHeaders;
2730
import org.springframework.http.server.ServletServerHttpRequest;
2831
import org.springframework.lang.Nullable;
2932
import org.springframework.util.Assert;
@@ -95,6 +98,9 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
9598

9699
private boolean includePayload = false;
97100

101+
@Nullable
102+
private Predicate<String> headerPredicate;
103+
98104
private int maxPayloadLength = DEFAULT_MAX_PAYLOAD_LENGTH;
99105

100106
private String beforeMessagePrefix = DEFAULT_BEFORE_MESSAGE_PREFIX;
@@ -176,6 +182,26 @@ protected boolean isIncludePayload() {
176182
return this.includePayload;
177183
}
178184

185+
/**
186+
* Configure a predicate for selecting which headers should be logged if
187+
* {@link #setIncludeHeaders(boolean)} is set to {@code true}.
188+
* <p>By default this is not set in which case all headers are logged.
189+
* @param headerPredicate the predicate to use
190+
* @since 5.2
191+
*/
192+
public void setHeaderPredicate(@Nullable Predicate<String> headerPredicate) {
193+
this.headerPredicate = headerPredicate;
194+
}
195+
196+
/**
197+
* The configured {@link #setHeaderPredicate(Predicate) headerPredicate}.
198+
* @since 5.2
199+
*/
200+
@Nullable
201+
public Predicate<String> getHeaderPredicate() {
202+
return this.headerPredicate;
203+
}
204+
179205
/**
180206
* Set the maximum length of the payload body to be included in the log message.
181207
* Default is 50 characters.
@@ -320,7 +346,17 @@ protected String createMessage(HttpServletRequest request, String prefix, String
320346
}
321347

322348
if (isIncludeHeaders()) {
323-
msg.append(";headers=").append(new ServletServerHttpRequest(request).getHeaders());
349+
HttpHeaders headers = new ServletServerHttpRequest(request).getHeaders();
350+
if (getHeaderPredicate() != null) {
351+
Enumeration<String> names = request.getHeaderNames();
352+
while (names.hasMoreElements()) {
353+
String header = names.nextElement();
354+
if (!getHeaderPredicate().test(header)) {
355+
headers.set(header, "masked");
356+
}
357+
}
358+
}
359+
msg.append(";headers=").append(headers);
324360
}
325361

326362
if (isIncludePayload()) {

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

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -17,6 +17,7 @@
1717
package org.springframework.web.filter;
1818

1919
import java.io.IOException;
20+
import java.nio.charset.StandardCharsets;
2021
import javax.servlet.FilterChain;
2122
import javax.servlet.ServletException;
2223
import javax.servlet.ServletRequest;
@@ -100,24 +101,41 @@ public void noQueryStringAvailable() throws Exception {
100101
assertTrue(filter.afterRequestMessage.contains("[uri=/hotels]"));
101102
}
102103

104+
@Test
105+
public void headers() throws Exception {
106+
final MockHttpServletRequest request = new MockHttpServletRequest("POST", "/hotels");
107+
request.setContentType("application/json");
108+
request.addHeader("token", "123");
109+
MockHttpServletResponse response = new MockHttpServletResponse();
110+
111+
FilterChain filterChain = new NoOpFilterChain();
112+
filter.setIncludeHeaders(true);
113+
filter.setHeaderPredicate(name -> !name.equalsIgnoreCase("token"));
114+
filter.doFilter(request, response, filterChain);
115+
116+
assertNotNull(filter.beforeRequestMessage);
117+
assertEquals("Before request [uri=/hotels;headers=[Content-Type:\"application/json\", token:\"masked\"]]",
118+
filter.beforeRequestMessage);
119+
120+
assertNotNull(filter.afterRequestMessage);
121+
assertEquals("After request [uri=/hotels;headers=[Content-Type:\"application/json\", token:\"masked\"]]",
122+
filter.afterRequestMessage);
123+
}
124+
103125
@Test
104126
public void payloadInputStream() throws Exception {
105127
filter.setIncludePayload(true);
106128

107129
final MockHttpServletRequest request = new MockHttpServletRequest("POST", "/hotels");
108130
MockHttpServletResponse response = new MockHttpServletResponse();
109131

110-
final byte[] requestBody = "Hello World".getBytes("UTF-8");
132+
final byte[] requestBody = "Hello World".getBytes(StandardCharsets.UTF_8);
111133
request.setContent(requestBody);
112134

113-
FilterChain filterChain = new FilterChain() {
114-
@Override
115-
public void doFilter(ServletRequest filterRequest, ServletResponse filterResponse)
116-
throws IOException, ServletException {
117-
((HttpServletResponse) filterResponse).setStatus(HttpServletResponse.SC_OK);
118-
byte[] buf = FileCopyUtils.copyToByteArray(filterRequest.getInputStream());
119-
assertArrayEquals(requestBody, buf);
120-
}
135+
FilterChain filterChain = (filterRequest, filterResponse) -> {
136+
((HttpServletResponse) filterResponse).setStatus(HttpServletResponse.SC_OK);
137+
byte[] buf = FileCopyUtils.copyToByteArray(filterRequest.getInputStream());
138+
assertArrayEquals(requestBody, buf);
121139
};
122140

123141
filter.doFilter(request, response, filterChain);
@@ -134,16 +152,12 @@ public void payloadReader() throws Exception {
134152
MockHttpServletResponse response = new MockHttpServletResponse();
135153

136154
final String requestBody = "Hello World";
137-
request.setContent(requestBody.getBytes("UTF-8"));
138-
139-
FilterChain filterChain = new FilterChain() {
140-
@Override
141-
public void doFilter(ServletRequest filterRequest, ServletResponse filterResponse)
142-
throws IOException, ServletException {
143-
((HttpServletResponse) filterResponse).setStatus(HttpServletResponse.SC_OK);
144-
String buf = FileCopyUtils.copyToString(filterRequest.getReader());
145-
assertEquals(requestBody, buf);
146-
}
155+
request.setContent(requestBody.getBytes(StandardCharsets.UTF_8));
156+
157+
FilterChain filterChain = (filterRequest, filterResponse) -> {
158+
((HttpServletResponse) filterResponse).setStatus(HttpServletResponse.SC_OK);
159+
String buf = FileCopyUtils.copyToString(filterRequest.getReader());
160+
assertEquals(requestBody, buf);
147161
};
148162

149163
filter.doFilter(request, response, filterChain);
@@ -160,20 +174,16 @@ public void payloadMaxLength() throws Exception {
160174
final MockHttpServletRequest request = new MockHttpServletRequest("POST", "/hotels");
161175
MockHttpServletResponse response = new MockHttpServletResponse();
162176

163-
final byte[] requestBody = "Hello World".getBytes("UTF-8");
177+
final byte[] requestBody = "Hello World".getBytes(StandardCharsets.UTF_8);
164178
request.setContent(requestBody);
165179

166-
FilterChain filterChain = new FilterChain() {
167-
@Override
168-
public void doFilter(ServletRequest filterRequest, ServletResponse filterResponse)
169-
throws IOException, ServletException {
170-
((HttpServletResponse) filterResponse).setStatus(HttpServletResponse.SC_OK);
171-
byte[] buf = FileCopyUtils.copyToByteArray(filterRequest.getInputStream());
172-
assertArrayEquals(requestBody, buf);
173-
ContentCachingRequestWrapper wrapper =
174-
WebUtils.getNativeRequest(filterRequest, ContentCachingRequestWrapper.class);
175-
assertArrayEquals("Hel".getBytes("UTF-8"), wrapper.getContentAsByteArray());
176-
}
180+
FilterChain filterChain = (filterRequest, filterResponse) -> {
181+
((HttpServletResponse) filterResponse).setStatus(HttpServletResponse.SC_OK);
182+
byte[] buf = FileCopyUtils.copyToByteArray(filterRequest.getInputStream());
183+
assertArrayEquals(requestBody, buf);
184+
ContentCachingRequestWrapper wrapper =
185+
WebUtils.getNativeRequest(filterRequest, ContentCachingRequestWrapper.class);
186+
assertArrayEquals("Hel".getBytes(StandardCharsets.UTF_8), wrapper.getContentAsByteArray());
177187
};
178188

179189
filter.doFilter(request, response, filterChain);

0 commit comments

Comments
 (0)