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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/conn/routing/HttpRoute.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,410 @@
     1.4 +/*
     1.5 + * ====================================================================
     1.6 + * Licensed to the Apache Software Foundation (ASF) under one
     1.7 + * or more contributor license agreements.  See the NOTICE file
     1.8 + * distributed with this work for additional information
     1.9 + * regarding copyright ownership.  The ASF licenses this file
    1.10 + * to you under the Apache License, Version 2.0 (the
    1.11 + * "License"); you may not use this file except in compliance
    1.12 + * with the License.  You may obtain a copy of the License at
    1.13 + *
    1.14 + *   http://www.apache.org/licenses/LICENSE-2.0
    1.15 + *
    1.16 + * Unless required by applicable law or agreed to in writing,
    1.17 + * software distributed under the License is distributed on an
    1.18 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    1.19 + * KIND, either express or implied.  See the License for the
    1.20 + * specific language governing permissions and limitations
    1.21 + * under the License.
    1.22 + * ====================================================================
    1.23 + *
    1.24 + * This software consists of voluntary contributions made by many
    1.25 + * individuals on behalf of the Apache Software Foundation.  For more
    1.26 + * information on the Apache Software Foundation, please see
    1.27 + * <http://www.apache.org/>.
    1.28 + *
    1.29 + */
    1.30 +
    1.31 +package ch.boye.httpclientandroidlib.conn.routing;
    1.32 +
    1.33 +import java.net.InetAddress;
    1.34 +
    1.35 +import ch.boye.httpclientandroidlib.annotation.Immutable;
    1.36 +import ch.boye.httpclientandroidlib.util.LangUtils;
    1.37 +
    1.38 +import ch.boye.httpclientandroidlib.HttpHost;
    1.39 +
    1.40 +/**
    1.41 + * The route for a request.
    1.42 + * Instances of this class are unmodifiable and therefore suitable
    1.43 + * for use as lookup keys.
    1.44 + *
    1.45 + * @since 4.0
    1.46 + */
    1.47 +@Immutable
    1.48 +public final class HttpRoute implements RouteInfo, Cloneable {
    1.49 +
    1.50 +    private static final HttpHost[] EMPTY_HTTP_HOST_ARRAY = new HttpHost[]{};
    1.51 +
    1.52 +    /** The target host to connect to. */
    1.53 +    private final HttpHost targetHost;
    1.54 +
    1.55 +    /**
    1.56 +     * The local address to connect from.
    1.57 +     * <code>null</code> indicates that the default should be used.
    1.58 +     */
    1.59 +    private final InetAddress localAddress;
    1.60 +
    1.61 +    /** The proxy servers, if any. Never null. */
    1.62 +    private final HttpHost[] proxyChain;
    1.63 +
    1.64 +    /** Whether the the route is tunnelled through the proxy. */
    1.65 +    private final TunnelType tunnelled;
    1.66 +
    1.67 +    /** Whether the route is layered. */
    1.68 +    private final LayerType layered;
    1.69 +
    1.70 +    /** Whether the route is (supposed to be) secure. */
    1.71 +    private final boolean secure;
    1.72 +
    1.73 +
    1.74 +    /**
    1.75 +     * Internal, fully-specified constructor.
    1.76 +     * This constructor does <i>not</i> clone the proxy chain array,
    1.77 +     * nor test it for <code>null</code> elements. This conversion and
    1.78 +     * check is the responsibility of the public constructors.
    1.79 +     * The order of arguments here is different from the similar public
    1.80 +     * constructor, as required by Java.
    1.81 +     *
    1.82 +     * @param local     the local address to route from, or
    1.83 +     *                  <code>null</code> for the default
    1.84 +     * @param target    the host to which to route
    1.85 +     * @param proxies   the proxy chain to use, or
    1.86 +     *                  <code>null</code> for a direct route
    1.87 +     * @param secure    <code>true</code> if the route is (to be) secure,
    1.88 +     *                  <code>false</code> otherwise
    1.89 +     * @param tunnelled the tunnel type of this route, or
    1.90 +     *                  <code>null</code> for PLAIN
    1.91 +     * @param layered   the layering type of this route, or
    1.92 +     *                  <code>null</code> for PLAIN
    1.93 +     */
    1.94 +    private HttpRoute(InetAddress local,
    1.95 +                      HttpHost target, HttpHost[] proxies,
    1.96 +                      boolean secure,
    1.97 +                      TunnelType tunnelled, LayerType layered) {
    1.98 +        if (target == null) {
    1.99 +            throw new IllegalArgumentException
   1.100 +                ("Target host may not be null.");
   1.101 +        }
   1.102 +        if (proxies == null) {
   1.103 +            throw new IllegalArgumentException
   1.104 +                ("Proxies may not be null.");
   1.105 +        }
   1.106 +        if ((tunnelled == TunnelType.TUNNELLED) && (proxies.length == 0)) {
   1.107 +            throw new IllegalArgumentException
   1.108 +                ("Proxy required if tunnelled.");
   1.109 +        }
   1.110 +
   1.111 +        // tunnelled is already checked above, that is in line with the default
   1.112 +        if (tunnelled == null)
   1.113 +            tunnelled = TunnelType.PLAIN;
   1.114 +        if (layered == null)
   1.115 +            layered = LayerType.PLAIN;
   1.116 +
   1.117 +        this.targetHost   = target;
   1.118 +        this.localAddress = local;
   1.119 +        this.proxyChain   = proxies;
   1.120 +        this.secure       = secure;
   1.121 +        this.tunnelled    = tunnelled;
   1.122 +        this.layered      = layered;
   1.123 +    }
   1.124 +
   1.125 +
   1.126 +    /**
   1.127 +     * Creates a new route with all attributes specified explicitly.
   1.128 +     *
   1.129 +     * @param target    the host to which to route
   1.130 +     * @param local     the local address to route from, or
   1.131 +     *                  <code>null</code> for the default
   1.132 +     * @param proxies   the proxy chain to use, or
   1.133 +     *                  <code>null</code> for a direct route
   1.134 +     * @param secure    <code>true</code> if the route is (to be) secure,
   1.135 +     *                  <code>false</code> otherwise
   1.136 +     * @param tunnelled the tunnel type of this route
   1.137 +     * @param layered   the layering type of this route
   1.138 +     */
   1.139 +    public HttpRoute(HttpHost target, InetAddress local, HttpHost[] proxies,
   1.140 +                     boolean secure, TunnelType tunnelled, LayerType layered) {
   1.141 +        this(local, target, toChain(proxies), secure, tunnelled, layered);
   1.142 +    }
   1.143 +
   1.144 +
   1.145 +    /**
   1.146 +     * Creates a new route with at most one proxy.
   1.147 +     *
   1.148 +     * @param target    the host to which to route
   1.149 +     * @param local     the local address to route from, or
   1.150 +     *                  <code>null</code> for the default
   1.151 +     * @param proxy     the proxy to use, or
   1.152 +     *                  <code>null</code> for a direct route
   1.153 +     * @param secure    <code>true</code> if the route is (to be) secure,
   1.154 +     *                  <code>false</code> otherwise
   1.155 +     * @param tunnelled <code>true</code> if the route is (to be) tunnelled
   1.156 +     *                  via the proxy,
   1.157 +     *                  <code>false</code> otherwise
   1.158 +     * @param layered   <code>true</code> if the route includes a
   1.159 +     *                  layered protocol,
   1.160 +     *                  <code>false</code> otherwise
   1.161 +     */
   1.162 +    public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy,
   1.163 +                     boolean secure, TunnelType tunnelled, LayerType layered) {
   1.164 +        this(local, target, toChain(proxy), secure, tunnelled, layered);
   1.165 +    }
   1.166 +
   1.167 +
   1.168 +    /**
   1.169 +     * Creates a new direct route.
   1.170 +     * That is a route without a proxy.
   1.171 +     *
   1.172 +     * @param target    the host to which to route
   1.173 +     * @param local     the local address to route from, or
   1.174 +     *                  <code>null</code> for the default
   1.175 +     * @param secure    <code>true</code> if the route is (to be) secure,
   1.176 +     *                  <code>false</code> otherwise
   1.177 +     */
   1.178 +    public HttpRoute(HttpHost target, InetAddress local, boolean secure) {
   1.179 +        this(local, target, EMPTY_HTTP_HOST_ARRAY, secure, TunnelType.PLAIN, LayerType.PLAIN);
   1.180 +    }
   1.181 +
   1.182 +
   1.183 +    /**
   1.184 +     * Creates a new direct insecure route.
   1.185 +     *
   1.186 +     * @param target    the host to which to route
   1.187 +     */
   1.188 +    public HttpRoute(HttpHost target) {
   1.189 +        this(null, target, EMPTY_HTTP_HOST_ARRAY, false, TunnelType.PLAIN, LayerType.PLAIN);
   1.190 +    }
   1.191 +
   1.192 +
   1.193 +    /**
   1.194 +     * Creates a new route through a proxy.
   1.195 +     * When using this constructor, the <code>proxy</code> MUST be given.
   1.196 +     * For convenience, it is assumed that a secure connection will be
   1.197 +     * layered over a tunnel through the proxy.
   1.198 +     *
   1.199 +     * @param target    the host to which to route
   1.200 +     * @param local     the local address to route from, or
   1.201 +     *                  <code>null</code> for the default
   1.202 +     * @param proxy     the proxy to use
   1.203 +     * @param secure    <code>true</code> if the route is (to be) secure,
   1.204 +     *                  <code>false</code> otherwise
   1.205 +     */
   1.206 +    public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy,
   1.207 +                     boolean secure) {
   1.208 +        this(local, target, toChain(proxy), secure,
   1.209 +             secure ? TunnelType.TUNNELLED : TunnelType.PLAIN,
   1.210 +             secure ? LayerType.LAYERED    : LayerType.PLAIN);
   1.211 +        if (proxy == null) {
   1.212 +            throw new IllegalArgumentException
   1.213 +                ("Proxy host may not be null.");
   1.214 +        }
   1.215 +    }
   1.216 +
   1.217 +
   1.218 +    /**
   1.219 +     * Helper to convert a proxy to a proxy chain.
   1.220 +     *
   1.221 +     * @param proxy     the only proxy in the chain, or <code>null</code>
   1.222 +     *
   1.223 +     * @return  a proxy chain array, may be empty (never null)
   1.224 +     */
   1.225 +    private static HttpHost[] toChain(HttpHost proxy) {
   1.226 +        if (proxy == null)
   1.227 +            return EMPTY_HTTP_HOST_ARRAY;
   1.228 +
   1.229 +        return new HttpHost[]{ proxy };
   1.230 +    }
   1.231 +
   1.232 +
   1.233 +    /**
   1.234 +     * Helper to duplicate and check a proxy chain.
   1.235 +     * <code>null</code> is converted to an empty proxy chain.
   1.236 +     *
   1.237 +     * @param proxies   the proxy chain to duplicate, or <code>null</code>
   1.238 +     *
   1.239 +     * @return  a new proxy chain array, may be empty (never null)
   1.240 +     */
   1.241 +    private static HttpHost[] toChain(HttpHost[] proxies) {
   1.242 +        if ((proxies == null) || (proxies.length < 1))
   1.243 +            return EMPTY_HTTP_HOST_ARRAY;
   1.244 +
   1.245 +        for (HttpHost proxy : proxies) {
   1.246 +            if (proxy == null)
   1.247 +                throw new IllegalArgumentException
   1.248 +                        ("Proxy chain may not contain null elements.");
   1.249 +        }
   1.250 +
   1.251 +        // copy the proxy chain, the traditional way
   1.252 +        HttpHost[] result = new HttpHost[proxies.length];
   1.253 +        System.arraycopy(proxies, 0, result, 0, proxies.length);
   1.254 +
   1.255 +        return result;
   1.256 +    }
   1.257 +
   1.258 +
   1.259 +
   1.260 +    // non-JavaDoc, see interface RouteInfo
   1.261 +    public final HttpHost getTargetHost() {
   1.262 +        return this.targetHost;
   1.263 +    }
   1.264 +
   1.265 +
   1.266 +    // non-JavaDoc, see interface RouteInfo
   1.267 +    public final InetAddress getLocalAddress() {
   1.268 +        return this.localAddress;
   1.269 +    }
   1.270 +
   1.271 +
   1.272 +    public final int getHopCount() {
   1.273 +        return proxyChain.length+1;
   1.274 +    }
   1.275 +
   1.276 +
   1.277 +    public final HttpHost getHopTarget(int hop) {
   1.278 +        if (hop < 0)
   1.279 +            throw new IllegalArgumentException
   1.280 +                ("Hop index must not be negative: " + hop);
   1.281 +        final int hopcount = getHopCount();
   1.282 +        if (hop >= hopcount)
   1.283 +            throw new IllegalArgumentException
   1.284 +                ("Hop index " + hop +
   1.285 +                 " exceeds route length " + hopcount);
   1.286 +
   1.287 +        HttpHost result = null;
   1.288 +        if (hop < hopcount-1)
   1.289 +            result = this.proxyChain[hop];
   1.290 +        else
   1.291 +            result = this.targetHost;
   1.292 +
   1.293 +        return result;
   1.294 +    }
   1.295 +
   1.296 +
   1.297 +    public final HttpHost getProxyHost() {
   1.298 +        return (this.proxyChain.length == 0) ? null : this.proxyChain[0];
   1.299 +    }
   1.300 +
   1.301 +
   1.302 +    public final TunnelType getTunnelType() {
   1.303 +        return this.tunnelled;
   1.304 +    }
   1.305 +
   1.306 +
   1.307 +    public final boolean isTunnelled() {
   1.308 +        return (this.tunnelled == TunnelType.TUNNELLED);
   1.309 +    }
   1.310 +
   1.311 +
   1.312 +    public final LayerType getLayerType() {
   1.313 +        return this.layered;
   1.314 +    }
   1.315 +
   1.316 +
   1.317 +    public final boolean isLayered() {
   1.318 +        return (this.layered == LayerType.LAYERED);
   1.319 +    }
   1.320 +
   1.321 +
   1.322 +    public final boolean isSecure() {
   1.323 +        return this.secure;
   1.324 +    }
   1.325 +
   1.326 +
   1.327 +    /**
   1.328 +     * Compares this route to another.
   1.329 +     *
   1.330 +     * @param obj         the object to compare with
   1.331 +     *
   1.332 +     * @return  <code>true</code> if the argument is the same route,
   1.333 +     *          <code>false</code>
   1.334 +     */
   1.335 +    @Override
   1.336 +    public final boolean equals(Object obj) {
   1.337 +        if (this == obj) return true;
   1.338 +        if (obj instanceof HttpRoute) {
   1.339 +            HttpRoute that = (HttpRoute) obj;
   1.340 +            return 
   1.341 +                // Do the cheapest tests first
   1.342 +                (this.secure    == that.secure) &&
   1.343 +                (this.tunnelled == that.tunnelled) &&
   1.344 +                (this.layered   == that.layered) &&
   1.345 +                LangUtils.equals(this.targetHost, that.targetHost) &&
   1.346 +                LangUtils.equals(this.localAddress, that.localAddress) &&
   1.347 +                LangUtils.equals(this.proxyChain, that.proxyChain);
   1.348 +        } else {
   1.349 +            return false;
   1.350 +        }
   1.351 +    }
   1.352 +
   1.353 +
   1.354 +    /**
   1.355 +     * Generates a hash code for this route.
   1.356 +     *
   1.357 +     * @return  the hash code
   1.358 +     */
   1.359 +    @Override
   1.360 +    public final int hashCode() {
   1.361 +        int hash = LangUtils.HASH_SEED;
   1.362 +        hash = LangUtils.hashCode(hash, this.targetHost);
   1.363 +        hash = LangUtils.hashCode(hash, this.localAddress);
   1.364 +        for (int i = 0; i < this.proxyChain.length; i++) {
   1.365 +            hash = LangUtils.hashCode(hash, this.proxyChain[i]);
   1.366 +        }
   1.367 +        hash = LangUtils.hashCode(hash, this.secure);
   1.368 +        hash = LangUtils.hashCode(hash, this.tunnelled);
   1.369 +        hash = LangUtils.hashCode(hash, this.layered);
   1.370 +        return hash;
   1.371 +    }
   1.372 +
   1.373 +
   1.374 +    /**
   1.375 +     * Obtains a description of this route.
   1.376 +     *
   1.377 +     * @return  a human-readable representation of this route
   1.378 +     */
   1.379 +    @Override
   1.380 +    public final String toString() {
   1.381 +        StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
   1.382 +
   1.383 +        cab.append("HttpRoute[");
   1.384 +        if (this.localAddress != null) {
   1.385 +            cab.append(this.localAddress);
   1.386 +            cab.append("->");
   1.387 +        }
   1.388 +        cab.append('{');
   1.389 +        if (this.tunnelled == TunnelType.TUNNELLED)
   1.390 +            cab.append('t');
   1.391 +        if (this.layered == LayerType.LAYERED)
   1.392 +            cab.append('l');
   1.393 +        if (this.secure)
   1.394 +            cab.append('s');
   1.395 +        cab.append("}->");
   1.396 +        for (HttpHost aProxyChain : this.proxyChain) {
   1.397 +            cab.append(aProxyChain);
   1.398 +            cab.append("->");
   1.399 +        }
   1.400 +        cab.append(this.targetHost);
   1.401 +        cab.append(']');
   1.402 +
   1.403 +        return cab.toString();
   1.404 +    }
   1.405 +
   1.406 +
   1.407 +    // default implementation of clone() is sufficient
   1.408 +    @Override
   1.409 +    public Object clone() throws CloneNotSupportedException {
   1.410 +        return super.clone();
   1.411 +    }
   1.412 +
   1.413 +}

mercurial