You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ro...@apache.org on 2007/02/09 21:52:28 UTC

svn commit: r505491 - in /jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http: conn/RouteDirector.java conn/RouteTracker.java impl/client/DefaultClientRequestDirector.java impl/conn/ThreadSafeClientConnManager.java

Author: rolandw
Date: Fri Feb  9 12:52:27 2007
New Revision: 505491

URL: http://svn.apache.org/viewvc?view=rev&rev=505491
Log:
request director uses route director; still missing tunnelling

Added:
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteDirector.java   (with props)
Modified:
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteTracker.java
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java

Added: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteDirector.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteDirector.java?view=auto&rev=505491
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteDirector.java (added)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteDirector.java Fri Feb  9 12:52:27 2007
@@ -0,0 +1,181 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+
+
+/**
+ * Provides directions on establishing a route.
+ * Instances of this class compare a planned route with a tracked route
+ * and indicate the next step required.
+ * 
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision$
+ *
+ * @since 4.0
+ */
+public class RouteDirector {
+
+    /** Indicates that the route can not be established at all. */
+    public final static int UNREACHABLE = -1;
+
+    /** Indicates that the route is complete. */
+    public final static int COMPLETE = 0;
+
+    /** Step: open connection to target. */
+    public final static int CONNECT_TARGET = 1;
+
+    /** Step: open connection to proxy. */
+    public final static int CONNECT_PROXY = 2;
+
+    /** Step: tunnel through proxy. */
+    public final static int CREATE_TUNNEL = 3;
+
+    /** Step: layer protocol (over tunnel). */
+    public final static int LAYER_PROTOCOL = 4;
+
+
+    // public default constructor
+
+
+    /**
+     * Provides the next step.
+     *
+     * @param plan      the planned route
+     * @param fact      the currently established route, or
+     *                  <code>null</code> if nothing is established
+     *
+     * @return  one of the constants defined in this class, indicating
+     *          either the next step to perform, or success, or failure.
+     *          0 is for success, a negative value for failure.
+     */
+    public int nextStep(HttpRoute plan, HttpRoute fact) {
+        if (plan == null) {
+            throw new IllegalArgumentException
+                ("Planned route may not be null.");
+        }
+
+        int step = UNREACHABLE;
+
+        if (fact == null)
+            step = firstStep(plan);
+        else if (plan.getProxyHost() == null)
+            step = directStep(plan, fact);
+        else
+            step = proxiedStep(plan, fact);
+
+        return step;
+
+    } // nextStep
+
+
+    /**
+     * Determines the first step to establish a route.
+     *
+     * @param plan      the planned route
+     *
+     * @return  the first step
+     */
+    protected int firstStep(HttpRoute plan) {
+
+        return (plan.getProxyHost() == null) ?
+            CONNECT_TARGET : CONNECT_PROXY;
+    }
+
+
+    /**
+     * Determines the next step to establish a direct connection.
+     *
+     * @param plan      the planned route
+     * @param fact      the currently established route
+     *
+     * @return  one of the constants defined in this class, indicating
+     *          either the next step to perform, or success, or failure
+     */
+    protected int directStep(HttpRoute plan, HttpRoute fact) {
+
+        if (fact.getProxyHost() != null)
+            return UNREACHABLE;
+        if (!plan.getTargetHost().equals(fact.getTargetHost()))
+            return UNREACHABLE;
+        // If the security values differ, we could now suggest to layer
+        // a secure protocol on the direct connection. Layering on direct
+        // connections has not been supported in HttpClient 3.x, we don't
+        // consider it here until there is a real-life use case for it.
+
+        // yes, this would cover the two checks above as well...
+        if (!plan.equals(fact))
+            return UNREACHABLE;
+
+        return COMPLETE;
+    }
+
+
+    /**
+     * Determines the next step to establish a connection via proxy.
+     *
+     * @param plan      the planned route
+     * @param fact      the currently established route
+     *
+     * @return  one of the constants defined in this class, indicating
+     *          either the next step to perform, or success, or failure
+     */
+    protected int proxiedStep(HttpRoute plan, HttpRoute fact) {
+
+        if (fact.getProxyHost() == null)
+            return UNREACHABLE;
+        if (!plan.getProxyHost().equals(fact.getProxyHost()) ||
+            !plan.getTargetHost().equals(fact.getTargetHost()))
+            return UNREACHABLE;
+
+        // proxy 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;
+        if (plan.isLayered() && !fact.isLayered())
+            return LAYER_PROTOCOL;
+
+        // tunnel and layering are the same, remains to check the security
+        if (plan.isSecure() != fact.isSecure())
+            return UNREACHABLE;
+
+        return COMPLETE;
+    }
+
+
+} // class RouteDirector

Propchange: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteDirector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteDirector.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteDirector.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteTracker.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteTracker.java?view=diff&rev=505491&r1=505490&r2=505491
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteTracker.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/RouteTracker.java Fri Feb  9 12:52:27 2007
@@ -142,7 +142,7 @@
      * @param secure    <code>true</code> if the route is secure,
      *                  <code>false</code> otherwise
      */
-    public final void establishTunnel(boolean secure) {
+    public final void createTunnel(boolean secure) {
         if (this.proxyHost == null) {
             throw new IllegalStateException("No tunnel without proxy.");
         }

Modified: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java?view=diff&rev=505491&r1=505490&r2=505491
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java Fri Feb  9 12:52:27 2007
@@ -39,6 +39,8 @@
 import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.http.conn.HttpRoute;
+import org.apache.http.conn.RouteDirector;
 import org.apache.http.conn.HostConfiguration;
 import org.apache.http.conn.ClientConnectionManager;
 import org.apache.http.conn.ManagedClientConnection;
@@ -166,40 +168,117 @@
     /**
      * Establishes the target route.
      *
-     * @param route     the route to establish
+     * @param hostconf  the route to establish
      * @param context   the context for the request execution
      *
      * @throws HttpException    in case of a problem
      * @throws IOException      in case of an IO problem
      */
-    protected void establishRoute(HostConfiguration route,
+    protected void establishRoute(HostConfiguration hostconf,
                                   HttpContext context)
         throws HttpException, IOException {
 
-        //@@@ where do we get the currently established route?
         //@@@ how to handle CONNECT requests for tunnelling?
+        //@@@ refuse to send external CONNECT via director? special handling?
 
-        //@@@ for now, let's just deal with connected and not connected
-        if ((route.getProxyHost() != null) &&
-            !"http".equals(route.getHost().getSchemeName())) {
-            //@@@ the actual check should be whether the socket factory
-            //@@@ for the target host scheme is a SecureSocketFactory
-            throw new UnsupportedOperationException
-                ("Currently only plain http via proxy is supported.");
-        }
-        if (managedConn.isOpen())
-            return; // already established
+        //@@@ this check for secure connections is an ugly hack until the
+        //@@@ director is changed to expect HttpRoute instead of HostConfig
+        //@@@ the actual check should be whether the socket factory
+        //@@@ for the target host scheme is a SecureSocketFactory
+        HttpRoute route = null;
+        {
+            final boolean secure =
+                !"http".equals(hostconf.getHost().getSchemeName());
+            if (hostconf.getProxyHost() == null)
+                route = new HttpRoute(hostconf.getHost(),
+                                      hostconf.getLocalAddress(),
+                                      secure);
+            else
+                route = new HttpRoute(hostconf.getHost(),
+                                      hostconf.getLocalAddress(),
+                                      hostconf.getProxyHost(),
+                                      secure);
+            System.out.println("@@@ planned: " + route);
+        } //@@@ end of ugly HostConfiguration -> HttpRoute conversion
 
-        //@@@ should the request parameters already be used here?
+
+        //@@@ should the request parameters already be used below?
         //@@@ probably yes, but they're not linked yet
-        //@@@ will linking above cause problems with linking in reqExec?
+        //@@@ will linking here/above cause problems with linking in reqExec?
         //@@@ probably not, because the parent is replaced
         //@@@ just make sure we don't link parameters to themselves
 
-        managedConn.open(route, context, defaultParams);
+
+        RouteDirector rowdy = new RouteDirector();
+        int step;
+        do {
+            HttpRoute fact = managedConn.getRoute();
+            System.out.println("@@@ current: " + fact);
+            step = rowdy.nextStep(route, fact);
+            System.out.println("@@@ action => " + step);
+
+            switch (step) {
+
+            case RouteDirector.CONNECT_TARGET:
+            case RouteDirector.CONNECT_PROXY:
+                managedConn.open(hostconf, context, defaultParams);
+                break;
+
+            case RouteDirector.CREATE_TUNNEL:
+                boolean secure = createTunnel(route, context);
+                managedConn.tunnelCreated(secure, defaultParams);
+                break;
+
+            case RouteDirector.LAYER_PROTOCOL:
+                managedConn.layerProtocol(context, defaultParams);
+                break;
+
+            case RouteDirector.UNREACHABLE:
+                throw new IllegalStateException
+                    ("Unable to establish route." +
+                     "\nplanned = " + route +
+                     "\ncurrent = " + fact);
+
+            case RouteDirector.COMPLETE:
+                // do nothing
+                break;
+
+            default:
+                throw new IllegalStateException
+                    ("Unknown step indicator "+step+" from RouteDirector.");
+            } // switch
+
+        } while (step > RouteDirector.COMPLETE);
 
     } // establishConnection
 
+
+    /**
+     * Creates a tunnel.
+     * The connection must be established to the proxy.
+     * A CONNECT request for tunnelling through the proxy
+     * will be created and sent.
+     *
+     * @param route     the route to establish
+     * @param context   the context for request execution
+     *
+     * @return  <code>true</code> if the tunnelled route is secure,
+     *          <code>false</code> otherwise.
+     *          The implementation here always returns <code>false</code>,
+     *          but derived classes may override.
+     *
+     * @throws HttpException    in case of a problem
+     * @throws IOException      in case of an IO problem
+     */
+    protected boolean createTunnel(HttpRoute route, HttpContext context) {
+        if (true) throw new UnsupportedOperationException("@@@ don't know how to establish a tunnel yet");
+
+        // How to decide on security of the tunnelled connection?
+        // The socket factory knows only about the segment to the proxy.
+        // Even if that is secure, the hop to the target may be insecure.
+        // Leave it to derived classes, consider everything insecure here.
+        return false;
+    }
 
     /**
      * Prepares a request for execution.

Modified: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java?view=diff&rev=505491&r1=505490&r2=505491
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java Fri Feb  9 12:52:27 2007
@@ -1211,7 +1211,7 @@
 
             this.connection.update(null, tracker.getTargetHost(),
                                    secure, params);
-            this.tracker.establishTunnel(secure);
+            this.tracker.createTunnel(secure);
 
         } // tunnelCreated