diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java index 9d7723b2b1b..c5dcbbe22f3 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java @@ -65,7 +65,7 @@ public class HttpDestination implements Dumpable private List _cookies; - + HttpDestination(HttpClient client, Address address, boolean ssl) { _client = client; @@ -524,7 +524,7 @@ public class HttpDestination implements Dumpable // Add any known authorizations if (_authorizations != null) { - Authentication auth = (Authentication)_authorizations.match(ex.getURI()); + Authentication auth = (Authentication)_authorizations.match(ex.getRequestURI()); if (auth != null) (auth).setCredentials(ex); } @@ -665,7 +665,7 @@ public class HttpDestination implements Dumpable AggregateLifeCycle.dump(out,indent,_connections); } } - + private class ConnectExchange extends ContentExchange { private final SelectConnector.ProxySelectChannelEndPoint proxyEndPoint; @@ -687,13 +687,17 @@ public class HttpDestination implements Dumpable @Override protected void onResponseComplete() throws IOException { - if (getResponseStatus() == HttpStatus.OK_200) + int responseStatus = getResponseStatus(); + if (responseStatus == HttpStatus.OK_200) { proxyEndPoint.upgrade(); } + else if(responseStatus == HttpStatus.GATEWAY_TIMEOUT_504){ + onExpire(); + } else { - onConnectionFailed(new ConnectException(exchange.getAddress().toString())); + onException(new ConnectException("Proxy: " + proxyEndPoint.getRemoteAddr() +":" + proxyEndPoint.getRemotePort() + " didn't return http return code 200, but " + responseStatus + " while trying to request: " + exchange.getAddress().toString())); } } @@ -702,5 +706,22 @@ public class HttpDestination implements Dumpable { HttpDestination.this.onConnectionFailed(x); } + + @Override + protected void onException(Throwable x) + { + _queue.remove(exchange); + exchange.setStatus(STATUS_EXCEPTED); + exchange.getEventListener().onException(x); + } + + @Override + protected void onExpire() + { + _queue.remove(exchange); + exchange.setStatus(STATUS_EXPIRED); + exchange.getEventListener().onExpire(); + } + } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpsViaBrokenHttpProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpsViaBrokenHttpProxyTest.java new file mode 100644 index 00000000000..a073237fcaa --- /dev/null +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpsViaBrokenHttpProxyTest.java @@ -0,0 +1,131 @@ +// ======================================================================== +// Copyright (c) 2009-2009 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.client; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.HttpConnection; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ConnectHandler; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/* ------------------------------------------------------------ */ +/** + * This UnitTest class executes two tests. Both will send a http request to https://google.com through a misbehaving proxy server. + * + * The first test runs against a proxy which simply closes the connection (as nginx does) for a connect request. The second proxy server always responds with a + * 500 error. + * + * The expected result for both tests is an exception and the HttpExchange should have status HttpExchange.STATUS_EXCEPTED. + */ +public class HttpsViaBrokenHttpProxyTest +{ + + private Server _proxy = new Server(); + private HttpClient _client = new HttpClient(); + + /* ------------------------------------------------------------ */ + /** + * @throws java.lang.Exception + */ + @Before + public void setUpBeforeClass() throws Exception + { + // setup proxies with different behaviour + _proxy.addConnector(new SelectChannelConnector()); + _proxy.setHandler(new BadBehavingConnectHandler()); + _proxy.start(); + int proxyClosingConnectionPort = _proxy.getConnectors()[0].getLocalPort(); + + _client.setProxy(new Address("localhost",proxyClosingConnectionPort)); + _client.start(); + } + + /* ------------------------------------------------------------ */ + /** + * @throws java.lang.Exception + */ + @After + public void tearDownAfterClass() throws Exception + { + _client.stop(); + _proxy.stop(); + } + + private class BadBehavingConnectHandler extends ConnectHandler + { + @Override + protected void handleConnect(Request baseRequest, HttpServletRequest request, HttpServletResponse response, String serverAddress) + throws ServletException, IOException + { + if (serverAddress.contains("close")) + HttpConnection.getCurrentConnection().getEndPoint().close(); + else if (serverAddress.contains("error500")) + { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500); + } + else if (serverAddress.contains("error504")) + { + response.setStatus(HttpStatus.GATEWAY_TIMEOUT_504); + } + baseRequest.setHandled(true); + } + } + + @Test + public void httpsViaProxyThatClosesConnectionOnConnectRequestTest() + { + sendRequestThroughProxy("close",9); + } + + @Test + public void httpsViaProxyThatReturns500ErrorTest() throws Exception + { + sendRequestThroughProxy("error500",9); + } + + @Test + public void httpsViaProxyThatReturns504ErrorTest() throws Exception + { + sendRequestThroughProxy("error504",8); + } + + private void sendRequestThroughProxy(String desiredBehaviour, int exptectedStatus) + { + String url = "https://" + desiredBehaviour + ".com/"; + try + { + ContentExchange exchange = new ContentExchange(); + exchange.setURL(url); + exchange.addRequestHeader("behaviour",desiredBehaviour); + _client.send(exchange); + assertEquals(HttpExchange.toState(exptectedStatus) + " status awaited",exptectedStatus,exchange.waitForDone()); + } + catch (Exception e) + { + System.out.println(e.getMessage()); + } + } +} diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java index 441f9dfac7d..a9a03879454 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java @@ -1,9 +1,13 @@ package org.eclipse.jetty.client; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.net.URLEncoder; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; @@ -26,9 +30,6 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.junit.After; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - public class ProxyTunnellingTest { private Server server; @@ -41,7 +42,7 @@ public class ProxyTunnellingTest { return proxyConnector.getLocalPort(); } - + protected void startSSLServer(Handler handler) throws Exception { SslSelectChannelConnector connector = new SslSelectChannelConnector(); @@ -217,11 +218,11 @@ public class ProxyTunnellingTest ContentExchange exchange = new ContentExchange(true) { @Override - protected void onConnectionFailed(Throwable x) + protected void onException(Throwable x) { latch.countDown(); } - + }; exchange.setMethod(HttpMethods.GET); String body = "BODY";