Cleaned up HttpRoute
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1511446 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e40168d06c
commit
4db8167981
|
@ -29,6 +29,10 @@ package org.apache.http.conn.routing;
|
|||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.annotation.Immutable;
|
||||
|
@ -45,8 +49,6 @@ import org.apache.http.util.LangUtils;
|
|||
@Immutable
|
||||
public final class HttpRoute implements RouteInfo, Cloneable {
|
||||
|
||||
private static final HttpHost[] EMPTY_HTTP_HOST_ARRAY = new HttpHost[]{};
|
||||
|
||||
/** The target host to connect to. */
|
||||
private final HttpHost targetHost;
|
||||
|
||||
|
@ -57,7 +59,7 @@ public final class HttpRoute implements RouteInfo, Cloneable {
|
|||
private final InetAddress localAddress;
|
||||
|
||||
/** The proxy servers, if any. Never null. */
|
||||
private final HttpHost[] proxyChain;
|
||||
private final List<HttpHost> proxyChain;
|
||||
|
||||
/** Whether the the route is tunnelled through the proxy. */
|
||||
private final TunnelType tunnelled;
|
||||
|
@ -68,42 +70,19 @@ public final class HttpRoute implements RouteInfo, Cloneable {
|
|||
/** Whether the route is (supposed to be) secure. */
|
||||
private final boolean secure;
|
||||
|
||||
|
||||
/**
|
||||
* Internal, fully-specified constructor.
|
||||
* This constructor does <i>not</i> clone the proxy chain array,
|
||||
* nor test it for <code>null</code> elements. This conversion and
|
||||
* check is the responsibility of the public constructors.
|
||||
* The order of arguments here is different from the similar public
|
||||
* constructor, as required by Java.
|
||||
*
|
||||
* @param local the local address to route from, or
|
||||
* <code>null</code> for the default
|
||||
* @param target the host to which to route
|
||||
* @param proxies the proxy chain to use, or
|
||||
* <code>null</code> for a direct route
|
||||
* @param secure <code>true</code> if the route is (to be) secure,
|
||||
* <code>false</code> otherwise
|
||||
* @param tunnelled the tunnel type of this route, or
|
||||
* <code>null</code> for PLAIN
|
||||
* @param layered the layering type of this route, or
|
||||
* <code>null</code> for PLAIN
|
||||
*/
|
||||
private HttpRoute(final InetAddress local,
|
||||
final HttpHost target, final HttpHost[] proxies,
|
||||
final boolean secure,
|
||||
final TunnelType tunnelled, final LayerType layered) {
|
||||
private HttpRoute(final HttpHost target, final InetAddress local, final List<HttpHost> proxies,
|
||||
final boolean secure, final TunnelType tunnelled, final LayerType layered) {
|
||||
Args.notNull(target, "Target host");
|
||||
Args.notNull(proxies, "Array of proxy hosts");
|
||||
for (final HttpHost proxy: proxies) {
|
||||
Args.notNull(proxy, "Proxy host");
|
||||
}
|
||||
if (tunnelled == TunnelType.TUNNELLED) {
|
||||
Args.check(proxies.length > 0, "Proxy required if tunnelled");
|
||||
}
|
||||
this.targetHost = target;
|
||||
this.localAddress = local;
|
||||
this.proxyChain = proxies;
|
||||
if (proxies != null && !proxies.isEmpty()) {
|
||||
this.proxyChain = new ArrayList<HttpHost>(proxies);
|
||||
} else {
|
||||
this.proxyChain = null;
|
||||
}
|
||||
if (tunnelled == TunnelType.TUNNELLED) {
|
||||
Args.check(this.proxyChain != null, "Proxy required if tunnelled");
|
||||
}
|
||||
this.secure = secure;
|
||||
this.tunnelled = tunnelled != null ? tunnelled : TunnelType.PLAIN;
|
||||
this.layered = layered != null ? layered : LayerType.PLAIN;
|
||||
|
@ -124,10 +103,10 @@ public final class HttpRoute implements RouteInfo, Cloneable {
|
|||
*/
|
||||
public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost[] proxies,
|
||||
final boolean secure, final TunnelType tunnelled, final LayerType layered) {
|
||||
this(local, target, toChain(proxies), secure, tunnelled, layered);
|
||||
this(target, local, proxies != null ? Arrays.asList(proxies) : null,
|
||||
secure, tunnelled, layered);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new route with at most one proxy.
|
||||
*
|
||||
|
@ -147,10 +126,10 @@ public final class HttpRoute implements RouteInfo, Cloneable {
|
|||
*/
|
||||
public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
|
||||
final boolean secure, final TunnelType tunnelled, final LayerType layered) {
|
||||
this(local, target, toChain(proxy), secure, tunnelled, layered);
|
||||
this(target, local, proxy != null ? Collections.singletonList(proxy) : null,
|
||||
secure, tunnelled, layered);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new direct route.
|
||||
* That is a route without a proxy.
|
||||
|
@ -162,20 +141,20 @@ public final class HttpRoute implements RouteInfo, Cloneable {
|
|||
* <code>false</code> otherwise
|
||||
*/
|
||||
public HttpRoute(final HttpHost target, final InetAddress local, final boolean secure) {
|
||||
this(local, target, EMPTY_HTTP_HOST_ARRAY, secure, TunnelType.PLAIN, LayerType.PLAIN);
|
||||
this(target, local, Collections.<HttpHost>emptyList(), secure,
|
||||
TunnelType.PLAIN, LayerType.PLAIN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new direct insecure route.
|
||||
*
|
||||
* @param target the host to which to route
|
||||
*/
|
||||
public HttpRoute(final HttpHost target) {
|
||||
this(null, target, EMPTY_HTTP_HOST_ARRAY, false, TunnelType.PLAIN, LayerType.PLAIN);
|
||||
this(target, null, Collections.<HttpHost>emptyList(), false,
|
||||
TunnelType.PLAIN, LayerType.PLAIN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new route through a proxy.
|
||||
* When using this constructor, the <code>proxy</code> MUST be given.
|
||||
|
@ -191,117 +170,62 @@ public final class HttpRoute implements RouteInfo, Cloneable {
|
|||
*/
|
||||
public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
|
||||
final boolean secure) {
|
||||
this(local, target, toChain(proxy), secure,
|
||||
this(target, local, Collections.singletonList(Args.notNull(proxy, "Proxy host")), secure,
|
||||
secure ? TunnelType.TUNNELLED : TunnelType.PLAIN,
|
||||
secure ? LayerType.LAYERED : LayerType.PLAIN);
|
||||
Args.notNull(proxy, "Proxy host");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to convert a proxy to a proxy chain.
|
||||
*
|
||||
* @param proxy the only proxy in the chain, or <code>null</code>
|
||||
*
|
||||
* @return a proxy chain array, may be empty (never null)
|
||||
*/
|
||||
private static HttpHost[] toChain(final HttpHost proxy) {
|
||||
if (proxy == null) {
|
||||
return EMPTY_HTTP_HOST_ARRAY;
|
||||
}
|
||||
|
||||
return new HttpHost[]{ proxy };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to duplicate and check a proxy chain.
|
||||
* <code>null</code> is converted to an empty proxy chain.
|
||||
*
|
||||
* @param proxies the proxy chain to duplicate, or <code>null</code>
|
||||
*
|
||||
* @return a new proxy chain array, may be empty (never null)
|
||||
*/
|
||||
private static HttpHost[] toChain(final HttpHost[] proxies) {
|
||||
if ((proxies == null) || (proxies.length < 1)) {
|
||||
return EMPTY_HTTP_HOST_ARRAY;
|
||||
}
|
||||
// copy the proxy chain, the traditional way
|
||||
final HttpHost[] result = new HttpHost[proxies.length];
|
||||
System.arraycopy(proxies, 0, result, 0, proxies.length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// non-JavaDoc, see interface RouteInfo
|
||||
public final HttpHost getTargetHost() {
|
||||
return this.targetHost;
|
||||
}
|
||||
|
||||
|
||||
// non-JavaDoc, see interface RouteInfo
|
||||
public final InetAddress getLocalAddress() {
|
||||
return this.localAddress;
|
||||
}
|
||||
|
||||
|
||||
public final InetSocketAddress getLocalSocketAddress() {
|
||||
return this.localAddress != null ? new InetSocketAddress(this.localAddress, 0) : null;
|
||||
}
|
||||
|
||||
public final int getHopCount() {
|
||||
return proxyChain.length+1;
|
||||
return proxyChain != null ? proxyChain.size() + 1 : 1;
|
||||
}
|
||||
|
||||
|
||||
public final HttpHost getHopTarget(final int hop) {
|
||||
Args.notNegative(hop, "Hop index");
|
||||
final int hopcount = getHopCount();
|
||||
Args.check(hop < hopcount, "Hop index exceeds tracked route length");
|
||||
|
||||
HttpHost result = null;
|
||||
if (hop < hopcount-1) {
|
||||
result = this.proxyChain[hop];
|
||||
if (hop < hopcount - 1) {
|
||||
return this.proxyChain.get(hop);
|
||||
} else {
|
||||
result = this.targetHost;
|
||||
return this.targetHost;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public final HttpHost getProxyHost() {
|
||||
return (this.proxyChain.length == 0) ? null : this.proxyChain[0];
|
||||
return proxyChain != null && !this.proxyChain.isEmpty() ? this.proxyChain.get(0) : null;
|
||||
}
|
||||
|
||||
|
||||
public final TunnelType getTunnelType() {
|
||||
return this.tunnelled;
|
||||
}
|
||||
|
||||
|
||||
public final boolean isTunnelled() {
|
||||
return (this.tunnelled == TunnelType.TUNNELLED);
|
||||
}
|
||||
|
||||
|
||||
public final LayerType getLayerType() {
|
||||
return this.layered;
|
||||
}
|
||||
|
||||
|
||||
public final boolean isLayered() {
|
||||
return (this.layered == LayerType.LAYERED);
|
||||
}
|
||||
|
||||
|
||||
public final boolean isSecure() {
|
||||
return this.secure;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compares this route to another.
|
||||
*
|
||||
|
@ -341,8 +265,10 @@ public final class HttpRoute implements RouteInfo, Cloneable {
|
|||
int hash = LangUtils.HASH_SEED;
|
||||
hash = LangUtils.hashCode(hash, this.targetHost);
|
||||
hash = LangUtils.hashCode(hash, this.localAddress);
|
||||
for (final HttpHost element : this.proxyChain) {
|
||||
hash = LangUtils.hashCode(hash, element);
|
||||
if (this.proxyChain != null) {
|
||||
for (final HttpHost element : this.proxyChain) {
|
||||
hash = LangUtils.hashCode(hash, element);
|
||||
}
|
||||
}
|
||||
hash = LangUtils.hashCode(hash, this.secure);
|
||||
hash = LangUtils.hashCode(hash, this.tunnelled);
|
||||
|
@ -350,7 +276,6 @@ public final class HttpRoute implements RouteInfo, Cloneable {
|
|||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains a description of this route.
|
||||
*
|
||||
|
@ -374,15 +299,16 @@ public final class HttpRoute implements RouteInfo, Cloneable {
|
|||
cab.append('s');
|
||||
}
|
||||
cab.append("}->");
|
||||
for (final HttpHost aProxyChain : this.proxyChain) {
|
||||
cab.append(aProxyChain);
|
||||
cab.append("->");
|
||||
if (this.proxyChain != null) {
|
||||
for (final HttpHost aProxyChain : this.proxyChain) {
|
||||
cab.append(aProxyChain);
|
||||
cab.append("->");
|
||||
}
|
||||
}
|
||||
cab.append(this.targetHost);
|
||||
return cab.toString();
|
||||
}
|
||||
|
||||
|
||||
// default implementation of clone() is sufficient
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
|
|
|
@ -226,17 +226,15 @@ public class TestHttpRoute {
|
|||
|
||||
@Test
|
||||
public void testInvalidArguments() {
|
||||
final HttpHost[] chain0 = { null };
|
||||
final HttpHost[] chain1 = { PROXY1 };
|
||||
final HttpHost[] chain4 = { PROXY1, PROXY2, null, PROXY3 };
|
||||
|
||||
// for reference: this one should succeed
|
||||
HttpRoute route = new HttpRoute(TARGET1, null, chain1, false,
|
||||
final HttpRoute route = new HttpRoute(TARGET1, null, chain1, false,
|
||||
TunnelType.TUNNELLED, LayerType.PLAIN);
|
||||
Assert.assertNotNull(route);
|
||||
|
||||
try {
|
||||
route = new HttpRoute(null, null, chain1, false,
|
||||
new HttpRoute(null, null, chain1, false,
|
||||
TunnelType.TUNNELLED, LayerType.PLAIN);
|
||||
Assert.fail("missing target not detected");
|
||||
} catch (final IllegalArgumentException iax) {
|
||||
|
@ -244,29 +242,12 @@ public class TestHttpRoute {
|
|||
}
|
||||
|
||||
try {
|
||||
route = new HttpRoute(TARGET1, null, (HttpHost[]) null, false,
|
||||
new HttpRoute(TARGET1, null, (HttpHost[]) null, false,
|
||||
TunnelType.TUNNELLED, LayerType.PLAIN);
|
||||
Assert.fail("missing proxy for tunnel not detected");
|
||||
} catch (final IllegalArgumentException iax) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// for the next two, we don't indicate a tunnel anymore
|
||||
try {
|
||||
new HttpRoute(TARGET1, null, chain0, false,
|
||||
TunnelType.PLAIN, LayerType.PLAIN);
|
||||
Assert.fail("invalid proxy chain (0) not detected");
|
||||
} catch (final IllegalArgumentException iax) {
|
||||
// expected
|
||||
}
|
||||
|
||||
try {
|
||||
new HttpRoute(TARGET1, null, chain4, false,
|
||||
TunnelType.PLAIN, LayerType.PLAIN);
|
||||
Assert.fail("invalid proxy chain (4) not detected");
|
||||
} catch (final IllegalArgumentException iax) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue