hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rola...@apache.org
Subject svn commit: r542193 - in /jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http: conn/ impl/client/ impl/conn/
Date Mon, 28 May 2007 10:50:29 GMT
Author: rolandw
Date: Mon May 28 03:50:28 2007
New Revision: 542193

URL: http://svn.apache.org/viewvc?view=rev&rev=542193
Log:
proxy chains in HttpRoute/RouteTracker/RouteDirector

Modified:
    jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/HttpRoute.java
    jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteDirector.java
    jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteTracker.java
    jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
    jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractPoolEntry.java

Modified: jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/HttpRoute.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/HttpRoute.java?view=diff&rev=542193&r1=542192&r2=542193
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/HttpRoute.java
(original)
+++ jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/HttpRoute.java
Mon May 28 03:50:28 2007
@@ -50,7 +50,7 @@
  *
  * @since 4.0
  */
-public final class HttpRoute {
+public final class HttpRoute implements Cloneable {
 
     /** The target host to connect to. */
     private final HttpHost targetHost;
@@ -61,8 +61,8 @@
      */
     private final InetAddress localAddress;
 
-    /** The proxy server, if any. */
-    private final HttpHost proxyHost;
+    /** The proxy servers, if any. */
+    private final HttpHost[] proxyChain;
 
     /** Whether the the route is tunnelled through the proxy. */
     private final boolean tunnelled;
@@ -75,36 +75,41 @@
 
 
     /**
-     * Creates a new route with all attributes specified explicitly.
+     * 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 target    the host to which to route
      * @param local     the local address to route from, or
      *                  <code>null</code> for the default
-     * @param proxy     the proxy to use, or
+     * @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 <code>true</code> if the route is (to be) tunnelled
-     *                  via the proxy,
+     *                  end-to-end via the proxy chain,
      *                  <code>false</code> otherwise
      * @param layered   <code>true</code> if the route includes a
      *                  layered protocol,
      *                  <code>false</code> otherwise
      */
-    public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy,
-                     boolean secure, boolean tunnelled, boolean layered) {
+    private HttpRoute(InetAddress local, HttpHost target, HttpHost[] proxies,
+                      boolean secure, boolean tunnelled, boolean layered) {
         if (target == null) {
             throw new IllegalArgumentException
                 ("Target host may not be null.");
         }
-        if (tunnelled && (proxy == null)) {
+        if (tunnelled && (proxies == null)) {
             throw new IllegalArgumentException
-                ("Proxy host may not be null if tunnelled.");
+                ("Proxy required if tunnelled.");
         }
 
         this.targetHost   = target;
         this.localAddress = local;
-        this.proxyHost    = proxy;
+        this.proxyChain   = proxies;
         this.secure       = secure;
         this.tunnelled    = tunnelled;
         this.layered      = layered;
@@ -112,6 +117,52 @@
 
 
     /**
+     * Creates a new route with all attributes specified explicitly.
+     *
+     * @param target    the host to which to route
+     * @param local     the local address to route from, or
+     *                  <code>null</code> for the default
+     * @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 <code>true</code> if the route is (to be) tunnelled
+     *                  end-to-end via the proxy chain,
+     *                  <code>false</code> otherwise
+     * @param layered   <code>true</code> if the route includes a
+     *                  layered protocol,
+     *                  <code>false</code> otherwise
+     */
+    public HttpRoute(HttpHost target, InetAddress local, HttpHost[] proxies,
+                     boolean secure, boolean tunnelled, boolean layered) {
+        this(local, target, toChain(proxies), secure, tunnelled, layered);
+    }
+
+
+    /**
+     * Creates a new route with at most one proxy.
+     *
+     * @param target    the host to which to route
+     * @param local     the local address to route from, or
+     *                  <code>null</code> for the default
+     * @param proxy     the proxy 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 <code>true</code> if the route is (to be) tunnelled
+     *                  via the proxy,
+     *                  <code>false</code> otherwise
+     * @param layered   <code>true</code> if the route includes a
+     *                  layered protocol,
+     *                  <code>false</code> otherwise
+     */
+    public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy,
+                     boolean secure, boolean tunnelled, boolean layered) {
+        this(local, target, toChain(proxy), secure, tunnelled, layered);
+    }
+
+
+    /**
      * Creates a new direct route.
      * That is a route without a proxy.
      *
@@ -122,18 +173,17 @@
      *                  <code>false</code> otherwise
      */
     public HttpRoute(HttpHost target, InetAddress local, boolean secure) {
-        this(target, local, null, secure, false, false);
+        this(local, target, null, secure, false, false);
     }
 
 
     /**
      * Creates a new direct insecure route.
-     * That is a route without a proxy.
      *
      * @param target    the host to which to route
      */
     public HttpRoute(HttpHost target) {
-        this(target, null, null, false, false, false);
+        this(null, target, null, false, false, false);
     }
 
 
@@ -152,7 +202,7 @@
      */
     public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy,
                      boolean secure) {
-        this(target, local, proxy, secure, secure, secure);
+        this(local, target, toChain(proxy), secure, secure, secure);
         if (proxy == null) {
             throw new IllegalArgumentException
                 ("Proxy host may not be null.");
@@ -161,6 +211,47 @@
 
 
     /**
+     * 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, or <code>null</code>
+     */
+    private static HttpHost[] toChain(HttpHost proxy) {
+        if (proxy == null)
+            return null;
+
+        return new HttpHost[]{ proxy };
+    }
+
+
+    /**
+     * Helper to duplicate and check a proxy chain.
+     * An empty proxy chain is converted to <code>null</code>.
+     *
+     * @param proxies   the proxy chain to duplicate, or <code>null</code>
+     *
+     * @return  a new proxy chain array, or <code>null</code>
+     */
+    private static HttpHost[] toChain(HttpHost[] proxies) {
+        if ((proxies == null) || (proxies.length < 1))
+            return null;
+
+        for (int i=0; i<proxies.length; i++) {
+            if (proxies[i] == null)
+                throw new IllegalArgumentException
+                    ("Proxy chain may not contain null elements.");
+        }
+
+        // copy the proxy chain, the traditional way
+        HttpHost[] result = new HttpHost[proxies.length];
+        System.arraycopy(proxies, 0, result, 0, proxies.length);
+
+        return result;
+    }
+
+
+    /**
      * Obtains the target host.
      * 
      * @return the target host
@@ -182,20 +273,71 @@
 
 
     /**
-     * Obtains the proxy host.
+     * Obtains the number of hops in this route.
+     * A direct route has one hop. A route through a proxy has two hops.
+     * A route through a chain of <i>n</i> proxies has <i>n+1</i>
hops.
+     *
+     * @return  the number of hops in this route
+     */
+    public final int getHopCount() {
+        return (proxyChain == null) ? 1 : (proxyChain.length+1);
+    }
+
+
+    /**
+     * Obtains the target of a hop in this route.
+     * The target of the last hop is the {@link #getTargetHost target host},
+     * the target of previous hops is the respective proxy in the chain.
+     * For a route through exactly one proxy, target of hop 0 is the proxy
+     * and target of hop 1 is the target host.
+     *
+     * @param hop       index of the hop for which to get the target,
+     *                  0 for first
+     *
+     * @return  the target of the given hop
+     *
+     * @throws IllegalArgumentException
+     *  if the argument is negative or not less than
+     *  {@link #getHopCount getHopCount()}
+     */
+    public final HttpHost getHopTarget(int hop) {
+        if (hop < 0)
+            throw new IllegalArgumentException
+                ("Hop index must not be negative: " + hop);
+        if (((this.proxyChain == null) && (hop > 0)) ||
+            ( this.proxyChain.length < hop)) {
+            throw new IllegalArgumentException
+                ("Hop index " + hop +
+                 " exceeds route length " + getHopCount() +".");
+        }
+
+        HttpHost result = null;
+        if ((this.proxyChain != null) && (hop < this.proxyChain.length))
+            result = this.proxyChain[hop];
+        else
+            result = this.targetHost;
+
+        return result;
+    }
+
+
+    /**
+     * Obtains the first proxy host.
      * 
-     * @return the proxy host, or
+     * @return the first proxy in the proxy chain, or
      *         <code>null</code> if this route is direct
      */
     public final HttpHost getProxyHost() {
-        return this.proxyHost;
+        return (this.proxyChain == null) ? null : this.proxyChain[0];
     }
 
 
     /**
      * Checks whether this route is tunnelled through a proxy.
+     * If there is a proxy chain, only end-to-end tunnels are considered.
      *
-     * @return  <code>true</code> if tunnelled,
+     * @return  <code>true</code> if tunnelled end-to-end through at least
+     *          one proxy,
      *          <code>false</code> otherwise
      */
     public final boolean isTunnelled() {
@@ -205,6 +347,8 @@
 
     /**
      * Checks whether this route includes a layered protocol.
+     * In the presence of proxies, only layering over an end-to-end tunnel
+     * is considered.
      *
      * @return  <code>true</code> if layered,
      *          <code>false</code> otherwise
@@ -235,8 +379,11 @@
      *          where routes need to be represented. No conversion necessary.
      */
     public final HostConfiguration toHostConfig() {
+        if ((this.proxyChain != null) && (this.proxyChain.length > 1)) {
+            throw new IllegalStateException("Cannot convert proxy chain.");
+        }
         return new HostConfiguration
-            (this.targetHost, this.proxyHost, this.localAddress);
+            (this.targetHost, getProxyHost(), this.localAddress);
     }
 
 
@@ -257,18 +404,25 @@
         HttpRoute that = (HttpRoute) o;
         boolean equal = this.targetHost.equals(that.targetHost);
         equal &=
-            ( this.localAddress == that.localAddress) |
+            ( this.localAddress == that.localAddress) ||
             ((this.localAddress != null) &&
               this.localAddress.equals(that.localAddress));
         equal &=
-            ( this.proxyHost == that.proxyHost) |
-            ((this.proxyHost != null) &&
-              this.proxyHost.equals(that.proxyHost));
+            ( this.proxyChain        == that.proxyChain) ||
+            ((this.proxyChain        != null) &&
+             (this.proxyChain.length == that.proxyChain.length));
+        // comparison of actual proxies follows below
         equal &=
             (this.secure    == that.secure) &&
             (this.tunnelled == that.tunnelled) &&
             (this.layered   == that.layered);
 
+        // chain length has been compared above, now check the proxies
+        if (equal && (this.proxyChain != null)) {
+            for (int i=0; equal && (i<this.proxyChain.length); i++)
+                equal = this.proxyChain[i].equals(that.proxyChain[i]);
+        }
+
         return equal;
     }
 
@@ -284,8 +438,11 @@
 
         if (this.localAddress != null)
             hc ^= localAddress.hashCode();
-        if (this.proxyHost != null)
-            hc ^= proxyHost.hashCode();
+        if (this.proxyChain != null) {
+            hc ^= proxyChain.length;
+            for (int i=0; i<proxyChain.length; i++)
+                hc ^= proxyChain[i].hashCode();
+        }
 
         if (this.secure)
             hc ^= 0x11111111;
@@ -304,7 +461,7 @@
      * @return  a human-readable representation of this route
      */
     public final String toString() {
-        CharArrayBuffer cab = new CharArrayBuffer(80);
+        CharArrayBuffer cab = new CharArrayBuffer(50 + getHopCount()*30);
 
         cab.append("HttpRoute[");
         if (this.localAddress != null) {
@@ -319,14 +476,23 @@
         if (this.secure)
             cab.append('s');
         cab.append("}->");
-        if (this.proxyHost != null) {
-            cab.append(this.proxyHost);
-            cab.append("->");
+        if (this.proxyChain != null) {
+            for (int i=0; i<this.proxyChain.length; i++) {
+                cab.append(this.proxyChain[i]);
+                cab.append("->");
+            }
         }
         cab.append(this.targetHost);
         cab.append(']');
 
         return cab.toString();
     }
+
+
+    // default implementation of clone() is sufficient
+    public Object clone() throws CloneNotSupportedException {
+        return super.clone();
+    }
+
 
 } // class HttpRoute

Modified: jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteDirector.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteDirector.java?view=diff&rev=542193&r1=542192&r2=542193
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteDirector.java
(original)
+++ jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteDirector.java
Mon May 28 03:50:28 2007
@@ -60,11 +60,14 @@
     /** Step: open connection to proxy. */
     public final static int CONNECT_PROXY = 2;
 
-    /** Step: tunnel through proxy. */
-    public final static int CREATE_TUNNEL = 3;
+    /** Step: tunnel through proxy to target. */
+    public final static int TUNNEL_TARGET = 3;
+
+    /** Step: tunnel through proxy to other proxy. */
+    public final static int TUNNEL_PROXY = 4;
 
     /** Step: layer protocol (over tunnel). */
-    public final static int LAYER_PROTOCOL = 4;
+    public final static int LAYER_PROTOCOL = 5;
 
 
     // public default constructor
@@ -91,10 +94,10 @@
 
         if (fact == null)
             step = firstStep(plan);
-        else if (plan.getProxyHost() == null)
-            step = directStep(plan, fact);
-        else
+        else if (plan.getHopCount() > 1)
             step = proxiedStep(plan, fact);
+        else
+            step = directStep(plan, fact);
 
         return step;
 
@@ -110,8 +113,8 @@
      */
     protected int firstStep(HttpRoute plan) {
 
-        return (plan.getProxyHost() == null) ?
-            CONNECT_TARGET : CONNECT_PROXY;
+        return (plan.getHopCount() > 1) ?
+            CONNECT_PROXY : CONNECT_TARGET;
     }
 
 
@@ -126,7 +129,7 @@
      */
     protected int directStep(HttpRoute plan, HttpRoute fact) {
 
-        if (fact.getProxyHost() != null)
+        if (fact.getHopCount() > 1)
             return UNREACHABLE;
         if (!plan.getTargetHost().equals(fact.getTargetHost()))
             return UNREACHABLE;
@@ -156,19 +159,30 @@
      */
     protected int proxiedStep(HttpRoute plan, HttpRoute fact) {
 
-        if (fact.getProxyHost() == null)
+        if (fact.getHopCount() <= 1)
+            return UNREACHABLE;
+        if (!plan.getTargetHost().equals(fact.getTargetHost()))
             return UNREACHABLE;
-        if (!plan.getProxyHost().equals(fact.getProxyHost()) ||
-            !plan.getTargetHost().equals(fact.getTargetHost()))
+        final int phc = plan.getHopCount();
+        final int fhc = fact.getHopCount();
+        if (phc < fhc)
             return UNREACHABLE;
 
-        // proxy and target are the same, check tunnelling and layering
+        for (int i=0; i<phc-1; i++) {
+            if (!plan.getHopTarget(i).equals(fact.getHopTarget(i)))
+                return UNREACHABLE;
+        }
+        // now we know that the target matches and proxies so far are the same
+        if (phc > fhc)
+            return TUNNEL_PROXY; // need to extend the proxy chain
+            
+        // proxy chain and target are the same, check tunnelling and layering
         if ((fact.isTunnelled() && !plan.isTunnelled()) ||
             (fact.isLayered()   && !plan.isLayered()))
             return UNREACHABLE;
 
         if (plan.isTunnelled() && !fact.isTunnelled())
-            return CREATE_TUNNEL;
+            return TUNNEL_TARGET;
         if (plan.isLayered() && !fact.isLayered())
             return LAYER_PROTOCOL;
 

Modified: jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteTracker.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteTracker.java?view=diff&rev=542193&r1=542192&r2=542193
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteTracker.java
(original)
+++ jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/RouteTracker.java
Mon May 28 03:50:28 2007
@@ -48,7 +48,7 @@
  *
  * @since 4.0
  */
-public final class RouteTracker {
+public final class RouteTracker implements Cloneable {
 
     /** The target host to connect to. */
     private final HttpHost targetHost;
@@ -65,10 +65,10 @@
     /** Whether the first hop of the route is established. */
     private boolean connected;
 
-    /** The proxy server, if any. */
-    private HttpHost proxyHost;
+    /** The proxy chain, if any. */
+    private HttpHost[] proxyChain;
 
-    /** Whether the the route is tunnelled through the proxy. */
+    /** Whether the the route is tunnelled end-to-end through proxies. */
     private boolean tunnelled;
 
     /** Whether the route is layered over a tunnel. */
@@ -114,13 +114,16 @@
      *                  <code>false</code> otherwise
      */
     public final void connectTarget(boolean secure) {
+        if (this.connected) {
+            throw new IllegalStateException("Already connected.");
+        }
         this.connected = true;
         this.secure = secure;
     }
 
 
     /**
-     * Tracks connecting to a proxy.
+     * Tracks connecting to the first proxy.
      *
      * @param proxy     the proxy connected to
      * @param secure    <code>true</code> if the route is secure,
@@ -130,20 +133,23 @@
         if (proxy == null) {
             throw new IllegalArgumentException("Proxy host may not be null.");
         }
-        this.connected = true;
-        this.proxyHost = proxy;
-        this.secure    = secure;
+        if (this.connected) {
+            throw new IllegalStateException("Already connected.");
+        }
+        this.connected  = true;
+        this.proxyChain = new HttpHost[]{ proxy };
+        this.secure     = secure;
     }
 
 
     /**
-     * Tracks tunnelling through the proxy.
+     * Tracks tunnelling to the target.
      *
      * @param secure    <code>true</code> if the route is secure,
      *                  <code>false</code> otherwise
      */
-    public final void createTunnel(boolean secure) {
-        if (this.proxyHost == null) {
+    public final void tunnelTarget(boolean secure) {
+        if (this.proxyChain == null) {
             throw new IllegalStateException("No tunnel without proxy.");
         }
         if (!this.connected) {
@@ -155,6 +161,37 @@
 
 
     /**
+     * Tracks tunnelling to a proxy in a proxy chain.
+     * This will extend the tracked proxy chain, but it does not mark
+     * the route as tunnelled. Only end-to-end tunnels are considered there.
+     *
+     * @param proxy     the proxy tunnelled to
+     * @param secure    <code>true</code> if the route is secure,
+     *                  <code>false</code> otherwise
+     */
+    public final void tunnelProxy(HttpHost proxy, boolean secure) {
+        if (proxy == null) {
+            throw new IllegalArgumentException("Proxy host may not be null.");
+        }
+        if (this.proxyChain == null) {
+            throw new IllegalStateException("No proxy tunnel without proxy.");
+        }
+        if (!this.connected) {
+            throw new IllegalStateException("No tunnel unless connected.");
+        }
+
+        // prepare an extended proxy chain
+        HttpHost[] proxies = new HttpHost[this.proxyChain.length+1];
+        System.arraycopy(this.proxyChain, 0,
+                         proxies, 0, this.proxyChain.length);
+        proxies[proxies.length+1] = proxy;
+
+        this.proxyChain = proxies;
+        this.secure     = secure;
+    }
+
+
+    /**
      * Tracks layering a protocol.
      *
      * @param secure    <code>true</code> if the route is secure,
@@ -194,12 +231,67 @@
 
 
     /**
-     * Obtains the proxy host.
+     * Obtains the number of tracked hops.
+     * An unconnected route has no hops.
+     * Connecting directly to the target adds one hop.
+     * Connecting to a proxy adds two hops, one for the proxy and
+     * one for the target.
+     * Tunnelling to a proxy in a proxy chain adds one hop.
+     *
+     * @return  the number of hops in the tracked route
+     */
+    public final int getHopCount() {
+        int hops = 0;
+        if (this.connected) {
+            if (proxyChain == null)
+                hops = 1;
+            else
+                hops = proxyChain.length + 1;
+        }
+        return hops;
+    }
+
+
+    /**
+     * Obtains the target of a hop in this route.
+     *
+     * @param hop       index of the hop for which to get the target,
+     *                  0 for first
+     *
+     * @return  the target of the given hop
+     *
+     * @throws IllegalArgumentException
+     *  if the argument is negative or not less than
+     *  {@link #getHopCount getHopCount()}
+     */
+    public final HttpHost getHopTarget(int hop) {
+        if (hop < 0)
+            throw new IllegalArgumentException
+                ("Hop index must not be negative: " + hop);
+        final int hopcount = getHopCount();
+        if (hop >= hopcount) {
+            throw new IllegalArgumentException
+                ("Hop index " + hop +
+                 " exceeds tracked route length " + hopcount +".");
+        }
+
+        HttpHost result = null;
+        if ((this.proxyChain != null) && (hop < this.proxyChain.length))
+            result = this.proxyChain[hop];
+        else
+            result = this.targetHost;
+
+        return result;
+    }
+
+
+    /**
+     * Obtains the first proxy host.
      * 
-     * @return the proxy host, or <code>null</code> if not tracked
+     * @return the first proxy host, or <code>null</code> if not tracked
      */
     public final HttpHost getProxyHost() {
-        return this.proxyHost;
+        return (this.proxyChain == null) ? null : this.proxyChain[0];
     }
 
 
@@ -258,7 +350,7 @@
     public final HttpRoute toRoute() {
         return !this.connected ?
             null : new HttpRoute(this.targetHost, this.localAddress,
-                                 this.proxyHost, this.secure,
+                                 this.proxyChain, this.secure,
                                  this.tunnelled, this.layered);
     }
 
@@ -277,8 +369,11 @@
      * @return  a representation of the route tracked so far
      */
     public final HostConfiguration toHostConfig() {
+        if ((this.proxyChain != null) && (this.proxyChain.length > 1)) {
+            throw new IllegalStateException("Cannot convert proxy chain.");
+        }
         return new HostConfiguration
-            (this.targetHost, this.proxyHost, this.localAddress);
+            (this.targetHost, getProxyHost(), this.localAddress);
     }
 
 
@@ -299,19 +394,26 @@
         RouteTracker that = (RouteTracker) o;
         boolean equal = this.targetHost.equals(that.targetHost);
         equal &=
-            ( this.localAddress == that.localAddress) |
+            ( this.localAddress == that.localAddress) ||
             ((this.localAddress != null) &&
               this.localAddress.equals(that.localAddress));
         equal &=
-            ( this.proxyHost == that.proxyHost) |
-            ((this.proxyHost != null) &&
-              this.proxyHost.equals(that.proxyHost));
+            ( this.proxyChain        == that.proxyChain) ||
+            ((this.proxyChain        != null) &&
+             (this.proxyChain.length == that.proxyChain.length));
+        // comparison of actual proxies follows below
         equal &=
             (this.connected == that.connected) &&
             (this.secure    == that.secure) &&
             (this.tunnelled == that.tunnelled) &&
             (this.layered   == that.layered);
 
+        // chain length has been compared above, now check the proxies
+        if (equal && (this.proxyChain != null)) {
+            for (int i=0; equal && (i<this.proxyChain.length); i++)
+                equal = this.proxyChain[i].equals(that.proxyChain[i]);
+        }
+
         return equal;
     }
 
@@ -330,8 +432,11 @@
 
         if (this.localAddress != null)
             hc ^= localAddress.hashCode();
-        if (this.proxyHost != null)
-            hc ^= proxyHost.hashCode();
+        if (this.proxyChain != null) {
+            hc ^= proxyChain.length;
+            for (int i=0; i<proxyChain.length; i++)
+                hc ^= proxyChain[i].hashCode();
+        }
 
         if (this.connected)
             hc ^= 0x11111111;
@@ -352,7 +457,7 @@
      * @return  a human-readable representation of the tracked route
      */
     public final String toString() {
-        CharArrayBuffer cab = new CharArrayBuffer(80);
+        CharArrayBuffer cab = new CharArrayBuffer(50 + getHopCount()*30);
 
         cab.append("RouteTracker[");
         if (this.localAddress != null) {
@@ -369,14 +474,23 @@
         if (this.secure)
             cab.append('s');
         cab.append("}->");
-        if (this.proxyHost != null) {
-            cab.append(this.proxyHost);
-            cab.append("->");
+        if (this.proxyChain != null) {
+            for (int i=0; i<this.proxyChain.length; i++) {
+                cab.append(this.proxyChain[i]);
+                cab.append("->");
+            }
         }
         cab.append(this.targetHost);
         cab.append(']');
 
         return cab.toString();
     }
+
+
+    // default implementation of clone() is sufficient
+    public Object clone() throws CloneNotSupportedException {
+        return super.clone();
+    }
+
 
 } // class RouteTracker

Modified: jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java?view=diff&rev=542193&r1=542192&r2=542193
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
(original)
+++ jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
Mon May 28 03:50:28 2007
@@ -487,11 +487,15 @@
                 managedConn.open(route, context, requestExec.getParams());
                 break;
 
-            case RouteDirector.CREATE_TUNNEL:
+            case RouteDirector.TUNNEL_TARGET:
                 boolean secure = createTunnel(route, context);
                 LOG.debug("Tunnel created");
                 managedConn.tunnelCreated(secure, requestExec.getParams());
                 break;
+
+            case RouteDirector.TUNNEL_PROXY:
+                throw new UnsupportedOperationException
+                    ("Proxy chains are not supported.");
 
             case RouteDirector.LAYER_PROTOCOL:
                 managedConn.layerProtocol(context, requestExec.getParams());

Modified: jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractPoolEntry.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractPoolEntry.java?view=diff&rev=542193&r1=542192&r2=542193
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractPoolEntry.java
(original)
+++ jakarta/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractPoolEntry.java
Mon May 28 03:50:28 2007
@@ -186,7 +186,7 @@
 
         this.connection.update(null, tracker.getTargetHost(),
                                secure, params);
-        this.tracker.createTunnel(secure);
+        this.tracker.tunnelTarget(secure);
 
     } // tunnelCreated
 



Mime
View raw message