Commit dcebcdb6 by Ryan Baxter

Merge remote-tracking branch 'origin/1.4.x'

parents 56772eeb 82b51b7a
......@@ -157,9 +157,9 @@ In general, additional metadata does not change the behavior of the client, unle
There are a couple of special cases, described later in this document, where Spring Cloud already assigns meaning to the metadata map.
// TODO Add links from here to the relevant places in the document
==== Using Eureka on Cloudfoundry
==== Using Eureka on Cloud Foundry
Cloudfoundry has a global router so that all instances of the same app have the same hostname (other PaaS solutions with a similar architecture have the same arrangement).
Cloud Foundry has a global router so that all instances of the same app have the same hostname (other PaaS solutions with a similar architecture have the same arrangement).
This is not necessarily a barrier to using Eureka.
However, if you use the router (recommended or even mandatory, depending on the way your platform was set up), you need to explicitly set the hostname and port numbers (secure or non-secure) so that they use the router.
You might also want to use instance metadata so that you can distinguish between the instances on the client (for example, in a custom load balancer).
......@@ -173,7 +173,7 @@ eureka:
nonSecurePort: 80
----
Depending on the way the security rules are set up in your Cloudfoundry instance, you might be able to register and use the IP address of the host VM for direct service-to-service calls.
Depending on the way the security rules are set up in your Cloud Foundry instance, you might be able to register and use the IP address of the host VM for direct service-to-service calls.
This feature is not yet available on Pivotal Web Services (https://run.pivotal.io[PWS]).
==== Using Eureka on AWS
......@@ -211,7 +211,7 @@ eureka:
----
With the metadata shown in the preceding example and multiple service instances deployed on localhost, the random value is inserted there to make the instance unique.
In Cloudfoundry, the `vcap.application.instance_id` is populated automatically in a Spring Boot application, so the random value is not needed.
In Cloud Foundry, the `vcap.application.instance_id` is populated automatically in a Spring Boot application, so the random value is not needed.
=== Using the EurekaClient
......@@ -1079,7 +1079,7 @@ hystrix:
myusers-service:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
ListOfServers: http://example1.com,http://example2.com
listOfServers: http://example1.com,http://example2.com
ConnectTimeout: 1000
ReadTimeout: 3000
MaxTotalHttpConnections: 500
......
......@@ -94,7 +94,7 @@ public class OkHttpRibbonConfiguration {
@Bean
@ConditionalOnMissingBean(AbstractLoadBalancerAwareClient.class)
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
public RetryableOkHttpLoadBalancingClient okHttpLoadBalancingClient(
public RetryableOkHttpLoadBalancingClient retryableOkHttpLoadBalancingClient(
IClientConfig config,
ServerIntrospector serverIntrospector,
ILoadBalancer loadBalancer,
......@@ -112,7 +112,7 @@ public class OkHttpRibbonConfiguration {
@Bean
@ConditionalOnMissingBean(AbstractLoadBalancerAwareClient.class)
@ConditionalOnMissingClass(value = "org.springframework.retry.support.RetryTemplate")
public OkHttpLoadBalancingClient retryableOkHttpLoadBalancingClient(
public OkHttpLoadBalancingClient okHttpLoadBalancingClient(
IClientConfig config,
ServerIntrospector serverIntrospector, ILoadBalancer loadBalancer,
RetryHandler retryHandler, OkHttpClient delegate) {
......
......@@ -35,6 +35,7 @@ import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
......@@ -56,6 +57,7 @@ import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.Host;
import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;
import org.springframework.context.event.EventListener;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
......@@ -93,6 +95,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
private HttpClientConnectionManager connectionManager;
private CloseableHttpClient httpClient;
private boolean customHttpClient = false;
private boolean useServlet31 = true;
@EventListener
public void onPropertyChange(EnvironmentChangeEvent event) {
......@@ -127,6 +130,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
.isForceOriginalQueryStringEncoding();
this.connectionManagerFactory = connectionManagerFactory;
this.httpClientFactory = httpClientFactory;
checkServletVersion();
}
public SimpleHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties properties,
......@@ -138,6 +142,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
.isForceOriginalQueryStringEncoding();
this.httpClient = httpClient;
this.customHttpClient = true;
checkServletVersion();
}
@PostConstruct
......@@ -193,7 +198,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
.buildZuulRequestQueryParams(request);
String verb = getVerb(request);
InputStream requestEntity = getRequestBody(request);
if (request.getContentLength() < 0) {
if (getContentLength(request) < 0) {
context.setChunkedRequestBody();
}
......@@ -211,6 +216,21 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
return null;
}
protected void checkServletVersion() {
// To support Servlet API 3.1 we need to check if getContentLengthLong exists
// Spring 5 minimum support is 3.0, so this stays
try {
HttpServletRequest.class.getMethod("getContentLengthLong");
useServlet31 = true;
} catch(NoSuchMethodException e) {
useServlet31 = false;
}
}
protected void setUseServlet31(boolean useServlet31) {
this.useServlet31 = useServlet31;
}
protected HttpClientConnectionManager getConnectionManager() {
return connectionManager;
}
......@@ -235,7 +255,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
URL host = RequestContext.getCurrentContext().getRouteHost();
HttpHost httpHost = getHttpHost(host);
uri = StringUtils.cleanPath((host.getPath() + uri).replaceAll("/{2,}", "/"));
int contentLength = request.getContentLength();
long contentLength = getContentLength(request);
ContentType contentType = null;
......@@ -382,4 +402,19 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
boolean isSslHostnameValidationEnabled() {
return this.sslHostnameValidationEnabled;
}
// Get the header value as a long in order to more correctly proxy very large requests
protected long getContentLength(HttpServletRequest request) {
if(useServlet31){
return request.getContentLengthLong();
}
String contentLengthHeader = request.getHeader(HttpHeaders.CONTENT_LENGTH);
if (contentLengthHeader != null) {
try {
return Long.parseLong(contentLengthHeader);
}
catch (NumberFormatException e){}
}
return request.getContentLength();
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment