Split ProxyRequestHelper to function without Actuator.
Previously ProxyRequestHelper contained a TraceRepository field. This caused zuul apps to fail with a class not found exception if they excluded actuator. This splits TraceRepository functionality into a new TraceProxyRequestHelper that extends ProxyRequestHelper. Auto configuration creates the appropriate ProxyRequestHelper based on the existence or not of actuator classes. fixes gh-1135
This commit is contained in:
@@ -21,6 +21,7 @@ import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.actuator.HasFeatures;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
@@ -31,6 +32,7 @@ import org.springframework.cloud.client.discovery.event.ParentHeartbeatEvent;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
|
||||
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
|
||||
import org.springframework.cloud.netflix.zuul.filters.TraceProxyRequestHelper;
|
||||
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
|
||||
import org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator;
|
||||
import org.springframework.cloud.netflix.zuul.filters.discovery.ServiceRouteMapper;
|
||||
@@ -55,9 +57,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
@Configuration
|
||||
public class ZuulProxyConfiguration extends ZuulConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private TraceRepository traces;
|
||||
|
||||
@Autowired
|
||||
private DiscoveryClient discovery;
|
||||
|
||||
@@ -132,17 +131,6 @@ public class ZuulProxyConfiguration extends ZuulConfiguration {
|
||||
return new SimpleHostRoutingFilter(helper, zuulProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ProxyRequestHelper proxyRequestHelper() {
|
||||
ProxyRequestHelper helper = new ProxyRequestHelper();
|
||||
if (this.traces != null) {
|
||||
helper.setTraces(this.traces);
|
||||
}
|
||||
helper.setIgnoredHeaders(this.zuulProperties.getIgnoredHeaders());
|
||||
helper.setTraceRequestBody(this.zuulProperties.isTraceRequestBody());
|
||||
return helper;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApplicationListener<ApplicationEvent> zuulDiscoveryRefreshRoutesListener() {
|
||||
return new ZuulDiscoveryRefreshListener();
|
||||
@@ -154,15 +142,42 @@ public class ZuulProxyConfiguration extends ZuulConfiguration {
|
||||
return new SimpleServiceRouteMapper();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingClass("org.springframework.boot.actuate.endpoint.Endpoint")
|
||||
protected static class NoActuatorConfiguration {
|
||||
|
||||
@Bean
|
||||
public ProxyRequestHelper proxyRequestHelper(ZuulProperties zuulProperties) {
|
||||
ProxyRequestHelper helper = new ProxyRequestHelper();
|
||||
helper.setIgnoredHeaders(zuulProperties.getIgnoredHeaders());
|
||||
helper.setTraceRequestBody(zuulProperties.isTraceRequestBody());
|
||||
return helper;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(Endpoint.class)
|
||||
protected static class RoutesEndpointConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private TraceRepository traces;
|
||||
|
||||
@Bean
|
||||
public RoutesEndpoint zuulEndpoint(RouteLocator routeLocator) {
|
||||
return new RoutesEndpoint(routeLocator);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ProxyRequestHelper proxyRequestHelper(ZuulProperties zuulProperties) {
|
||||
TraceProxyRequestHelper helper = new TraceProxyRequestHelper();
|
||||
if (this.traces != null) {
|
||||
helper.setTraces(this.traces);
|
||||
}
|
||||
helper.setIgnoredHeaders(zuulProperties.getIgnoredHeaders());
|
||||
helper.setTraceRequestBody(zuulProperties.isTraceRequestBody());
|
||||
return helper;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ZuulDiscoveryRefreshListener
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
package org.springframework.cloud.netflix.zuul.filters;
|
||||
|
||||
import static org.springframework.http.HttpHeaders.CONTENT_ENCODING;
|
||||
import static org.springframework.http.HttpHeaders.CONTENT_LENGTH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
@@ -33,7 +34,6 @@ import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.cloud.netflix.zuul.util.RequestUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
@@ -45,14 +45,12 @@ import org.springframework.web.util.WebUtils;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import com.netflix.zuul.util.HTTPRequestUtils;
|
||||
|
||||
import static org.springframework.http.HttpHeaders.CONTENT_ENCODING;
|
||||
import static org.springframework.http.HttpHeaders.CONTENT_LENGTH;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Marcos Barbero
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public class ProxyRequestHelper {
|
||||
@@ -63,8 +61,6 @@ public class ProxyRequestHelper {
|
||||
*/
|
||||
public static final String IGNORED_HEADERS = "ignoredHeaders";
|
||||
|
||||
private TraceRepository traces;
|
||||
|
||||
private Set<String> ignoredHeaders = new LinkedHashSet<>();
|
||||
|
||||
private Set<String> sensitiveHeaders = new LinkedHashSet<>();
|
||||
@@ -85,10 +81,6 @@ public class ProxyRequestHelper {
|
||||
this.ignoredHeaders.addAll(ignoredHeaders);
|
||||
}
|
||||
|
||||
public void setTraces(TraceRepository traces) {
|
||||
this.traces = traces;
|
||||
}
|
||||
|
||||
public void setTraceRequestBody(boolean traceRequestBody) {
|
||||
this.traceRequestBody = traceRequestBody;
|
||||
}
|
||||
@@ -238,32 +230,10 @@ public class ProxyRequestHelper {
|
||||
MultiValueMap<String, String> headers, MultiValueMap<String, String> params,
|
||||
InputStream requestEntity) throws IOException {
|
||||
Map<String, Object> info = new LinkedHashMap<>();
|
||||
if (this.traces != null) {
|
||||
RequestContext context = RequestContext.getCurrentContext();
|
||||
info.put("method", verb);
|
||||
info.put("path", uri);
|
||||
info.put("query", getQueryString(params));
|
||||
info.put("remote", true);
|
||||
info.put("proxy", context.get("proxy"));
|
||||
Map<String, Object> trace = new LinkedHashMap<>();
|
||||
Map<String, Object> input = new LinkedHashMap<>();
|
||||
trace.put("request", input);
|
||||
info.put("headers", trace);
|
||||
transformHeaders(headers, input);
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
if (shouldDebugBody(ctx)) {
|
||||
// Prevent input stream from being read if it needs to go downstream
|
||||
if (requestEntity != null) {
|
||||
debugRequestEntity(info, ctx.getRequest().getInputStream());
|
||||
}
|
||||
}
|
||||
this.traces.add(info);
|
||||
return info;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/* for tests */ boolean shouldDebugBody(RequestContext ctx) {
|
||||
protected boolean shouldDebugBody(RequestContext ctx) {
|
||||
HttpServletRequest request = ctx.getRequest();
|
||||
if (!this.traceRequestBody || ctx.isChunkedRequestBody()
|
||||
|| RequestUtils.isZuulServletRequest()) {
|
||||
@@ -277,40 +247,6 @@ public class ProxyRequestHelper {
|
||||
|
||||
public void appendDebug(Map<String, Object> info, int status,
|
||||
MultiValueMap<String, String> headers) {
|
||||
if (this.traces != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> trace = (Map<String, Object>) info.get("headers");
|
||||
Map<String, Object> output = new LinkedHashMap<>();
|
||||
trace.put("response", output);
|
||||
transformHeaders(headers, output);
|
||||
output.put("status", "" + status);
|
||||
}
|
||||
}
|
||||
|
||||
void transformHeaders(MultiValueMap<String, String> headers, Map<String, Object> output) {
|
||||
for (Entry<String, List<String>> key : headers.entrySet()) {
|
||||
Collection<String> collection = key.getValue();
|
||||
Object value = collection;
|
||||
if (collection.size() < 2) {
|
||||
value = collection.isEmpty() ? "" : collection.iterator().next();
|
||||
}
|
||||
output.put(key.getKey(), value);
|
||||
}
|
||||
}
|
||||
|
||||
private void debugRequestEntity(Map<String, Object> info, InputStream inputStream)
|
||||
throws IOException {
|
||||
if (RequestContext.getCurrentContext().isChunkedRequestBody()) {
|
||||
info.put("body", "<chunked>");
|
||||
return;
|
||||
}
|
||||
char[] buffer = new char[4096];
|
||||
int count = new InputStreamReader(inputStream, Charset.forName("UTF-8"))
|
||||
.read(buffer, 0, buffer.length);
|
||||
if (count > 0) {
|
||||
String entity = new String(buffer).substring(0, count);
|
||||
info.put("body", entity.length() < 4096 ? entity : entity + "<truncated>");
|
||||
}
|
||||
}
|
||||
|
||||
public String getQueryString(MultiValueMap<String, String> params) {
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.zuul.filters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public class TraceProxyRequestHelper extends ProxyRequestHelper {
|
||||
|
||||
private TraceRepository traces;
|
||||
|
||||
public void setTraces(TraceRepository traces) {
|
||||
this.traces = traces;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> debug(String verb, String uri,
|
||||
MultiValueMap<String, String> headers, MultiValueMap<String, String> params,
|
||||
InputStream requestEntity) throws IOException {
|
||||
Map<String, Object> info = new LinkedHashMap<>();
|
||||
if (this.traces != null) {
|
||||
RequestContext context = RequestContext.getCurrentContext();
|
||||
info.put("method", verb);
|
||||
info.put("path", uri);
|
||||
info.put("query", getQueryString(params));
|
||||
info.put("remote", true);
|
||||
info.put("proxy", context.get("proxy"));
|
||||
Map<String, Object> trace = new LinkedHashMap<>();
|
||||
Map<String, Object> input = new LinkedHashMap<>();
|
||||
trace.put("request", input);
|
||||
info.put("headers", trace);
|
||||
debugHeaders(headers, input);
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
if (shouldDebugBody(ctx)) {
|
||||
// Prevent input stream from being read if it needs to go downstream
|
||||
if (requestEntity != null) {
|
||||
debugRequestEntity(info, ctx.getRequest().getInputStream());
|
||||
}
|
||||
}
|
||||
this.traces.add(info);
|
||||
return info;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
void debugHeaders(MultiValueMap<String, String> headers, Map<String, Object> map) {
|
||||
for (Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
Collection<String> collection = entry.getValue();
|
||||
Object value = collection;
|
||||
if (collection.size() < 2) {
|
||||
value = collection.isEmpty() ? "" : collection.iterator().next();
|
||||
}
|
||||
map.put(entry.getKey(), value);
|
||||
}
|
||||
}
|
||||
|
||||
public void appendDebug(Map<String, Object> info, int status,
|
||||
MultiValueMap<String, String> headers) {
|
||||
if (this.traces != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> trace = (Map<String, Object>) info.get("headers");
|
||||
Map<String, Object> output = new LinkedHashMap<String, Object>();
|
||||
trace.put("response", output);
|
||||
debugHeaders(headers, output);
|
||||
output.put("status", "" + status);
|
||||
}
|
||||
}
|
||||
|
||||
private void debugRequestEntity(Map<String, Object> info, InputStream inputStream)
|
||||
throws IOException {
|
||||
if (RequestContext.getCurrentContext().isChunkedRequestBody()) {
|
||||
info.put("body", "<chunked>");
|
||||
return;
|
||||
}
|
||||
char[] buffer = new char[4096];
|
||||
int count = new InputStreamReader(inputStream, Charset.forName("UTF-8"))
|
||||
.read(buffer, 0, buffer.length);
|
||||
if (count > 0) {
|
||||
String entity = new String(buffer).substring(0, count);
|
||||
info.put("body", entity.length() < 4096 ? entity : entity + "<truncated>");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public class ProxyRequestHelperTests {
|
||||
request.addHeader("multiName", "multiValue2");
|
||||
RequestContext.getCurrentContext().setRequest(request);
|
||||
|
||||
ProxyRequestHelper helper = new ProxyRequestHelper();
|
||||
TraceProxyRequestHelper helper = new TraceProxyRequestHelper();
|
||||
this.traceRepository = new InMemoryTraceRepository();
|
||||
helper.setTraces(this.traceRepository);
|
||||
|
||||
@@ -172,7 +172,7 @@ public class ProxyRequestHelperTests {
|
||||
request.addHeader("multiName", "multiValue1");
|
||||
request.addHeader("multiName", "multiValue2");
|
||||
|
||||
ProxyRequestHelper helper = new ProxyRequestHelper();
|
||||
TraceProxyRequestHelper helper = new TraceProxyRequestHelper();
|
||||
helper.setTraces(this.traceRepository);
|
||||
|
||||
MultiValueMap<String, String> headers = helper.buildZuulRequestHeaders(request);
|
||||
|
||||
Reference in New Issue
Block a user