479026 - Wrong CONNECT request idle timeout.

Explicitly set the CONNECT request idle timeout instead of inheriting
HttpClient's.
This commit is contained in:
Simone Bordet 2015-10-05 11:52:58 +02:00
parent 6aae1265bd
commit 399755b352
3 changed files with 76 additions and 25 deletions

View File

@ -26,7 +26,6 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
@ -119,7 +118,7 @@ public class HttpProxy extends ProxyConfiguration.Proxy
{
String message = String.format("Cannot perform requests over SSL, no %s in %s",
SslContextFactory.class.getSimpleName(), HttpClient.class.getSimpleName());
promise.failed(new IllegalStateException(message));
tunnelFailed(new IllegalStateException(message));
}
}
else
@ -131,7 +130,7 @@ public class HttpProxy extends ProxyConfiguration.Proxy
@Override
public void failed(Throwable x)
{
promise.failed(x);
tunnelFailed(x);
}
private void tunnel(HttpDestination destination, final Connection connection)
@ -139,17 +138,16 @@ public class HttpProxy extends ProxyConfiguration.Proxy
String target = destination.getOrigin().getAddress().asString();
Origin.Address proxyAddress = destination.getConnectAddress();
HttpClient httpClient = destination.getHttpClient();
long connectTimeout = httpClient.getConnectTimeout();
Request connect = httpClient.newRequest(proxyAddress.getHost(), proxyAddress.getPort())
.scheme(HttpScheme.HTTP.asString())
.method(HttpMethod.CONNECT)
.path(target)
.header(HttpHeader.HOST, target)
.timeout(httpClient.getConnectTimeout(), TimeUnit.MILLISECONDS);
.idleTimeout(2 * connectTimeout, TimeUnit.MILLISECONDS)
.timeout(connectTimeout, TimeUnit.MILLISECONDS);
connection.send(connect, new Response.CompleteListener()
{
@Override
public void onComplete(Result result)
connection.send(connect, result ->
{
if (result.isFailed())
{
@ -167,7 +165,6 @@ public class HttpProxy extends ProxyConfiguration.Proxy
tunnelFailed(new HttpResponseException("Received " + response + " for " + result.getRequest(), response));
}
}
}
});
}
@ -198,7 +195,7 @@ public class HttpProxy extends ProxyConfiguration.Proxy
private void tunnelFailed(Throwable failure)
{
endPoint.close();
failed(failure);
promise.failed(failure);
}
}
}

View File

@ -168,11 +168,11 @@ public abstract class PoolingHttpDestination<C extends Connection> extends HttpD
}
@Override
public void close(Connection oldConnection)
public void close(Connection connection)
{
super.close(oldConnection);
super.close(connection);
connectionPool.remove(oldConnection);
boolean removed = connectionPool.remove(connection);
if (getHttpExchanges().isEmpty())
{
@ -192,6 +192,7 @@ public abstract class PoolingHttpDestination<C extends Connection> extends HttpD
// We need to execute queued requests even if this connection failed.
// We may create a connection that is not needed, but it will eventually
// idle timeout, so no worries.
if (removed)
process();
}
}

View File

@ -18,8 +18,6 @@
package org.eclipse.jetty.proxy;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;
@ -64,6 +62,8 @@ import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ProxyTunnellingTest
{
@Rule
@ -278,6 +278,59 @@ public class ProxyTunnellingTest
}
}
@Test
public void testShortIdleTimeoutOverriddenByRequest() throws Exception
{
// Short idle timeout for HttpClient.
long idleTimeout = 500;
startSSLServer(new ServerHandler());
startProxy(new ConnectHandler()
{
@Override
protected void handleConnect(Request baseRequest, HttpServletRequest request, HttpServletResponse response, String serverAddress)
{
try
{
// Make sure the proxy remains idle enough.
Thread.sleep(2 * idleTimeout);
super.handleConnect(baseRequest, request, response, serverAddress);
}
catch (InterruptedException x)
{
onConnectFailure(request, response, null, x);
}
}
});
HttpClient httpClient = new HttpClient(sslContextFactory);
httpClient.getProxyConfiguration().getProxies().add(new HttpProxy("localhost", proxyPort()));
// Short idle timeout for HttpClient.
httpClient.setIdleTimeout(idleTimeout);
httpClient.start();
try
{
String host = "localhost";
String body = "BODY";
ContentResponse response = httpClient.newRequest(host, serverConnector.getLocalPort())
.scheme(HttpScheme.HTTPS.asString())
.method(HttpMethod.GET)
.path("/echo?body=" + URLEncoder.encode(body, "UTF-8"))
// Long idle timeout for the request.
.idleTimeout(10 * idleTimeout, TimeUnit.MILLISECONDS)
.send();
assertEquals(HttpStatus.OK_200, response.getStatus());
String content = response.getContentAsString();
assertEquals(body, content);
}
finally
{
httpClient.stop();
}
}
@Test
public void testProxyDown() throws Exception
{