mobile/android/thirdparty/ch/boye/httpclientandroidlib/conn/routing/RouteTracker.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2  * ====================================================================
     3  * Licensed to the Apache Software Foundation (ASF) under one
     4  * or more contributor license agreements.  See the NOTICE file
     5  * distributed with this work for additional information
     6  * regarding copyright ownership.  The ASF licenses this file
     7  * to you under the Apache License, Version 2.0 (the
     8  * "License"); you may not use this file except in compliance
     9  * with the License.  You may obtain a copy of the License at
    10  *
    11  *   http://www.apache.org/licenses/LICENSE-2.0
    12  *
    13  * Unless required by applicable law or agreed to in writing,
    14  * software distributed under the License is distributed on an
    15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    16  * KIND, either express or implied.  See the License for the
    17  * specific language governing permissions and limitations
    18  * under the License.
    19  * ====================================================================
    20  *
    21  * This software consists of voluntary contributions made by many
    22  * individuals on behalf of the Apache Software Foundation.  For more
    23  * information on the Apache Software Foundation, please see
    24  * <http://www.apache.org/>.
    25  *
    26  */
    28 package ch.boye.httpclientandroidlib.conn.routing;
    30 import java.net.InetAddress;
    32 import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
    33 import ch.boye.httpclientandroidlib.util.LangUtils;
    35 import ch.boye.httpclientandroidlib.HttpHost;
    37 /**
    38  * Helps tracking the steps in establishing a route.
    39  *
    40  * @since 4.0
    41  */
    42 @NotThreadSafe
    43 public final class RouteTracker implements RouteInfo, Cloneable {
    45     /** The target host to connect to. */
    46     private final HttpHost targetHost;
    48     /**
    49      * The local address to connect from.
    50      * <code>null</code> indicates that the default should be used.
    51      */
    52     private final InetAddress localAddress;
    54     // the attributes above are fixed at construction time
    55     // now follow attributes that indicate the established route
    57     /** Whether the first hop of the route is established. */
    58     private boolean connected;
    60     /** The proxy chain, if any. */
    61     private HttpHost[] proxyChain;
    63     /** Whether the the route is tunnelled end-to-end through proxies. */
    64     private TunnelType tunnelled;
    66     /** Whether the route is layered over a tunnel. */
    67     private LayerType layered;
    69     /** Whether the route is secure. */
    70     private boolean secure;
    72     /**
    73      * Creates a new route tracker.
    74      * The target and origin need to be specified at creation time.
    75      *
    76      * @param target    the host to which to route
    77      * @param local     the local address to route from, or
    78      *                  <code>null</code> for the default
    79      */
    80     public RouteTracker(HttpHost target, InetAddress local) {
    81         if (target == null) {
    82             throw new IllegalArgumentException("Target host may not be null.");
    83         }
    84         this.targetHost   = target;
    85         this.localAddress = local;
    86         this.tunnelled    = TunnelType.PLAIN;
    87         this.layered      = LayerType.PLAIN;
    88     }
    91     /**
    92      * Creates a new tracker for the given route.
    93      * Only target and origin are taken from the route,
    94      * everything else remains to be tracked.
    95      *
    96      * @param route     the route to track
    97      */
    98     public RouteTracker(HttpRoute route) {
    99         this(route.getTargetHost(), route.getLocalAddress());
   100     }
   102     /**
   103      * Tracks connecting to the target.
   104      *
   105      * @param secure    <code>true</code> if the route is secure,
   106      *                  <code>false</code> otherwise
   107      */
   108     public final void connectTarget(boolean secure) {
   109         if (this.connected) {
   110             throw new IllegalStateException("Already connected.");
   111         }
   112         this.connected = true;
   113         this.secure = secure;
   114     }
   116     /**
   117      * Tracks connecting to the first proxy.
   118      *
   119      * @param proxy     the proxy connected to
   120      * @param secure    <code>true</code> if the route is secure,
   121      *                  <code>false</code> otherwise
   122      */
   123     public final void connectProxy(HttpHost proxy, boolean secure) {
   124         if (proxy == null) {
   125             throw new IllegalArgumentException("Proxy host may not be null.");
   126         }
   127         if (this.connected) {
   128             throw new IllegalStateException("Already connected.");
   129         }
   130         this.connected  = true;
   131         this.proxyChain = new HttpHost[]{ proxy };
   132         this.secure     = secure;
   133     }
   135     /**
   136      * Tracks tunnelling to the target.
   137      *
   138      * @param secure    <code>true</code> if the route is secure,
   139      *                  <code>false</code> otherwise
   140      */
   141     public final void tunnelTarget(boolean secure) {
   142         if (!this.connected) {
   143             throw new IllegalStateException("No tunnel unless connected.");
   144         }
   145         if (this.proxyChain == null) {
   146             throw new IllegalStateException("No tunnel without proxy.");
   147         }
   148         this.tunnelled = TunnelType.TUNNELLED;
   149         this.secure    = secure;
   150     }
   152     /**
   153      * Tracks tunnelling to a proxy in a proxy chain.
   154      * This will extend the tracked proxy chain, but it does not mark
   155      * the route as tunnelled. Only end-to-end tunnels are considered there.
   156      *
   157      * @param proxy     the proxy tunnelled to
   158      * @param secure    <code>true</code> if the route is secure,
   159      *                  <code>false</code> otherwise
   160      */
   161     public final void tunnelProxy(HttpHost proxy, boolean secure) {
   162         if (proxy == null) {
   163             throw new IllegalArgumentException("Proxy host may not be null.");
   164         }
   165         if (!this.connected) {
   166             throw new IllegalStateException("No tunnel unless connected.");
   167         }
   168         if (this.proxyChain == null) {
   169             throw new IllegalStateException("No proxy tunnel without proxy.");
   170         }
   172         // prepare an extended proxy chain
   173         HttpHost[] proxies = new HttpHost[this.proxyChain.length+1];
   174         System.arraycopy(this.proxyChain, 0,
   175                          proxies, 0, this.proxyChain.length);
   176         proxies[proxies.length-1] = proxy;
   178         this.proxyChain = proxies;
   179         this.secure     = secure;
   180     }
   182     /**
   183      * Tracks layering a protocol.
   184      *
   185      * @param secure    <code>true</code> if the route is secure,
   186      *                  <code>false</code> otherwise
   187      */
   188     public final void layerProtocol(boolean secure) {
   189         // it is possible to layer a protocol over a direct connection,
   190         // although this case is probably not considered elsewhere
   191         if (!this.connected) {
   192             throw new IllegalStateException
   193                 ("No layered protocol unless connected.");
   194         }
   195         this.layered = LayerType.LAYERED;
   196         this.secure  = secure;
   197     }
   199     public final HttpHost getTargetHost() {
   200         return this.targetHost;
   201     }
   203     public final InetAddress getLocalAddress() {
   204         return this.localAddress;
   205     }
   207     public final int getHopCount() {
   208         int hops = 0;
   209         if (this.connected) {
   210             if (proxyChain == null)
   211                 hops = 1;
   212             else
   213                 hops = proxyChain.length + 1;
   214         }
   215         return hops;
   216     }
   218     public final HttpHost getHopTarget(int hop) {
   219         if (hop < 0)
   220             throw new IllegalArgumentException
   221                 ("Hop index must not be negative: " + hop);
   222         final int hopcount = getHopCount();
   223         if (hop >= hopcount) {
   224             throw new IllegalArgumentException
   225                 ("Hop index " + hop +
   226                  " exceeds tracked route length " + hopcount +".");
   227         }
   229         HttpHost result = null;
   230         if (hop < hopcount-1)
   231             result = this.proxyChain[hop];
   232         else
   233             result = this.targetHost;
   235         return result;
   236     }
   238     public final HttpHost getProxyHost() {
   239         return (this.proxyChain == null) ? null : this.proxyChain[0];
   240     }
   242     public final boolean isConnected() {
   243         return this.connected;
   244     }
   246     public final TunnelType getTunnelType() {
   247         return this.tunnelled;
   248     }
   250     public final boolean isTunnelled() {
   251         return (this.tunnelled == TunnelType.TUNNELLED);
   252     }
   254     public final LayerType getLayerType() {
   255         return this.layered;
   256     }
   258     public final boolean isLayered() {
   259         return (this.layered == LayerType.LAYERED);
   260     }
   262     public final boolean isSecure() {
   263         return this.secure;
   264     }
   266     /**
   267      * Obtains the tracked route.
   268      * If a route has been tracked, it is {@link #isConnected connected}.
   269      * If not connected, nothing has been tracked so far.
   270      *
   271      * @return  the tracked route, or
   272      *          <code>null</code> if nothing has been tracked so far
   273      */
   274     public final HttpRoute toRoute() {
   275         return !this.connected ?
   276             null : new HttpRoute(this.targetHost, this.localAddress,
   277                                  this.proxyChain, this.secure,
   278                                  this.tunnelled, this.layered);
   279     }
   281     /**
   282      * Compares this tracked route to another.
   283      *
   284      * @param o         the object to compare with
   285      *
   286      * @return  <code>true</code> if the argument is the same tracked route,
   287      *          <code>false</code>
   288      */
   289     @Override
   290     public final boolean equals(Object o) {
   291         if (o == this)
   292             return true;
   293         if (!(o instanceof RouteTracker))
   294             return false;
   296         RouteTracker that = (RouteTracker) o;
   297         return
   298             // Do the cheapest checks first
   299             (this.connected == that.connected) &&
   300             (this.secure    == that.secure) &&
   301             (this.tunnelled == that.tunnelled) &&
   302             (this.layered   == that.layered) &&
   303             LangUtils.equals(this.targetHost, that.targetHost) &&
   304             LangUtils.equals(this.localAddress, that.localAddress) &&
   305             LangUtils.equals(this.proxyChain, that.proxyChain);
   306     }
   308     /**
   309      * Generates a hash code for this tracked route.
   310      * Route trackers are modifiable and should therefore not be used
   311      * as lookup keys. Use {@link #toRoute toRoute} to obtain an
   312      * unmodifiable representation of the tracked route.
   313      *
   314      * @return  the hash code
   315      */
   316     @Override
   317     public final int hashCode() {
   318         int hash = LangUtils.HASH_SEED;
   319         hash = LangUtils.hashCode(hash, this.targetHost);
   320         hash = LangUtils.hashCode(hash, this.localAddress);
   321         if (this.proxyChain != null) {
   322             for (int i = 0; i < this.proxyChain.length; i++) {
   323                 hash = LangUtils.hashCode(hash, this.proxyChain[i]);
   324             }
   325         }
   326         hash = LangUtils.hashCode(hash, this.connected);
   327         hash = LangUtils.hashCode(hash, this.secure);
   328         hash = LangUtils.hashCode(hash, this.tunnelled);
   329         hash = LangUtils.hashCode(hash, this.layered);
   330         return hash;
   331     }
   333     /**
   334      * Obtains a description of the tracked route.
   335      *
   336      * @return  a human-readable representation of the tracked route
   337      */
   338     @Override
   339     public final String toString() {
   340         StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
   342         cab.append("RouteTracker[");
   343         if (this.localAddress != null) {
   344             cab.append(this.localAddress);
   345             cab.append("->");
   346         }
   347         cab.append('{');
   348         if (this.connected)
   349             cab.append('c');
   350         if (this.tunnelled == TunnelType.TUNNELLED)
   351             cab.append('t');
   352         if (this.layered == LayerType.LAYERED)
   353             cab.append('l');
   354         if (this.secure)
   355             cab.append('s');
   356         cab.append("}->");
   357         if (this.proxyChain != null) {
   358             for (int i=0; i<this.proxyChain.length; i++) {
   359                 cab.append(this.proxyChain[i]);
   360                 cab.append("->");
   361             }
   362         }
   363         cab.append(this.targetHost);
   364         cab.append(']');
   366         return cab.toString();
   367     }
   370     // default implementation of clone() is sufficient
   371     @Override
   372     public Object clone() throws CloneNotSupportedException {
   373         return super.clone();
   374     }
   376 }

mercurial