diff --git a/src/java/org/apache/http/conn/ManagedClientConnection.java b/src/java/org/apache/http/conn/ManagedClientConnection.java index 8ee511dec..ac2877029 100644 --- a/src/java/org/apache/http/conn/ManagedClientConnection.java +++ b/src/java/org/apache/http/conn/ManagedClientConnection.java @@ -67,6 +67,16 @@ public interface ManagedClientConnection ; + /** + * Obtains the current route of this connection. + * + * @return the route established so far, or + * null if not connected + */ + HttpRoute getRoute() + ; + + /** * Opens this connection according to the given route. * diff --git a/src/java/org/apache/http/conn/RouteTracker.java b/src/java/org/apache/http/conn/RouteTracker.java index 2c9ae8f09..973961699 100644 --- a/src/java/org/apache/http/conn/RouteTracker.java +++ b/src/java/org/apache/http/conn/RouteTracker.java @@ -110,7 +110,7 @@ public final class RouteTracker implements Cloneable { /** * Tracks connecting to the target. * - * @param secure true if the connection is secure, + * @param secure true if the route is secure, * false otherwise */ public final void connectTarget(boolean secure) { @@ -123,20 +123,26 @@ public final class RouteTracker implements Cloneable { * Tracks connecting to a proxy. * * @param proxy the proxy connected to + * @param secure true if the route is secure, + * false otherwise */ - public final void connectProxy(HttpHost proxy) { + public final void connectProxy(HttpHost proxy, boolean secure) { if (proxy == null) { throw new IllegalArgumentException("Proxy host may not be null."); } this.connected = true; this.proxyHost = proxy; + this.secure = secure; } /** * Tracks tunnelling through the proxy. + * + * @param secure true if the route is secure, + * false otherwise */ - public final void establishTunnel() { + public final void establishTunnel(boolean secure) { if (this.proxyHost == null) { throw new IllegalStateException("No tunnel without proxy."); } @@ -144,6 +150,7 @@ public final class RouteTracker implements Cloneable { throw new IllegalStateException("No tunnel unless connected."); } this.tunnelled = true; + this.secure = secure; } diff --git a/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java b/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java index 0b671b19d..dedb62110 100644 --- a/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java +++ b/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java @@ -47,6 +47,8 @@ import org.apache.http.HttpHost; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.ClientConnectionOperator; import org.apache.http.conn.ConnectionPoolTimeoutException; +import org.apache.http.conn.HttpRoute; +import org.apache.http.conn.RouteTracker; import org.apache.http.conn.HostConfiguration; import org.apache.http.conn.ManagedClientConnection; import org.apache.http.conn.OperatedClientConnection; @@ -817,7 +819,7 @@ public class ThreadSafeClientConnManager */ private synchronized void deleteConnection(TrackingPoolEntry entry) { - HostConfiguration route = entry.route; + HostConfiguration route = entry.tracker.toHostConfig(); if (LOG.isDebugEnabled()) { LOG.debug("Reclaiming connection, hostConfig=" + route); @@ -1084,14 +1086,8 @@ public class ThreadSafeClientConnManager /** The route for which this entry gets allocated. */ private HostConfiguration plannedRoute; - /** The host configuration part of the tracked route. */ - private HostConfiguration route; - - /** The tunnel created flag part of the tracked route. */ - private boolean tunnelled; - - /** The layered flag part of the tracked route. */ - private boolean layered; + /** The tracked route, or null before tracking starts. */ + private RouteTracker tracker; /** The connection manager. */ private ThreadSafeClientConnManager manager; @@ -1112,8 +1108,8 @@ public class ThreadSafeClientConnManager */ private TrackingPoolEntry(OperatedClientConnection occ) { this.connection = occ; - this.route = null; - this.tunnelled = false; + //@@@ pass planned route to the constructor? + this.tracker = null; this.manager = ThreadSafeClientConnManager.this; this.reference = new WeakReference(this, REFERENCE_QUEUE); } @@ -1141,6 +1137,9 @@ public class ThreadSafeClientConnManager throw new IllegalArgumentException ("Parameters must not be null."); } + if ((this.tracker != null) && this.tracker.isConnected()) { + throw new IllegalStateException("Connection already open."); + } // - collect the arguments // - call the operator @@ -1155,6 +1154,8 @@ public class ThreadSafeClientConnManager } final HttpHost proxy = route.getProxyHost(); + //@@@ verify against planned route? + if (LOG.isDebugEnabled()) { if (proxy == null) { LOG.debug("Open connection to " + target); @@ -1164,12 +1165,18 @@ public class ThreadSafeClientConnManager } } + this.tracker = new RouteTracker + (route.getHost(), route.getLocalAddress()); + ThreadSafeClientConnManager.this.connectionOperator.openConnection (this.connection, (proxy != null) ? proxy : target, context, params); - this.route = route; + if (proxy == null) + this.tracker.connectTarget(this.connection.isSecure()); + else + this.tracker.connectProxy(proxy, this.connection.isSecure()); } // open @@ -1193,17 +1200,18 @@ public class ThreadSafeClientConnManager ("Parameters must not be null."); } - if (route.getProxyHost() == null) { - throw new IllegalStateException("No proxy in route."); + //@@@ check for proxy in planned route? + if ((this.tracker == null) || !this.tracker.isConnected()) { + throw new IllegalStateException("Connection not open."); } - if (tunnelled) { + if (this.tracker.isTunnelled()) { throw new IllegalStateException ("Connection is already tunnelled."); } - this.connection.update(null, route.getHost(), + this.connection.update(null, tracker.getTargetHost(), secure, params); - tunnelled = true; + this.tracker.establishTunnel(secure); } // tunnelCreated @@ -1225,13 +1233,17 @@ public class ThreadSafeClientConnManager ("Parameters must not be null."); } - if (!this.tunnelled) { + if ((this.tracker == null) || !this.tracker.isConnected()) { + throw new IllegalStateException("Connection not open."); + } + if (!this.tracker.isTunnelled()) { + //@@@ allow this? throw new IllegalStateException ("Protocol layering without a tunnel not supported."); } - if (this.layered) { + if (this.tracker.isLayered()) { throw new IllegalStateException - ("Protocol already layered."); + ("Multiple protocol layering not supported."); } // - collect the arguments @@ -1240,7 +1252,7 @@ public class ThreadSafeClientConnManager // In this order, we can be sure that only a successful // layering on top of the connection will be tracked. - final HttpHost target = route.getHost(); + final HttpHost target = tracker.getTargetHost(); if (LOG.isDebugEnabled()) { LOG.debug("Layer protocol on connection to " + target); @@ -1250,7 +1262,7 @@ public class ThreadSafeClientConnManager .updateSecureConnection(this.connection, target, context, params); - this.layered = true; + this.tracker.layerProtocol(this.connection.isSecure()); } // layerProtocol @@ -1261,9 +1273,8 @@ public class ThreadSafeClientConnManager * in both cases. This method should be called regardless of * whether the close or shutdown succeeds or triggers an error. */ - private void closing() { - route = null; - tunnelled = false; + private void closing() { + tracker = null; } } // class TrackingPoolEntry @@ -1322,6 +1333,14 @@ public class ThreadSafeClientConnManager } + // non-javadoc, see interface ManagedHttpConnection + public HttpRoute getRoute() { + + assertAttached(); + return (poolEntry.tracker == null) ? + null : poolEntry.tracker.toRoute(); + } + // non-javadoc, see interface ManagedHttpConnection public void open(HostConfiguration route, HttpContext context, HttpParams params)