From 053296de939831c4c72f6871d779f7cf4122c2c7 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 18 Jan 2016 16:46:37 +0000 Subject: [PATCH] Ensure request body is not buffered when direct to ZuulServlet A change in Zuul in NetflixOSS means that it buffers all requests unless you switch it off at the level of the servlet. And even when you do that you need to ensure that Spring Cloud doesn't re-introduce a buffer through the Servlet30RequestWrapper. This change restores the feature in Spring Cloud Angel that multipart files posted to /zuul/* go straight through the servlet and are not buffered in memory. Fixes gh-773 --- .../cloud/netflix/zuul/ZuulConfiguration.java | 7 +- .../zuul/filters/ProxyRequestHelper.java | 45 +++++--- .../filters/pre/Servlet30WrapperFilter.java | 15 ++- .../filters/route/RibbonRoutingFilter.java | 38 +++--- .../route/SimpleHostRoutingFilter.java | 109 ++++++++++-------- .../FormZuulServletProxyApplicationTests.java | 28 ++--- 6 files changed, 146 insertions(+), 96 deletions(-) diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java index d57ec893..ac302097 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java @@ -95,9 +95,14 @@ public class ZuulConfiguration { } @Bean + @ConditionalOnMissingBean(name = "zuulServlet") public ServletRegistrationBean zuulServlet() { - return new ServletRegistrationBean(new ZuulServlet(), + ServletRegistrationBean servlet = new ServletRegistrationBean(new ZuulServlet(), this.zuulProperties.getServletPattern()); + // The whole point of exposing this servlet is to provide a route that doesn't + // buffer requests. + servlet.addInitParameter("buffer-requests", "false"); + return servlet; } // pre filters diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java index e1e9ef8f..b6379cd2 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java @@ -41,11 +41,11 @@ import org.springframework.web.util.WebUtils; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.util.HTTPRequestUtils; -import lombok.extern.apachecommons.CommonsLog; - import static org.springframework.http.HttpHeaders.CONTENT_ENCODING; import static org.springframework.http.HttpHeaders.CONTENT_LENGTH; +import lombok.extern.apachecommons.CommonsLog; + /** * @author Dave Syer */ @@ -123,7 +123,7 @@ public class ProxyRequestHelper { } public void setResponse(int status, InputStream entity, - MultiValueMap headers) throws IOException { + MultiValueMap headers) throws IOException { RequestContext context = RequestContext.getCurrentContext(); context.setResponseStatusCode(status); if (entity != null) { @@ -185,21 +185,21 @@ public class ProxyRequestHelper { } } switch (name) { - case "host": - case "connection": - case "content-length": - case "content-encoding": - case "server": - case "transfer-encoding": - return false; - default: - return true; + case "host": + case "connection": + case "content-length": + case "content-encoding": + case "server": + case "transfer-encoding": + return false; + default: + return true; } } public Map debug(String verb, String uri, - MultiValueMap headers, MultiValueMap params, - InputStream requestEntity) throws IOException { + MultiValueMap headers, MultiValueMap params, + InputStream requestEntity) throws IOException { Map info = new LinkedHashMap(); if (this.traces != null) { RequestContext context = RequestContext.getCurrentContext(); @@ -230,7 +230,8 @@ public class ProxyRequestHelper { input.put(entry.getKey(), value); } RequestContext ctx = RequestContext.getCurrentContext(); - if (!ctx.isChunkedRequestBody()) { + if (shouldDebugBody(ctx)) { + // Prevent input stream from being read if it needs to go downstream if (requestEntity != null) { debugRequestEntity(info, ctx.getRequest().getInputStream()); } @@ -241,8 +242,19 @@ public class ProxyRequestHelper { return info; } + private boolean shouldDebugBody(RequestContext ctx) { + HttpServletRequest request = ctx.getRequest(); + if (ctx.isChunkedRequestBody()) { + return false; + } + if (request == null || request.getContentType() == null) { + return true; + } + return !request.getContentType().toLowerCase().contains("multipart"); + } + public void appendDebug(Map info, int status, - MultiValueMap headers) { + MultiValueMap headers) { if (this.traces != null) { @SuppressWarnings("unchecked") Map trace = (Map) info.get("headers"); @@ -276,4 +288,3 @@ public class ProxyRequestHelper { } } - diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/Servlet30WrapperFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/Servlet30WrapperFilter.java index 8a18bad4..9f667bb3 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/Servlet30WrapperFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/Servlet30WrapperFilter.java @@ -22,6 +22,7 @@ import javax.servlet.http.HttpServletRequest; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; +import org.springframework.web.servlet.DispatcherServlet; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; @@ -37,7 +38,8 @@ public class Servlet30WrapperFilter extends ZuulFilter { public Servlet30WrapperFilter() { this.requestField = ReflectionUtils.findField(HttpServletRequestWrapper.class, "req", HttpServletRequest.class); - Assert.notNull(this.requestField, "HttpServletRequestWrapper.req field not found"); + Assert.notNull(this.requestField, + "HttpServletRequestWrapper.req field not found"); this.requestField.setAccessible(true); } @@ -67,9 +69,18 @@ public class Servlet30WrapperFilter extends ZuulFilter { if (request instanceof HttpServletRequestWrapper) { request = (HttpServletRequest) ReflectionUtils.getField(this.requestField, request); + ctx.setRequest(new Servlet30RequestWrapper(request)); + } + else if (isDispatcherServletRequest(request)) { + // If it's going through the dispatcher we need to buffer the body + ctx.setRequest(new Servlet30RequestWrapper(request)); } - ctx.setRequest(new Servlet30RequestWrapper(request)); return null; } + private boolean isDispatcherServletRequest(HttpServletRequest request) { + return request.getAttribute( + DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null; + } + } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java index c7117691..18c28e89 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java @@ -23,8 +23,6 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import lombok.extern.apachecommons.CommonsLog; - import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; import org.springframework.http.client.ClientHttpResponse; import org.springframework.util.MultiValueMap; @@ -35,6 +33,8 @@ import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; +import lombok.extern.apachecommons.CommonsLog; + @CommonsLog public class RibbonRoutingFilter extends ZuulFilter { @@ -64,8 +64,8 @@ public class RibbonRoutingFilter extends ZuulFilter { @Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); - return (ctx.getRouteHost() == null && ctx.get("serviceId") != null && ctx - .sendZuulResponse()); + return (ctx.getRouteHost() == null && ctx.get("serviceId") != null + && ctx.sendZuulResponse()); } @Override @@ -78,7 +78,8 @@ public class RibbonRoutingFilter extends ZuulFilter { return response; } catch (Exception ex) { - context.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + context.set("error.status_code", + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); context.set("error.exception", ex); } return null; @@ -93,6 +94,9 @@ public class RibbonRoutingFilter extends ZuulFilter { .buildZuulRequestQueryParams(request); String verb = getVerb(request); InputStream requestEntity = getRequestBody(request); + if (request.getContentLength() < 0) { + context.setChunkedRequestBody(); + } String serviceId = (String) context.get("serviceId"); Boolean retryable = (Boolean) context.get("retryable"); @@ -102,15 +106,15 @@ public class RibbonRoutingFilter extends ZuulFilter { // remove double slashes uri = uri.replace("//", "/"); - return new RibbonCommandContext(serviceId, verb, uri, retryable, - headers, params, requestEntity); + return new RibbonCommandContext(serviceId, verb, uri, retryable, headers, params, + requestEntity); } private ClientHttpResponse forward(RibbonCommandContext context) throws Exception { Map info = this.helper.debug(context.getVerb(), context.getUri(), context.getHeaders(), context.getParams(), context.getRequestEntity()); - RibbonCommand command = ribbonCommandFactory.create(context); + RibbonCommand command = this.ribbonCommandFactory.create(context); try { ClientHttpResponse response = command.execute(); this.helper.appendDebug(info, response.getStatusCode().value(), @@ -124,11 +128,11 @@ public class RibbonRoutingFilter extends ZuulFilter { && ex.getFallbackException().getCause() instanceof ClientException) { ClientException cause = (ClientException) ex.getFallbackException() .getCause(); - throw new ZuulException(cause, "Forwarding error", 500, cause - .getErrorType().toString()); + throw new ZuulException(cause, "Forwarding error", 500, + cause.getErrorType().toString()); } - throw new ZuulException(ex, "Forwarding error", 500, ex.getFailureType() - .toString()); + throw new ZuulException(ex, "Forwarding error", 500, + ex.getFailureType().toString()); } } @@ -140,8 +144,8 @@ public class RibbonRoutingFilter extends ZuulFilter { return null; } try { - requestEntity = (InputStream) RequestContext.getCurrentContext().get( - "requestEntity"); + requestEntity = (InputStream) RequestContext.getCurrentContext() + .get("requestEntity"); if (requestEntity == null) { requestEntity = request.getInputStream(); } @@ -154,12 +158,14 @@ public class RibbonRoutingFilter extends ZuulFilter { private String getVerb(HttpServletRequest request) { String method = request.getMethod(); - if (method == null) + if (method == null) { return "GET"; + } return method; } - private void setResponse(ClientHttpResponse resp) throws ClientException, IOException { + private void setResponse(ClientHttpResponse resp) + throws ClientException, IOException { this.helper.setResponse(resp.getStatusCode().value(), resp.getBody() == null ? null : resp.getBody(), resp.getHeaders()); } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java index 2d3c2629..f231d7b9 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; + import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.net.ssl.SSLContext; @@ -55,6 +56,7 @@ 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.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; @@ -80,12 +82,12 @@ import lombok.extern.apachecommons.CommonsLog; public class SimpleHostRoutingFilter extends ZuulFilter { private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory - .getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_SOCKET_TIMEOUT_MILLIS, - 10000); + .getInstance() + .getIntProperty(ZuulConstants.ZUUL_HOST_SOCKET_TIMEOUT_MILLIS, 10000); private static final DynamicIntProperty CONNECTION_TIMEOUT = DynamicPropertyFactory - .getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_CONNECT_TIMEOUT_MILLIS, - 2000); + .getInstance() + .getIntProperty(ZuulConstants.ZUUL_HOST_CONNECT_TIMEOUT_MILLIS, 2000); private final Timer connectionManagerTimer = new Timer( "SimpleHostRoutingFilter.connectionManagerTimer", true); @@ -98,11 +100,12 @@ public class SimpleHostRoutingFilter extends ZuulFilter { @Override public void run() { try { - httpClient.close(); - } catch (IOException ex) { + SimpleHostRoutingFilter.this.httpClient.close(); + } + catch (IOException ex) { log.error("error closing client", ex); } - httpClient = newClient(); + SimpleHostRoutingFilter.this.httpClient = newClient(); } }; @@ -117,22 +120,22 @@ public class SimpleHostRoutingFilter extends ZuulFilter { @PostConstruct private void initialize() { this.httpClient = newClient(); - SOCKET_TIMEOUT.addCallback(clientloader); - CONNECTION_TIMEOUT.addCallback(clientloader); - connectionManagerTimer.schedule(new TimerTask() { + SOCKET_TIMEOUT.addCallback(this.clientloader); + CONNECTION_TIMEOUT.addCallback(this.clientloader); + this.connectionManagerTimer.schedule(new TimerTask() { @Override public void run() { - if (connectionManager == null) { + if (SimpleHostRoutingFilter.this.connectionManager == null) { return; } - connectionManager.closeExpiredConnections(); + SimpleHostRoutingFilter.this.connectionManager.closeExpiredConnections(); } }, 30000, 5000); } @PreDestroy public void stop() { - connectionManagerTimer.cancel(); + this.connectionManagerTimer.cancel(); } @Override @@ -161,16 +164,20 @@ public class SimpleHostRoutingFilter extends ZuulFilter { .buildZuulRequestQueryParams(request); String verb = getVerb(request); InputStream requestEntity = getRequestBody(request); + if (request.getContentLength() < 0) { + context.setChunkedRequestBody(); + } String uri = this.helper.buildZuulRequestURI(request); try { - HttpResponse response = forward(httpClient, verb, uri, request, headers, + HttpResponse response = forward(this.httpClient, verb, uri, request, headers, params, requestEntity); setResponse(response); } catch (Exception ex) { - context.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + context.set("error.status_code", + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); context.set("error.exception", ex); } return null; @@ -179,31 +186,37 @@ public class SimpleHostRoutingFilter extends ZuulFilter { protected PoolingHttpClientConnectionManager newConnectionManager() { try { final SSLContext sslContext = SSLContext.getInstance("SSL"); - sslContext.init(null, new TrustManager[]{new X509TrustManager() { + sslContext.init(null, new TrustManager[] { new X509TrustManager() { @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + public void checkClientTrusted(X509Certificate[] x509Certificates, + String s) throws CertificateException { } @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + public void checkServerTrusted(X509Certificate[] x509Certificates, + String s) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } - }}, new SecureRandom()); + } }, new SecureRandom()); - final Registry registry = RegistryBuilder.create() + final Registry registry = RegistryBuilder + . create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslContext)) .build(); - connectionManager = new PoolingHttpClientConnectionManager(registry); - connectionManager.setMaxTotal(Integer.parseInt(System.getProperty("zuul.max.host.connections", "200"))); - connectionManager.setDefaultMaxPerRoute(Integer.parseInt(System.getProperty("zuul.max.host.connections", "20"))); - return connectionManager; - } catch (Exception ex) { + this.connectionManager = new PoolingHttpClientConnectionManager(registry); + this.connectionManager.setMaxTotal(Integer + .parseInt(System.getProperty("zuul.max.host.connections", "200"))); + this.connectionManager.setDefaultMaxPerRoute(Integer + .parseInt(System.getProperty("zuul.max.host.connections", "20"))); + return this.connectionManager; + } + catch (Exception ex) { throw new RuntimeException(ex); } } @@ -212,55 +225,56 @@ public class SimpleHostRoutingFilter extends ZuulFilter { final RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(SOCKET_TIMEOUT.get()) .setConnectTimeout(CONNECTION_TIMEOUT.get()) - .setCookieSpec(CookieSpecs.IGNORE_COOKIES) - .build(); + .setCookieSpec(CookieSpecs.IGNORE_COOKIES).build(); - return HttpClients.custom() - .setConnectionManager(newConnectionManager()) + return HttpClients.custom().setConnectionManager(newConnectionManager()) .setDefaultRequestConfig(requestConfig) .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)) .setRedirectStrategy(new RedirectStrategy() { @Override - public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { + public boolean isRedirected(HttpRequest request, + HttpResponse response, HttpContext context) + throws ProtocolException { return false; } @Override - public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { + public HttpUriRequest getRedirect(HttpRequest request, + HttpResponse response, HttpContext context) + throws ProtocolException { return null; } - }) - .build(); + }).build(); } private HttpResponse forward(HttpClient httpclient, String verb, String uri, - HttpServletRequest request, MultiValueMap headers, - MultiValueMap params, InputStream requestEntity) - throws Exception { + HttpServletRequest request, MultiValueMap headers, + MultiValueMap params, InputStream requestEntity) + throws Exception { Map info = this.helper.debug(verb, uri, headers, params, requestEntity); URL host = RequestContext.getCurrentContext().getRouteHost(); HttpHost httpHost = getHttpHost(host); uri = StringUtils.cleanPath((host.getPath() + uri).replaceAll("/{2,}", "/")); HttpRequest httpRequest; + int contentLength = request.getContentLength(); + InputStreamEntity entity = new InputStreamEntity(requestEntity, contentLength, + ContentType.create(request.getContentType())); switch (verb.toUpperCase()) { case "POST": HttpPost httpPost = new HttpPost(uri + getQueryString()); httpRequest = httpPost; - httpPost.setEntity(new InputStreamEntity(requestEntity, request - .getContentLength())); + httpPost.setEntity(entity); break; case "PUT": HttpPut httpPut = new HttpPut(uri + getQueryString()); httpRequest = httpPut; - httpPut.setEntity(new InputStreamEntity(requestEntity, request - .getContentLength())); + httpPut.setEntity(entity); break; case "PATCH": HttpPatch httpPatch = new HttpPatch(uri + getQueryString()); httpRequest = httpPatch; - httpPatch.setEntity(new InputStreamEntity(requestEntity, request - .getContentLength())); + httpPatch.setEntity(entity); break; default: httpRequest = new BasicHttpRequest(verb, uri + getQueryString()); @@ -312,10 +326,11 @@ public class SimpleHostRoutingFilter extends ZuulFilter { private String getQueryString() throws UnsupportedEncodingException { HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); - MultiValueMap params=helper.buildZuulRequestQueryParams(request); - StringBuilder query=new StringBuilder(); + MultiValueMap params = this.helper + .buildZuulRequestQueryParams(request); + StringBuilder query = new StringBuilder(); for (Map.Entry> entry : params.entrySet()) { - String key=URLEncoder.encode(entry.getKey(), "UTF-8"); + String key = URLEncoder.encode(entry.getKey(), "UTF-8"); for (String value : entry.getValue()) { query.append("&"); query.append(key); @@ -323,7 +338,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter { query.append(URLEncoder.encode(value, "UTF-8")); } } - return (query.length()>0) ? "?" + query.substring(1) : ""; + return (query.length() > 0) ? "?" + query.substring(1) : ""; } private HttpHost getHttpHost(URL host) { @@ -359,7 +374,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter { * @param names */ protected void addIgnoredHeaders(String... names) { - helper.addIgnoredHeaders(names); + this.helper.addIgnoredHeaders(names); } } diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/FormZuulServletProxyApplicationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/FormZuulServletProxyApplicationTests.java index 6b0b74cf..6666ac23 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/FormZuulServletProxyApplicationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/FormZuulServletProxyApplicationTests.java @@ -16,14 +16,10 @@ package org.springframework.cloud.netflix.zuul; -import static org.junit.Assert.assertEquals; - import java.io.IOException; import java.io.InputStream; import java.util.Map; -import lombok.extern.slf4j.Slf4j; - import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Value; @@ -60,6 +56,10 @@ import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; import com.netflix.zuul.ZuulFilter; +import static org.junit.Assert.assertEquals; + +import lombok.extern.slf4j.Slf4j; + @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = FormZuulServletProxyApplication.class) @WebAppConfiguration @@ -107,6 +107,8 @@ public class FormZuulServletProxyApplicationTests { form.set("foo", new HttpEntity("bar".getBytes(), part)); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); + headers.set("Transfer-Encoding", "chunked"); + headers.setContentLength(-1); ResponseEntity result = new TestRestTemplate().exchange( "http://localhost:" + this.port + "/zuul/simple/file", HttpMethod.POST, new HttpEntity>(form, headers), @@ -120,8 +122,8 @@ public class FormZuulServletProxyApplicationTests { MultiValueMap form = new LinkedMultiValueMap(); form.set("foo", "bar"); HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType - .valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + "; charset=UTF-8")); + headers.setContentType(MediaType.valueOf( + MediaType.APPLICATION_FORM_URLENCODED_VALUE + "; charset=UTF-8")); ResponseEntity result = new TestRestTemplate().exchange( "http://localhost:" + this.port + "/zuul/simple/form", HttpMethod.POST, new HttpEntity>(form, headers), @@ -209,12 +211,12 @@ class FormZuulServletProxyApplication { } public static void main(String[] args) { - new SpringApplicationBuilder(FormZuulProxyApplication.class).properties( - "zuul.routes.simple:/zuul/simple/**", - "zuul.routes.direct.url:http://localhost:9999", - "zuul.routes.direct.path:/zuul/direct/**", - "multipart.maxFileSize:4096MB", "multipart.maxRequestSize:4096MB").run( - args); + new SpringApplicationBuilder(FormZuulProxyApplication.class) + .properties("zuul.routes.simple:/zuul/simple/**", + "zuul.routes.direct.url:http://localhost:9999", + "zuul.routes.direct.path:/zuul/direct/**", + "multipart.maxFileSize:4096MB", "multipart.maxRequestSize:4096MB") + .run(args); } } @@ -228,7 +230,7 @@ class ServletFormRibbonClientConfiguration { @Bean public ServerList ribbonServerList() { - return new StaticServerList<>(new Server("localhost", port)); + return new StaticServerList<>(new Server("localhost", this.port)); } }