From 4462e6a01e62de7eeaff52995b3a81aca9a52a8a Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Feb 2015 15:29:44 +0100 Subject: [PATCH] 459352 - AsyncMiddleManServlet should set "Host:" header correctly in proxy to remote request headers. Fixed by removing the host header during the copy, so that HttpClient correctly sets it by looking at the request target. --- .../jetty/proxy/AbstractProxyServlet.java | 2 +- .../eclipse/jetty/proxy/ProxyServletTest.java | 45 ++++--- .../eclipse/jetty/proxy/ReverseProxyTest.java | 127 ++++++++++++++++++ 3 files changed, 152 insertions(+), 22 deletions(-) create mode 100644 jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ReverseProxyTest.java diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java index 5c1e40d5da8..1411b0a8abf 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java @@ -402,7 +402,7 @@ public abstract class AbstractProxyServlet extends HttpServlet String headerName = headerNames.nextElement(); String lowerHeaderName = headerName.toLowerCase(Locale.ENGLISH); - if (_hostHeader != null && HttpHeader.HOST.is(headerName)) + if (HttpHeader.HOST.is(headerName)) continue; // Remove hop-by-hop headers. diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java index e1cd32178ea..ee343c12fb6 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java @@ -907,24 +907,31 @@ public class ProxyServletTest Assert.assertEquals(value1, cookies.get(0).getValue()); HttpClient client2 = prepareClient(); - String value2 = "2"; - ContentResponse response2 = client2.newRequest("localhost", serverConnector.getLocalPort()) - .header(name, value2) - .timeout(5, TimeUnit.SECONDS) - .send(); - Assert.assertEquals(200, response2.getStatus()); - Assert.assertTrue(response2.getHeaders().containsKey(PROXIED_HEADER)); - cookies = client2.getCookieStore().getCookies(); - Assert.assertEquals(1, cookies.size()); - Assert.assertEquals(name, cookies.get(0).getName()); - Assert.assertEquals(value2, cookies.get(0).getValue()); + try + { + String value2 = "2"; + ContentResponse response2 = client2.newRequest("localhost", serverConnector.getLocalPort()) + .header(name, value2) + .timeout(5, TimeUnit.SECONDS) + .send(); + Assert.assertEquals(200, response2.getStatus()); + Assert.assertTrue(response2.getHeaders().containsKey(PROXIED_HEADER)); + cookies = client2.getCookieStore().getCookies(); + Assert.assertEquals(1, cookies.size()); + Assert.assertEquals(name, cookies.get(0).getName()); + Assert.assertEquals(value2, cookies.get(0).getValue()); - // Make a third request to be sure the proxy does not mix cookies - ContentResponse response3 = client.newRequest("localhost", serverConnector.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .send(); - Assert.assertEquals(200, response3.getStatus()); - Assert.assertTrue(response3.getHeaders().containsKey(PROXIED_HEADER)); + // Make a third request to be sure the proxy does not mix cookies + ContentResponse response3 = client.newRequest("localhost", serverConnector.getLocalPort()) + .timeout(5, TimeUnit.SECONDS) + .send(); + Assert.assertEquals(200, response3.getStatus()); + Assert.assertTrue(response3.getHeaders().containsKey(PROXIED_HEADER)); + } + finally + { + client2.stop(); + } } @Test @@ -967,7 +974,6 @@ public class ProxyServletTest } }); - HttpClient client = prepareClient(); InputStreamResponseListener listener = new InputStreamResponseListener(); int port = serverConnector.getLocalPort(); client.newRequest("localhost", port).send(listener); @@ -1039,7 +1045,6 @@ public class ProxyServletTest } }); - HttpClient client = prepareClient(); InputStreamResponseListener listener = new InputStreamResponseListener(); int port = serverConnector.getLocalPort(); client.newRequest("localhost", port).send(listener); @@ -1099,7 +1104,6 @@ public class ProxyServletTest proxyContext.start(); prepareServer(new EmptyHttpServlet()); - HttpClient client = prepareClient(); ContentResponse response = client.newRequest("localhost", serverConnector.getLocalPort()).send(); Assert.assertEquals(200, response.getStatus()); @@ -1132,7 +1136,6 @@ public class ProxyServletTest } }); - HttpClient client = prepareClient(); Request request = client.newRequest("localhost", serverConnector.getLocalPort()); for (Map.Entry entry : hopHeaders.entrySet()) request.header(entry.getKey(), entry.getValue()); diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ReverseProxyTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ReverseProxyTest.java new file mode 100644 index 00000000000..57d85307e91 --- /dev/null +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ReverseProxyTest.java @@ -0,0 +1,127 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.proxy; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.toolchain.test.TestTracker; +import org.junit.After; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ReverseProxyTest +{ + @Rule + public final TestTracker tracker = new TestTracker(); + private HttpClient client; + private Server proxy; + private ServerConnector proxyConnector; + private Server server; + private ServerConnector serverConnector; + + private void startProxy() throws Exception + { + proxy = new Server(); + + HttpConfiguration configuration = new HttpConfiguration(); + configuration.setSendDateHeader(false); + configuration.setSendServerVersion(false); + proxyConnector = new ServerConnector(proxy, new HttpConnectionFactory(configuration)); + proxy.addConnector(proxyConnector); + + ServletContextHandler proxyContext = new ServletContextHandler(proxy, "/", true, false); + ServletHolder proxyServletHolder = new ServletHolder(new AsyncMiddleManServlet() + { + @Override + protected String rewriteTarget(HttpServletRequest clientRequest) + { + StringBuilder builder = new StringBuilder(); + builder.append(clientRequest.getScheme()).append("://localhost:"); + builder.append(serverConnector.getLocalPort()); + builder.append(clientRequest.getRequestURI()); + String query = clientRequest.getQueryString(); + if (query != null) + builder.append("?").append(query); + return builder.toString(); + } + }); + proxyContext.addServlet(proxyServletHolder, "/*"); + + proxy.start(); + } + + private void startServer(HttpServlet servlet) throws Exception + { + server = new Server(); + + serverConnector = new ServerConnector(server); + server.addConnector(serverConnector); + + ServletContextHandler appCtx = new ServletContextHandler(server, "/", true, false); + ServletHolder appServletHolder = new ServletHolder(servlet); + appCtx.addServlet(appServletHolder, "/*"); + + server.start(); + } + + private void startClient() throws Exception + { + client = new HttpClient(); + client.start(); + } + + @After + public void dispose() throws Exception + { + client.stop(); + proxy.stop(); + server.stop(); + } + + @Test + public void testClientHostHeaderUpdatedWhenSentToServer() throws Exception + { + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + Assert.assertEquals(request.getServerPort(), serverConnector.getLocalPort()); + } + }); + startProxy(); + startClient(); + + ContentResponse response = client.newRequest("localhost", proxyConnector.getLocalPort()).send(); + Assert.assertEquals(200, response.getStatus()); + } +}