mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/conn/DefaultClientConnectionOperator.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.impl.conn;
    30 import java.io.IOException;
    31 import java.net.ConnectException;
    32 import java.net.InetSocketAddress;
    33 import java.net.Socket;
    34 import java.net.InetAddress;
    35 import java.net.UnknownHostException;
    37 import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
    38 /* LogFactory removed by HttpClient for Android script. */
    39 import ch.boye.httpclientandroidlib.annotation.ThreadSafe;
    41 import ch.boye.httpclientandroidlib.HttpHost;
    42 import ch.boye.httpclientandroidlib.params.HttpParams;
    43 import ch.boye.httpclientandroidlib.params.HttpConnectionParams;
    44 import ch.boye.httpclientandroidlib.protocol.HttpContext;
    46 import ch.boye.httpclientandroidlib.conn.ConnectTimeoutException;
    47 import ch.boye.httpclientandroidlib.conn.HttpHostConnectException;
    48 import ch.boye.httpclientandroidlib.conn.OperatedClientConnection;
    49 import ch.boye.httpclientandroidlib.conn.ClientConnectionOperator;
    50 import ch.boye.httpclientandroidlib.conn.scheme.LayeredSchemeSocketFactory;
    51 import ch.boye.httpclientandroidlib.conn.scheme.Scheme;
    52 import ch.boye.httpclientandroidlib.conn.scheme.SchemeRegistry;
    53 import ch.boye.httpclientandroidlib.conn.scheme.SchemeSocketFactory;
    55 /**
    56  * Default implementation of a {@link ClientConnectionOperator}. It uses a {@link SchemeRegistry}
    57  * to look up {@link SchemeSocketFactory} objects.
    58  * <p>
    59  * This connection operator is multihome network aware and will attempt to retry failed connects
    60  * against all known IP addresses sequentially until the connect is successful or all known
    61  * addresses fail to respond. Please note the same
    62  * {@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#CONNECTION_TIMEOUT} value will be used
    63  * for each connection attempt, so in the worst case the total elapsed time before timeout
    64  * can be <code>CONNECTION_TIMEOUT * n</code> where <code>n</code> is the number of IP addresses
    65  * of the given host. One can disable multihome support by overriding
    66  * the {@link #resolveHostname(String)} method and returning only one IP address for the given
    67  * host name.
    68  * <p>
    69  * The following parameters can be used to customize the behavior of this
    70  * class:
    71  * <ul>
    72  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreProtocolPNames#HTTP_ELEMENT_CHARSET}</li>
    73  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SO_TIMEOUT}</li>
    74  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SO_LINGER}</li>
    75  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SO_REUSEADDR}</li>
    76  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#TCP_NODELAY}</li>
    77  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SOCKET_BUFFER_SIZE}</li>
    78  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#CONNECTION_TIMEOUT}</li>
    79  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_LINE_LENGTH}</li>
    80  * </ul>
    81  *
    82  * @since 4.0
    83  */
    84 @ThreadSafe
    85 public class DefaultClientConnectionOperator implements ClientConnectionOperator {
    87     public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
    89     /** The scheme registry for looking up socket factories. */
    90     protected final SchemeRegistry schemeRegistry; // @ThreadSafe
    92     /**
    93      * Creates a new client connection operator for the given scheme registry.
    94      *
    95      * @param schemes   the scheme registry
    96      */
    97     public DefaultClientConnectionOperator(final SchemeRegistry schemes) {
    98         if (schemes == null) {
    99             throw new IllegalArgumentException("Scheme registry amy not be null");
   100         }
   101         this.schemeRegistry = schemes;
   102     }
   104     public OperatedClientConnection createConnection() {
   105         return new DefaultClientConnection();
   106     }
   108     public void openConnection(
   109             final OperatedClientConnection conn,
   110             final HttpHost target,
   111             final InetAddress local,
   112             final HttpContext context,
   113             final HttpParams params) throws IOException {
   114         if (conn == null) {
   115             throw new IllegalArgumentException("Connection may not be null");
   116         }
   117         if (target == null) {
   118             throw new IllegalArgumentException("Target host may not be null");
   119         }
   120         if (params == null) {
   121             throw new IllegalArgumentException("Parameters may not be null");
   122         }
   123         if (conn.isOpen()) {
   124             throw new IllegalStateException("Connection must not be open");
   125         }
   127         Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
   128         SchemeSocketFactory sf = schm.getSchemeSocketFactory();
   130         InetAddress[] addresses = resolveHostname(target.getHostName());
   131         int port = schm.resolvePort(target.getPort());
   132         for (int i = 0; i < addresses.length; i++) {
   133             InetAddress address = addresses[i];
   134             boolean last = i == addresses.length - 1;
   136             Socket sock = sf.createSocket(params);
   137             conn.opening(sock, target);
   139             InetSocketAddress remoteAddress = new HttpInetSocketAddress(target, address, port);
   140             InetSocketAddress localAddress = null;
   141             if (local != null) {
   142                 localAddress = new InetSocketAddress(local, 0);
   143             }
   144             if (this.log.isDebugEnabled()) {
   145                 this.log.debug("Connecting to " + remoteAddress);
   146             }
   147             try {
   148                 Socket connsock = sf.connectSocket(sock, remoteAddress, localAddress, params);
   149                 if (sock != connsock) {
   150                     sock = connsock;
   151                     conn.opening(sock, target);
   152                 }
   153                 prepareSocket(sock, context, params);
   154                 conn.openCompleted(sf.isSecure(sock), params);
   155                 return;
   156             } catch (ConnectException ex) {
   157                 if (last) {
   158                     throw new HttpHostConnectException(target, ex);
   159                 }
   160             } catch (ConnectTimeoutException ex) {
   161                 if (last) {
   162                     throw ex;
   163                 }
   164             }
   165             if (this.log.isDebugEnabled()) {
   166                 this.log.debug("Connect to " + remoteAddress + " timed out. " +
   167                         "Connection will be retried using another IP address");
   168             }
   169         }
   170     }
   172     public void updateSecureConnection(
   173             final OperatedClientConnection conn,
   174             final HttpHost target,
   175             final HttpContext context,
   176             final HttpParams params) throws IOException {
   177         if (conn == null) {
   178             throw new IllegalArgumentException("Connection may not be null");
   179         }
   180         if (target == null) {
   181             throw new IllegalArgumentException("Target host may not be null");
   182         }
   183         if (params == null) {
   184             throw new IllegalArgumentException("Parameters may not be null");
   185         }
   186         if (!conn.isOpen()) {
   187             throw new IllegalStateException("Connection must be open");
   188         }
   190         final Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
   191         if (!(schm.getSchemeSocketFactory() instanceof LayeredSchemeSocketFactory)) {
   192             throw new IllegalArgumentException
   193                 ("Target scheme (" + schm.getName() +
   194                  ") must have layered socket factory.");
   195         }
   197         LayeredSchemeSocketFactory lsf = (LayeredSchemeSocketFactory) schm.getSchemeSocketFactory();
   198         Socket sock;
   199         try {
   200             sock = lsf.createLayeredSocket(
   201                     conn.getSocket(), target.getHostName(), target.getPort(), true);
   202         } catch (ConnectException ex) {
   203             throw new HttpHostConnectException(target, ex);
   204         }
   205         prepareSocket(sock, context, params);
   206         conn.update(sock, target, lsf.isSecure(sock), params);
   207     }
   209     /**
   210      * Performs standard initializations on a newly created socket.
   211      *
   212      * @param sock      the socket to prepare
   213      * @param context   the context for the connection
   214      * @param params    the parameters from which to prepare the socket
   215      *
   216      * @throws IOException      in case of an IO problem
   217      */
   218     protected void prepareSocket(
   219             final Socket sock,
   220             final HttpContext context,
   221             final HttpParams params) throws IOException {
   222         sock.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params));
   223         sock.setSoTimeout(HttpConnectionParams.getSoTimeout(params));
   225         int linger = HttpConnectionParams.getLinger(params);
   226         if (linger >= 0) {
   227             sock.setSoLinger(linger > 0, linger);
   228         }
   229     }
   231     /**
   232      * Resolves the given host name to an array of corresponding IP addresses, based on the
   233      * configured name service on the system.
   234      *
   235      * @param host host name to resolve
   236      * @return array of IP addresses
   237      * @exception  UnknownHostException  if no IP address for the host could be determined.
   238      *
   239      * @since 4.1
   240      */
   241     protected InetAddress[] resolveHostname(final String host) throws UnknownHostException {
   242         return InetAddress.getAllByName(host);
   243     }
   245 }

mercurial