HTTPCLIENT-649: ManagedClientConnection now supports proxy chains
git-svn-id: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpclient/trunk@573844 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7738386c10
commit
efe4b9c9c0
|
@ -1,5 +1,8 @@
|
|||
Changes since release 4.0 Alpha 1
|
||||
|
||||
* [HTTPCLIENT-649] support for proxy chains in HttpConn
|
||||
Contributed by Roland Weber <rolandw at apache.org>
|
||||
|
||||
* [HTTPCLIENT-636] refactor ThreadSafeClientConnManager in separate package
|
||||
Contributed by Roland Weber <rolandw at apache.org>
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.io.IOException;
|
|||
|
||||
import org.apache.http.HttpClientConnection;
|
||||
import org.apache.http.HttpInetConnection;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
|
@ -80,8 +81,8 @@ public interface ManagedClientConnection extends
|
|||
/**
|
||||
* Opens this connection according to the given route.
|
||||
*
|
||||
* @param route the route along which to open. It will be opened
|
||||
* to the proxy if present, or directly to the target.
|
||||
* @param route the route along which to open. It will be opened to
|
||||
* the first proxy if present, or directly to the target.
|
||||
* @param context the context for opening this connection
|
||||
* @param params the parameters for opening this connection
|
||||
*
|
||||
|
@ -93,7 +94,7 @@ public interface ManagedClientConnection extends
|
|||
|
||||
|
||||
/**
|
||||
* Indicates that a tunnel has been established.
|
||||
* Indicates that a tunnel to the target has been established.
|
||||
* The route is the one previously passed to {@link #open open}.
|
||||
* Subsequently, {@link #layerProtocol layerProtocol} can be called
|
||||
* to layer the TLS/SSL protocol on top of the tunnelled connection.
|
||||
|
@ -109,7 +110,32 @@ public interface ManagedClientConnection extends
|
|||
*
|
||||
* @throws IOException in case of a problem
|
||||
*/
|
||||
void tunnelCreated(boolean secure, HttpParams params)
|
||||
void tunnelTarget(boolean secure, HttpParams params)
|
||||
throws IOException
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that a tunnel to an intermediate proxy has been established.
|
||||
* This is used exclusively for so-called <i>proxy chains</i>, where
|
||||
* a request has to pass through multiple proxies before reaching the
|
||||
* target. In that case, all proxies but the last need to be tunnelled
|
||||
* when establishing the connection. Tunnelling of the last proxy to the
|
||||
* target is optional and would be indicated via {@link #tunnelTarget}.
|
||||
*
|
||||
* @param next the proxy to which the tunnel was established.
|
||||
* This is <i>not</i> the proxy <i>through</i> which
|
||||
* the tunnel was established, but the new end point
|
||||
* of the tunnel. The tunnel does <i>not</i> yet
|
||||
* reach to the target, use {@link #tunnelTarget}
|
||||
* to indicate an end-to-end tunnel.
|
||||
* @param secure <code>true</code> if the connection should be
|
||||
* considered secure, <code>false</code> otherwise
|
||||
* @param params the parameters for tunnelling this connection
|
||||
*
|
||||
* @throws IOException in case of a problem
|
||||
*/
|
||||
void tunnelProxy(HttpHost next, boolean secure, HttpParams params)
|
||||
throws IOException
|
||||
;
|
||||
|
||||
|
|
|
@ -439,7 +439,8 @@ public class DefaultClientRequestDirector
|
|||
*
|
||||
* @throws HttpException in case of a problem
|
||||
*/
|
||||
protected ManagedClientConnection allocateConnection(HttpRoute route, long timeout)
|
||||
protected ManagedClientConnection allocateConnection(HttpRoute route,
|
||||
long timeout)
|
||||
throws HttpException, ConnectionPoolTimeoutException {
|
||||
|
||||
return connManager.getConnection(route, timeout);
|
||||
|
@ -481,15 +482,24 @@ public class DefaultClientRequestDirector
|
|||
managedConn.open(route, context, this.params);
|
||||
break;
|
||||
|
||||
case HttpRouteDirector.TUNNEL_TARGET:
|
||||
boolean secure = createTunnel(route, context);
|
||||
LOG.debug("Tunnel created");
|
||||
managedConn.tunnelCreated(secure, this.params);
|
||||
break;
|
||||
case HttpRouteDirector.TUNNEL_TARGET: {
|
||||
boolean secure = createTunnelToTarget(route, context);
|
||||
LOG.debug("Tunnel to target created.");
|
||||
managedConn.tunnelTarget(secure, this.params);
|
||||
} break;
|
||||
|
||||
case HttpRouteDirector.TUNNEL_PROXY: {
|
||||
// The most simple example for this case is a proxy chain
|
||||
// of two proxies, where P1 must be tunnelled to P2.
|
||||
// route: Source -> P1 -> P2 -> Target (3 hops)
|
||||
// fact: Source -> P1 -> Target (2 hops)
|
||||
final int hop = fact.getHopCount()-1; // the hop to establish
|
||||
boolean secure = createTunnelToProxy(route, hop, context);
|
||||
LOG.debug("Tunnel to proxy created.");
|
||||
managedConn.tunnelProxy(route.getHopTarget(hop),
|
||||
secure, this.params);
|
||||
} break;
|
||||
|
||||
case HttpRouteDirector.TUNNEL_PROXY:
|
||||
throw new UnsupportedOperationException
|
||||
("Proxy chains are not supported.");
|
||||
|
||||
case HttpRouteDirector.LAYER_PROTOCOL:
|
||||
managedConn.layerProtocol(context, this.params);
|
||||
|
@ -516,8 +526,8 @@ public class DefaultClientRequestDirector
|
|||
|
||||
|
||||
/**
|
||||
* Creates a tunnel.
|
||||
* The connection must be established to the proxy.
|
||||
* Creates a tunnel to the target server.
|
||||
* The connection must be established to the (last) proxy.
|
||||
* A CONNECT request for tunnelling through the proxy will
|
||||
* be created and sent, the response received and checked.
|
||||
* This method does <i>not</i> update the connection with
|
||||
|
@ -534,7 +544,8 @@ public class DefaultClientRequestDirector
|
|||
* @throws HttpException in case of a problem
|
||||
* @throws IOException in case of an IO problem
|
||||
*/
|
||||
protected boolean createTunnel(HttpRoute route, HttpContext context)
|
||||
protected boolean createTunnelToTarget(HttpRoute route,
|
||||
HttpContext context)
|
||||
throws HttpException, IOException {
|
||||
|
||||
HttpHost proxy = route.getProxyHost();
|
||||
|
@ -645,9 +656,47 @@ public class DefaultClientRequestDirector
|
|||
// Even if that is secure, the hop to the target may be insecure.
|
||||
// Leave it to derived classes, consider insecure by default here.
|
||||
return false;
|
||||
|
||||
} // createTunnelToTarget
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a tunnel to an intermediate proxy.
|
||||
* This method is <i>not</i> implemented in this class.
|
||||
* It just throws an exception here.
|
||||
*
|
||||
* @param route the route to establish
|
||||
* @param hop the hop in the route to establish now.
|
||||
* <code>route.getHopTarget(hop)</code>
|
||||
* will return the proxy to tunnel to.
|
||||
* @param context the context for request execution
|
||||
*
|
||||
* @return <code>true</code> if the partially tunnelled connection
|
||||
* is secure, <code>false</code> otherwise.
|
||||
*
|
||||
* @throws HttpException in case of a problem
|
||||
* @throws IOException in case of an IO problem
|
||||
*/
|
||||
protected boolean createTunnelToProxy(HttpRoute route, int hop,
|
||||
HttpContext context)
|
||||
throws HttpException, IOException {
|
||||
|
||||
// Have a look at createTunnelToTarget and replicate the parts
|
||||
// you need in a custom derived class. If your proxies don't require
|
||||
// authentication, it is not too hard. But for the stock version of
|
||||
// HttpClient, we cannot make such simplifying assumptions and would
|
||||
// have to include proxy authentication code. The HttpComponents team
|
||||
// is currently not in a position to support rarely used code of this
|
||||
// complexity. Feel free to submit patches that refactor the code in
|
||||
// createTunnelToTarget to facilitate re-use for proxy tunnelling.
|
||||
|
||||
throw new UnsupportedOperationException
|
||||
("Proxy chains are not supported.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates the CONNECT request for tunnelling.
|
||||
* Called by {@link #createTunnel createTunnel}.
|
||||
|
|
|
@ -161,9 +161,9 @@ public abstract class AbstractPoolEntry {
|
|||
|
||||
|
||||
/**
|
||||
* Tracks tunnelling of the connection.
|
||||
* Tracks tunnelling of the connection to the target.
|
||||
* The tunnel has to be established outside by sending a CONNECT
|
||||
* request to the proxy.
|
||||
* request to the (last) proxy.
|
||||
*
|
||||
* @param secure <code>true</code> if the tunnel should be
|
||||
* considered secure, <code>false</code> otherwise
|
||||
|
@ -171,7 +171,7 @@ public abstract class AbstractPoolEntry {
|
|||
*
|
||||
* @throws IOException in case of a problem
|
||||
*/
|
||||
public void tunnelCreated(boolean secure, HttpParams params)
|
||||
public void tunnelTarget(boolean secure, HttpParams params)
|
||||
throws IOException {
|
||||
|
||||
if (params == null) {
|
||||
|
@ -194,7 +194,47 @@ public abstract class AbstractPoolEntry {
|
|||
secure, params);
|
||||
this.tracker.tunnelTarget(secure);
|
||||
|
||||
} // tunnelCreated
|
||||
} // tunnelTarget
|
||||
|
||||
|
||||
/**
|
||||
* Tracks tunnelling of the connection to a chained proxy.
|
||||
* The tunnel has to be established outside by sending a CONNECT
|
||||
* request to the previous proxy.
|
||||
*
|
||||
* @param next the proxy to which the tunnel was established.
|
||||
* See {@link org.apache.http.conn.ManagedClientConnection#tunnelProxy
|
||||
* ManagedClientConnection.tunnelProxy}
|
||||
* for details.
|
||||
* @param secure <code>true</code> if the tunnel should be
|
||||
* considered secure, <code>false</code> otherwise
|
||||
* @param params the parameters for tunnelling the connection
|
||||
*
|
||||
* @throws IOException in case of a problem
|
||||
*/
|
||||
public void tunnelProxy(HttpHost next, boolean secure, HttpParams params)
|
||||
throws IOException {
|
||||
|
||||
if (next == null) {
|
||||
throw new IllegalArgumentException
|
||||
("Next proxy must not be null.");
|
||||
}
|
||||
if (params == null) {
|
||||
throw new IllegalArgumentException
|
||||
("Parameters must not be null.");
|
||||
}
|
||||
|
||||
//@@@ check for proxy in planned route?
|
||||
if ((this.tracker == null) || !this.tracker.isConnected()) {
|
||||
throw new IllegalStateException("Connection not open.");
|
||||
}
|
||||
|
||||
// LOG.debug?
|
||||
|
||||
this.connection.update(null, next, secure, params);
|
||||
this.tracker.tunnelProxy(next, secure);
|
||||
|
||||
} // tunnelProxy
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,6 +33,7 @@ package org.apache.http.impl.conn;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.apache.http.conn.HttpRoute;
|
||||
|
@ -122,11 +123,20 @@ public abstract class AbstractPooledConnAdapter
|
|||
|
||||
|
||||
// non-javadoc, see interface ManagedHttpConnection
|
||||
public void tunnelCreated(boolean secure, HttpParams params)
|
||||
public void tunnelTarget(boolean secure, HttpParams params)
|
||||
throws IOException {
|
||||
|
||||
assertAttached();
|
||||
poolEntry.tunnelCreated(secure, params);
|
||||
poolEntry.tunnelTarget(secure, params);
|
||||
}
|
||||
|
||||
|
||||
// non-javadoc, see interface ManagedHttpConnection
|
||||
public void tunnelProxy(HttpHost next, boolean secure, HttpParams params)
|
||||
throws IOException {
|
||||
|
||||
assertAttached();
|
||||
poolEntry.tunnelProxy(next, secure, params);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
package org.apache.http.impl.conn;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.conn.HttpRoute;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
@ -64,7 +65,11 @@ public class ClientConnAdapterMockup extends AbstractClientConnAdapter {
|
|||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
public void tunnelCreated(boolean secure, HttpParams params) {
|
||||
public void tunnelTarget(boolean secure, HttpParams params) {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
public void tunnelProxy(HttpHost next, boolean secure, HttpParams params) {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue