mirror of
https://github.com/spring-cloud/spring-cloud-netflix.git
synced 2026-09-19 16:49:01 +00:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
931f058068 | ||
|
|
c1dd0a6b6d | ||
|
|
c57a0e323c | ||
|
|
e1dca45c10 | ||
|
|
a8282dd0bd | ||
|
|
9e3e749438 | ||
|
|
434305de19 | ||
|
|
a9c0fc1502 | ||
|
|
9dafae6c01 | ||
|
|
f538444dee | ||
|
|
99beb9d045 | ||
|
|
4cada7c8cc | ||
|
|
34dff916cf | ||
|
|
7e9faef2e7 | ||
|
|
476a5cb84c | ||
|
|
cfa4302965 | ||
|
|
5d6590da44 |
@@ -14,3 +14,4 @@ _site/
|
||||
*.ipr
|
||||
*.iws
|
||||
.factorypath
|
||||
.shelf
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-docs</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<relativePath />
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Netflix</name>
|
||||
<description>Spring Cloud Netflix</description>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-core</artifactId>
|
||||
|
||||
+4
-1
@@ -114,7 +114,10 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
private boolean isSecure(Server server, String serviceId) {
|
||||
IClientConfig config = this.clientFactory.getClientConfig(serviceId);
|
||||
if (config != null) {
|
||||
return config.get(CommonClientConfigKey.IsSecure, false);
|
||||
Boolean isSecure = config.get(CommonClientConfigKey.IsSecure);
|
||||
if (isSecure != null) {
|
||||
return isSecure;
|
||||
}
|
||||
}
|
||||
|
||||
return serverIntrospector(serviceId).isSecure(server);
|
||||
|
||||
+16
-1
@@ -37,6 +37,7 @@ import lombok.Getter;
|
||||
public class RibbonApacheHttpRequest extends ClientRequest implements Cloneable {
|
||||
|
||||
private final String method;
|
||||
private Long contentLength;
|
||||
|
||||
private final MultiValueMap<String, String> headers;
|
||||
|
||||
@@ -44,11 +45,18 @@ public class RibbonApacheHttpRequest extends ClientRequest implements Cloneable
|
||||
|
||||
private final InputStream requestEntity;
|
||||
|
||||
public RibbonApacheHttpRequest(final String method, final URI uri,
|
||||
final Boolean retryable, final MultiValueMap<String, String> headers,
|
||||
final MultiValueMap<String, String> params, final InputStream requestEntity) {
|
||||
this(method, uri, retryable, headers, params, requestEntity, null);
|
||||
}
|
||||
|
||||
public RibbonApacheHttpRequest(final String method, final URI uri,
|
||||
final Boolean retryable, final MultiValueMap<String, String> headers,
|
||||
final MultiValueMap<String, String> params, final InputStream requestEntity) {
|
||||
final MultiValueMap<String, String> params, final InputStream requestEntity, Long contentLength) {
|
||||
|
||||
this.method = method;
|
||||
this.contentLength = contentLength;
|
||||
this.uri = uri;
|
||||
this.isRetriable = retryable;
|
||||
this.headers = headers;
|
||||
@@ -77,6 +85,13 @@ public class RibbonApacheHttpRequest extends ClientRequest implements Cloneable
|
||||
final BasicHttpEntity entity;
|
||||
entity = new BasicHttpEntity();
|
||||
entity.setContent(this.requestEntity);
|
||||
// if the entity contentLength isn't set, transfer-encoding will be set
|
||||
// to chunked in org.apache.http.protocol.RequestContent. See gh-1042
|
||||
if (contentLength != null) {
|
||||
entity.setContentLength(this.contentLength);
|
||||
} else if ("GET".equals(this.method)) {
|
||||
entity.setContentLength(0);
|
||||
}
|
||||
builder.setEntity(entity);
|
||||
}
|
||||
|
||||
|
||||
+29
-14
@@ -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.cloud.client.actuator.HasFeatures;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
|
||||
@@ -30,6 +31,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;
|
||||
@@ -52,9 +54,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
@Configuration
|
||||
public class ZuulProxyConfiguration extends ZuulConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private TraceRepository traces;
|
||||
|
||||
@Autowired
|
||||
private SpringClientFactory clientFactory;
|
||||
|
||||
@@ -108,17 +107,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();
|
||||
@@ -130,15 +118,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
|
||||
|
||||
+5
-72
@@ -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,39 +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);
|
||||
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();
|
||||
}
|
||||
input.put(entry.getKey(), value);
|
||||
}
|
||||
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()) {
|
||||
@@ -284,36 +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<String, Object>();
|
||||
trace.put("response", 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);
|
||||
}
|
||||
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>");
|
||||
}
|
||||
}
|
||||
|
||||
public String getQueryString(MultiValueMap<String, String> params) {
|
||||
|
||||
+117
@@ -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>");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+7
-1
@@ -111,7 +111,7 @@ public class ZuulProperties {
|
||||
private boolean traceRequestBody = true;
|
||||
|
||||
/**
|
||||
* Flag to say that path elelents past the first semicolon can be dropped.
|
||||
* Flag to say that path elements past the first semicolon can be dropped.
|
||||
*/
|
||||
private boolean removeSemicolonContent = true;
|
||||
|
||||
@@ -125,6 +125,12 @@ public class ZuulProperties {
|
||||
private Set<String> sensitiveHeaders = new LinkedHashSet<>(
|
||||
Arrays.asList("Cookie", "Set-Cookie", "Authorization"));
|
||||
|
||||
/**
|
||||
* Flag to say whether the hostname for ssl connections should be verified or not. Default is true.
|
||||
* This should only be used in test setups!
|
||||
*/
|
||||
private boolean sslHostnameValidationEnabled =true;
|
||||
|
||||
public Set<String> getIgnoredHeaders() {
|
||||
Set<String> ignoredHeaders = new LinkedHashSet<>(this.ignoredHeaders);
|
||||
if (ClassUtils.isPresent(
|
||||
|
||||
+28
-6
@@ -53,11 +53,13 @@ import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
@@ -66,7 +68,6 @@ import org.apache.http.protocol.HttpContext;
|
||||
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
|
||||
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
|
||||
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.Host;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -94,6 +95,8 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
private final Timer connectionManagerTimer = new Timer(
|
||||
"SimpleHostRoutingFilter.connectionManagerTimer", true);
|
||||
|
||||
private boolean sslHostnameValidationEnabled;
|
||||
|
||||
private ProxyRequestHelper helper;
|
||||
private Host hostProperties;
|
||||
private PoolingHttpClientConnectionManager connectionManager;
|
||||
@@ -115,6 +118,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
public SimpleHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties properties) {
|
||||
this.helper = helper;
|
||||
this.hostProperties = properties.getHost();
|
||||
this.sslHostnameValidationEnabled = properties.isSslHostnameValidationEnabled();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@@ -204,11 +208,18 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
}
|
||||
} }, new SecureRandom());
|
||||
|
||||
final Registry<ConnectionSocketFactory> registry = RegistryBuilder
|
||||
RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder
|
||||
.<ConnectionSocketFactory> create()
|
||||
.register("http", PlainConnectionSocketFactory.INSTANCE)
|
||||
.register("https", new SSLConnectionSocketFactory(sslContext))
|
||||
.build();
|
||||
.register("http", PlainConnectionSocketFactory.INSTANCE);
|
||||
if (sslHostnameValidationEnabled) {
|
||||
registryBuilder.register("https",
|
||||
new SSLConnectionSocketFactory(sslContext));
|
||||
}
|
||||
else {
|
||||
registryBuilder.register("https", new SSLConnectionSocketFactory(
|
||||
sslContext, NoopHostnameVerifier.INSTANCE));
|
||||
}
|
||||
final Registry<ConnectionSocketFactory> registry = registryBuilder.build();
|
||||
|
||||
this.connectionManager = new PoolingHttpClientConnectionManager(registry);
|
||||
this.connectionManager
|
||||
@@ -228,7 +239,11 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
.setConnectTimeout(CONNECTION_TIMEOUT.get())
|
||||
.setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
|
||||
|
||||
return HttpClients.custom().setConnectionManager(newConnectionManager())
|
||||
HttpClientBuilder httpClientBuilder = HttpClients.custom();
|
||||
if (!sslHostnameValidationEnabled) {
|
||||
httpClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
|
||||
}
|
||||
return httpClientBuilder.setConnectionManager(newConnectionManager())
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
|
||||
.setRedirectStrategy(new RedirectStrategy() {
|
||||
@@ -363,4 +378,11 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
this.helper.addIgnoredHeaders(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the filter enables the validation for ssl hostnames.
|
||||
* @return
|
||||
*/
|
||||
boolean isSslHostnameValidationEnabled() {
|
||||
return sslHostnameValidationEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -35,6 +35,7 @@ import com.netflix.hystrix.HystrixCommandKey;
|
||||
import com.netflix.hystrix.HystrixCommandProperties;
|
||||
import com.netflix.zuul.constants.ZuulConstants;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Christian Lohmann
|
||||
@@ -100,10 +101,15 @@ public class HttpClientRibbonCommand extends HystrixCommand<ClientHttpResponse>
|
||||
|
||||
protected ClientHttpResponse forward() throws Exception {
|
||||
final RequestContext context = RequestContext.getCurrentContext();
|
||||
Long contentLength = null;
|
||||
String contentLengthHeader = context.getRequest().getHeader("Content-Length");
|
||||
if (StringUtils.hasText(contentLengthHeader)) {
|
||||
contentLength = new Long(contentLengthHeader);
|
||||
}
|
||||
URI uriInstance = new URI(this.uri);
|
||||
RibbonApacheHttpRequest request = new RibbonApacheHttpRequest(this.method,
|
||||
uriInstance, this.retryable, this.headers, this.params,
|
||||
this.requestEntity);
|
||||
this.requestEntity, contentLength);
|
||||
final RibbonApacheHttpResponse response = this.client
|
||||
.executeWithLoadBalancer(request);
|
||||
context.set("ribbonResponse", response);
|
||||
|
||||
+33
-1
@@ -112,7 +112,7 @@ public class RibbonLoadBalancerClientTests {
|
||||
public void testReconstructUriWithSecureClientConfig() {
|
||||
RibbonServer server = getRibbonServer();
|
||||
IClientConfig config = mock(IClientConfig.class);
|
||||
when(config.get(CommonClientConfigKey.IsSecure, false)).thenReturn(true);
|
||||
when(config.get(CommonClientConfigKey.IsSecure)).thenReturn(true);
|
||||
when(clientFactory.getClientConfig(server.getServiceId())).thenReturn(config);
|
||||
|
||||
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
|
||||
@@ -124,6 +124,33 @@ public class RibbonLoadBalancerClientTests {
|
||||
assertEquals("https", uri.getScheme());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
public void testReconstructSecureUriWithoutScheme() {
|
||||
testReconstructSchemelessUriWithoutClientConfig(getSecureRibbonServer(), "https");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
public void testReconstructUnsecureSchemelessUri() {
|
||||
testReconstructSchemelessUriWithoutClientConfig(getRibbonServer(), "http");
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void testReconstructSchemelessUriWithoutClientConfig(RibbonServer server, String expectedScheme) {
|
||||
IClientConfig config = mock(IClientConfig.class);
|
||||
when(config.get(CommonClientConfigKey.IsSecure)).thenReturn(null);
|
||||
when(clientFactory.getClientConfig(server.getServiceId())).thenReturn(config);
|
||||
|
||||
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
|
||||
ServiceInstance serviceInstance = client.choose(server.getServiceId());
|
||||
URI uri = client.reconstructURI(serviceInstance,
|
||||
new URI("//" + server.getServiceId()));
|
||||
assertEquals(server.getHost(), uri.getHost());
|
||||
assertEquals(server.getPort(), uri.getPort());
|
||||
assertEquals(expectedScheme, uri.getScheme());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChoose() {
|
||||
RibbonServer server = getRibbonServer();
|
||||
@@ -206,6 +233,11 @@ public class RibbonLoadBalancerClientTests {
|
||||
Collections.singletonMap("mykey", "myvalue"));
|
||||
}
|
||||
|
||||
protected RibbonServer getSecureRibbonServer() {
|
||||
return new RibbonServer("testService", new Server("myhost", 8443), false,
|
||||
Collections.singletonMap("mykey", "myvalue"));
|
||||
}
|
||||
|
||||
protected void verifyServerStats() {
|
||||
verify(this.serverStats).incrementActiveRequestsCount();
|
||||
verify(this.serverStats).decrementActiveRequestsCount();
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.ribbon.apache;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.junit.Test;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class RibbonApacheHttpRequestTests {
|
||||
|
||||
@Test
|
||||
public void testNullEntity() throws Exception {
|
||||
URI uri = URI.create("http://example.com");
|
||||
LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||
headers.add("my-header", "my-value");
|
||||
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("myparam", "myparamval");
|
||||
RibbonApacheHttpRequest httpRequest = new RibbonApacheHttpRequest("GET", uri, false,
|
||||
headers, params, null);
|
||||
|
||||
HttpUriRequest request = httpRequest.toRequest(RequestConfig.custom().build());
|
||||
|
||||
assertThat("request is wrong type", request, is(not(instanceOf(HttpEntityEnclosingRequest.class))));
|
||||
assertThat("uri is wrong", request.getURI().toString(), startsWith(uri.toString()));
|
||||
assertThat("my-header is missing", request.getFirstHeader("my-header"), is(notNullValue()));
|
||||
assertThat("my-header is wrong", request.getFirstHeader("my-header").getValue(), is(equalTo("my-value")));
|
||||
assertThat("myparam is missing", request.getURI().getQuery(), is(equalTo("myparam=myparamval")));
|
||||
}
|
||||
|
||||
@Test
|
||||
// this situation happens, see https://github.com/spring-cloud/spring-cloud-netflix/issues/1042#issuecomment-227723877
|
||||
public void testEmptyEntityGet() throws Exception {
|
||||
String entityValue = "";
|
||||
testEntity(entityValue, new ByteArrayInputStream(entityValue.getBytes()), false, "GET");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonEmptyEntityPost() throws Exception {
|
||||
String entityValue = "abcd";
|
||||
testEntity(entityValue, new ByteArrayInputStream(entityValue.getBytes()), true, "POST");
|
||||
}
|
||||
|
||||
void testEntity(String entityValue, ByteArrayInputStream requestEntity, boolean addContentLengthHeader, String method) throws IOException {
|
||||
String lengthString = String.valueOf(entityValue.length());
|
||||
Long length = null;
|
||||
URI uri = URI.create("http://example.com");
|
||||
LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||
if (addContentLengthHeader) {
|
||||
headers.add("Content-Length", lengthString);
|
||||
length = (long) entityValue.length();
|
||||
}
|
||||
RibbonApacheHttpRequest httpRequest = new RibbonApacheHttpRequest(method, uri, false,
|
||||
headers, new LinkedMultiValueMap<String, String>(), requestEntity,
|
||||
length);
|
||||
|
||||
HttpUriRequest request = httpRequest.toRequest(RequestConfig.custom().build());
|
||||
|
||||
assertThat("request is wrong type", request, is(instanceOf(HttpEntityEnclosingRequest.class)));
|
||||
assertThat("uri is wrong", request.getURI().toString(), startsWith(uri.toString()));
|
||||
if (addContentLengthHeader) {
|
||||
assertThat("Content-Length is missing", request.getFirstHeader("Content-Length"), is(notNullValue()));
|
||||
assertThat("Content-Length is wrong", request.getFirstHeader("Content-Length").getValue(),
|
||||
is(equalTo(lengthString)));
|
||||
}
|
||||
|
||||
HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) request;
|
||||
assertThat("entity is missing", entityRequest.getEntity(), is(notNullValue()));
|
||||
HttpEntity entity = entityRequest.getEntity();
|
||||
assertThat("contentLength is wrong", entity.getContentLength(), is(equalTo((long)entityValue.length())));
|
||||
assertThat("content is missing", entity.getContent(), is(notNullValue()));
|
||||
String string = StreamUtils.copyToString(entity.getContent(), Charset.forName("UTF-8"));
|
||||
assertThat("content is wrong", string, is(equalTo(entityValue)));
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+17
@@ -28,6 +28,8 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.boot.test.EnvironmentTestUtils.addEnvironment;
|
||||
|
||||
/**
|
||||
@@ -54,6 +56,21 @@ public class SimpleHostRoutingFilterTests {
|
||||
assertEquals(10, connMgr.getDefaultMaxPerRoute());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateSslHostnamesByDefault() {
|
||||
setupContext();
|
||||
assertTrue("Hostname verification should be enabled by default",
|
||||
getFilter().isSslHostnameValidationEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationOfSslHostnamesCanBeDisabledViaProperty() {
|
||||
addEnvironment(this.context, "zuul.sslHostnameValidationEnabled=false");
|
||||
setupContext();
|
||||
assertFalse("Hostname verification should be disabled via property",
|
||||
getFilter().isSslHostnameValidationEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultPropertiesAreApplied() {
|
||||
setupContext();
|
||||
|
||||
@@ -9,16 +9,16 @@
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>spring-cloud-netflix-dependencies</name>
|
||||
<description>Spring Cloud Netflix Dependencies</description>
|
||||
<properties>
|
||||
<spring-cloud-commons.version>1.1.2.BUILD-SNAPSHOT</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>1.1.2.BUILD-SNAPSHOT</spring-cloud-config.version>
|
||||
<spring-cloud-stream.version>1.0.3.BUILD-SNAPSHOT</spring-cloud-stream.version>
|
||||
<spring-cloud-commons.version>1.1.1.RELEASE</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>1.1.2.RELEASE</spring-cloud-config.version>
|
||||
<spring-cloud-stream.version>1.0.2.RELEASE</spring-cloud-stream.version>
|
||||
<archaius.version>0.7.4</archaius.version>
|
||||
<eureka.version>1.4.8</eureka.version>
|
||||
<eureka.version>1.4.9</eureka.version>
|
||||
<feign.version>8.16.2</feign.version>
|
||||
<hystrix.version>1.5.3</hystrix.version>
|
||||
<ribbon.version>2.2.0</ribbon.version>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
|
||||
|
||||
+27
-13
@@ -11,7 +11,9 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.Version;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
@@ -36,9 +38,13 @@ public class CloudJacksonJson extends LegacyJacksonJson {
|
||||
|
||||
protected final CloudJacksonCodec codec = new CloudJacksonCodec();
|
||||
|
||||
public CloudJacksonCodec getCodec() {
|
||||
return codec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String codecName() {
|
||||
return getCodecName(this.getClass());
|
||||
return getCodecName(LegacyJacksonJson.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,25 +126,26 @@ public class CloudJacksonJson extends LegacyJacksonJson {
|
||||
|
||||
static class CloudInstanceInfoSerializer extends InstanceInfoSerializer {
|
||||
@Override
|
||||
public void serialize(InstanceInfo info, JsonGenerator jgen,
|
||||
public void serialize(final InstanceInfo info, JsonGenerator jgen,
|
||||
SerializerProvider provider) throws IOException {
|
||||
|
||||
if (info.getInstanceId() == null && info.getMetadata() != null) {
|
||||
String instanceId = calculateInstanceId(info);
|
||||
info = new InstanceInfo.Builder(info).setInstanceId(instanceId).build();
|
||||
}
|
||||
|
||||
super.serialize(info, jgen, provider);
|
||||
InstanceInfo updated = updateIfNeeded(info);
|
||||
super.serialize(updated, jgen, provider);
|
||||
}
|
||||
}
|
||||
|
||||
private String calculateInstanceId(InstanceInfo info) {
|
||||
static InstanceInfo updateIfNeeded(final InstanceInfo info) {
|
||||
if (info.getInstanceId() == null && info.getMetadata() != null) {
|
||||
String instanceId = info.getMetadata().get("instanceId");
|
||||
String hostName = info.getHostName();
|
||||
if (instanceId != null && StringUtils.hasText(hostName) && !instanceId.startsWith(hostName)) {
|
||||
instanceId = hostName + ":" + instanceId;
|
||||
if (StringUtils.hasText(instanceId)) {
|
||||
// backwards compatibility for Angel
|
||||
if (StringUtils.hasText(info.getHostName()) && !instanceId.startsWith(info.getHostName())) {
|
||||
instanceId = info.getHostName()+":"+instanceId;
|
||||
}
|
||||
return new InstanceInfo.Builder(info).setInstanceId(instanceId).build();
|
||||
}
|
||||
return instanceId == null ? hostName : instanceId;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
static class CloudInstanceInfoDeserializer extends InstanceInfoDeserializer {
|
||||
@@ -146,5 +153,12 @@ public class CloudJacksonJson extends LegacyJacksonJson {
|
||||
protected CloudInstanceInfoDeserializer(ObjectMapper mapper) {
|
||||
super(mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstanceInfo deserialize(JsonParser jp, DeserializationContext context) throws IOException {
|
||||
InstanceInfo info = super.deserialize(jp, context);
|
||||
InstanceInfo updated = updateIfNeeded(info);
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-2
@@ -52,6 +52,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
|
||||
import com.netflix.appinfo.ApplicationInfoManager;
|
||||
import com.netflix.discovery.EurekaClient;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
import com.netflix.discovery.converters.EurekaJacksonCodec;
|
||||
import com.netflix.discovery.converters.wrappers.CodecWrapper;
|
||||
import com.netflix.discovery.converters.wrappers.CodecWrappers;
|
||||
import com.netflix.eureka.DefaultEurekaServerContext;
|
||||
@@ -102,6 +103,7 @@ public class EurekaServerConfiguration extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Value("${eureka.server.defaultOpenForTrafficCount:1}")
|
||||
private int defaultOpenForTrafficCount;
|
||||
public static final CloudJacksonJson JACKSON_JSON = new CloudJacksonJson();
|
||||
|
||||
@Bean
|
||||
public HasFeatures eurekaServerFeature() {
|
||||
@@ -128,15 +130,19 @@ public class EurekaServerConfiguration extends WebMvcConfigurerAdapter {
|
||||
return new EurekaController(this.applicationInfoManager);
|
||||
}
|
||||
|
||||
static {
|
||||
CodecWrappers.registerWrapper(JACKSON_JSON);
|
||||
EurekaJacksonCodec.setInstance(JACKSON_JSON.getCodec());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServerCodecs serverCodecs() {
|
||||
CodecWrappers.registerWrapper(new CloudJacksonJson());
|
||||
return new CloudServerCodecs(this.eurekaServerConfig);
|
||||
}
|
||||
|
||||
private static CodecWrapper getFullJson(EurekaServerConfig serverConfig) {
|
||||
CodecWrapper codec = CodecWrappers.getCodec(serverConfig.getJsonCodecName());
|
||||
return codec == null ? CodecWrappers.getCodec(CloudJacksonJson.class) : codec;
|
||||
return codec == null ? CodecWrappers.getCodec(JACKSON_JSON.codecName()) : codec;
|
||||
}
|
||||
|
||||
private static CodecWrapper getFullXml(EurekaServerConfig serverConfig) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-hystrix-amqp</artifactId>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<properties>
|
||||
|
||||
-3
@@ -114,9 +114,6 @@
|
||||
convertAvg(data, "errorPercentage", true);
|
||||
convertAvg(data, "latencyExecute_mean", false);
|
||||
convertAvg(data, "latencyTotal_mean", false);
|
||||
|
||||
// the following will break when it becomes a compound string if the property is dynamically changed
|
||||
convertAvg(data, "propertyValue_metricsRollingStatisticalWindowInMilliseconds", false);
|
||||
}
|
||||
|
||||
function convertAvg(data, key, decimal) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-hystrix-stream</artifactId>
|
||||
|
||||
+9
-2
@@ -23,11 +23,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.actuator.HasFeatures;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.annotation.Output;
|
||||
import org.springframework.cloud.stream.config.BindingProperties;
|
||||
import org.springframework.cloud.stream.config.ChannelBindingServiceProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import com.netflix.hystrix.HystrixCircuitBreaker;
|
||||
@@ -57,6 +60,10 @@ public class HystrixStreamAutoConfiguration {
|
||||
@Autowired
|
||||
private HystrixStreamProperties properties;
|
||||
|
||||
@Autowired
|
||||
@Output(HystrixStreamClient.OUTPUT)
|
||||
private MessageChannel outboundChannel;
|
||||
|
||||
@Bean
|
||||
public HasFeatures hystrixStreamQueueFeature() {
|
||||
return HasFeatures.namedFeature("Hystrix Stream (Queue)",
|
||||
@@ -87,8 +94,8 @@ public class HystrixStreamAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HystrixStreamTask hystrixStreamTask() {
|
||||
return new HystrixStreamTask();
|
||||
public HystrixStreamTask hystrixStreamTask(DiscoveryClient discoveryClient) {
|
||||
return new HystrixStreamTask(this.outboundChannel, discoveryClient, this.properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
@@ -28,14 +28,28 @@ import lombok.Data;
|
||||
@Data
|
||||
public class HystrixStreamProperties {
|
||||
|
||||
/** Flag to indicate that Hystrix Stream is enabled. Default is true. */
|
||||
private boolean enabled = true;
|
||||
|
||||
/** Flag to indicate to prefix metric names with serviceId. Default is true. */
|
||||
private boolean prefixMetricName = true;
|
||||
|
||||
/** Flag to indicate to send the id field in the metrics. Default is true */
|
||||
private boolean sendId = true;
|
||||
|
||||
/** The destination of the stream. Destination as defined by Spring Cloud Stream. Defaults to springCloudHystrixStream */
|
||||
private String destination = HystrixConstants.HYSTRIX_STREAM_DESTINATION;
|
||||
|
||||
/** The content type of the messages. Defaults to application/json */
|
||||
private String contentType = "application/json";
|
||||
|
||||
/** How often (in ms) to send messages to the stream. Defaults to 500. */
|
||||
private long sendRate = 500;
|
||||
|
||||
/** How often to put messages in the queue. This queue drains to the stream. Defaults to 500. */
|
||||
private long gatherRate = 500;
|
||||
|
||||
/** The size of the metrics queue. This queue drains to the stream. Defaults to 1000. */
|
||||
private int size = 1000;
|
||||
|
||||
}
|
||||
|
||||
+11
-11
@@ -23,10 +23,8 @@ import java.util.Collection;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.stream.annotation.Output;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
@@ -55,24 +53,26 @@ import lombok.extern.apachecommons.CommonsLog;
|
||||
@CommonsLog
|
||||
public class HystrixStreamTask implements ApplicationContextAware {
|
||||
|
||||
@Autowired
|
||||
@Output(HystrixStreamClient.OUTPUT)
|
||||
private MessageChannel outboundChannel;
|
||||
|
||||
@Autowired
|
||||
private DiscoveryClient discoveryClient;
|
||||
|
||||
private HystrixStreamProperties properties;
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private HystrixStreamProperties properties;
|
||||
|
||||
// Visible for testing
|
||||
final LinkedBlockingQueue<String> jsonMetrics = new LinkedBlockingQueue<>(
|
||||
1000);
|
||||
final LinkedBlockingQueue<String> jsonMetrics;
|
||||
|
||||
private final JsonFactory jsonFactory = new JsonFactory();
|
||||
|
||||
public HystrixStreamTask(MessageChannel outboundChannel, DiscoveryClient discoveryClient, HystrixStreamProperties properties) {
|
||||
this.outboundChannel = outboundChannel;
|
||||
this.discoveryClient = discoveryClient;
|
||||
this.properties = properties;
|
||||
this.jsonMetrics = new LinkedBlockingQueue<>(properties.getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
@@ -95,7 +95,7 @@ public class HystrixStreamTask implements ApplicationContextAware {
|
||||
// TODO: remove the explicit content type when s-c-stream can handle that for us
|
||||
this.outboundChannel.send(MessageBuilder.withPayload(json)
|
||||
.setHeader(MessageHeaders.CONTENT_TYPE,
|
||||
"application/json")
|
||||
this.properties.getContentType())
|
||||
.build());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
|
||||
+2
-1
@@ -61,8 +61,9 @@ public class HystrixStreamTaskTests {
|
||||
new HystrixPropertiesCommandDefault(hystrixCommandKey, HystrixCommandProperties.defaultSetter()));
|
||||
given(this.discoveryClient.getLocalServiceInstance()).willReturn(this.serviceInstance);
|
||||
|
||||
this.hystrixStreamTask.setApplicationContext(this.context);
|
||||
this.hystrixStreamTask.gatherMetrics();
|
||||
|
||||
assertThat(this.hystrixStreamTask.jsonMetrics.isEmpty(), is(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-sidecar</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-spectator</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-turbine-stream</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-turbine</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-archaius</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-atlas</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-eureka-server</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-eureka</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-feign</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-hystrix</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-ribbon</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-spectator</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-turbine-amqp</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-turbine-stream</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-turbine</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.1.3.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.4.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-zuul</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user