1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/conn/DefaultClientConnectionOperator.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,246 @@ 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.impl.conn; 1.32 + 1.33 +import java.io.IOException; 1.34 +import java.net.ConnectException; 1.35 +import java.net.InetSocketAddress; 1.36 +import java.net.Socket; 1.37 +import java.net.InetAddress; 1.38 +import java.net.UnknownHostException; 1.39 + 1.40 +import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog; 1.41 +/* LogFactory removed by HttpClient for Android script. */ 1.42 +import ch.boye.httpclientandroidlib.annotation.ThreadSafe; 1.43 + 1.44 +import ch.boye.httpclientandroidlib.HttpHost; 1.45 +import ch.boye.httpclientandroidlib.params.HttpParams; 1.46 +import ch.boye.httpclientandroidlib.params.HttpConnectionParams; 1.47 +import ch.boye.httpclientandroidlib.protocol.HttpContext; 1.48 + 1.49 +import ch.boye.httpclientandroidlib.conn.ConnectTimeoutException; 1.50 +import ch.boye.httpclientandroidlib.conn.HttpHostConnectException; 1.51 +import ch.boye.httpclientandroidlib.conn.OperatedClientConnection; 1.52 +import ch.boye.httpclientandroidlib.conn.ClientConnectionOperator; 1.53 +import ch.boye.httpclientandroidlib.conn.scheme.LayeredSchemeSocketFactory; 1.54 +import ch.boye.httpclientandroidlib.conn.scheme.Scheme; 1.55 +import ch.boye.httpclientandroidlib.conn.scheme.SchemeRegistry; 1.56 +import ch.boye.httpclientandroidlib.conn.scheme.SchemeSocketFactory; 1.57 + 1.58 +/** 1.59 + * Default implementation of a {@link ClientConnectionOperator}. It uses a {@link SchemeRegistry} 1.60 + * to look up {@link SchemeSocketFactory} objects. 1.61 + * <p> 1.62 + * This connection operator is multihome network aware and will attempt to retry failed connects 1.63 + * against all known IP addresses sequentially until the connect is successful or all known 1.64 + * addresses fail to respond. Please note the same 1.65 + * {@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#CONNECTION_TIMEOUT} value will be used 1.66 + * for each connection attempt, so in the worst case the total elapsed time before timeout 1.67 + * can be <code>CONNECTION_TIMEOUT * n</code> where <code>n</code> is the number of IP addresses 1.68 + * of the given host. One can disable multihome support by overriding 1.69 + * the {@link #resolveHostname(String)} method and returning only one IP address for the given 1.70 + * host name. 1.71 + * <p> 1.72 + * The following parameters can be used to customize the behavior of this 1.73 + * class: 1.74 + * <ul> 1.75 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreProtocolPNames#HTTP_ELEMENT_CHARSET}</li> 1.76 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SO_TIMEOUT}</li> 1.77 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SO_LINGER}</li> 1.78 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SO_REUSEADDR}</li> 1.79 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#TCP_NODELAY}</li> 1.80 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SOCKET_BUFFER_SIZE}</li> 1.81 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#CONNECTION_TIMEOUT}</li> 1.82 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_LINE_LENGTH}</li> 1.83 + * </ul> 1.84 + * 1.85 + * @since 4.0 1.86 + */ 1.87 +@ThreadSafe 1.88 +public class DefaultClientConnectionOperator implements ClientConnectionOperator { 1.89 + 1.90 + public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass()); 1.91 + 1.92 + /** The scheme registry for looking up socket factories. */ 1.93 + protected final SchemeRegistry schemeRegistry; // @ThreadSafe 1.94 + 1.95 + /** 1.96 + * Creates a new client connection operator for the given scheme registry. 1.97 + * 1.98 + * @param schemes the scheme registry 1.99 + */ 1.100 + public DefaultClientConnectionOperator(final SchemeRegistry schemes) { 1.101 + if (schemes == null) { 1.102 + throw new IllegalArgumentException("Scheme registry amy not be null"); 1.103 + } 1.104 + this.schemeRegistry = schemes; 1.105 + } 1.106 + 1.107 + public OperatedClientConnection createConnection() { 1.108 + return new DefaultClientConnection(); 1.109 + } 1.110 + 1.111 + public void openConnection( 1.112 + final OperatedClientConnection conn, 1.113 + final HttpHost target, 1.114 + final InetAddress local, 1.115 + final HttpContext context, 1.116 + final HttpParams params) throws IOException { 1.117 + if (conn == null) { 1.118 + throw new IllegalArgumentException("Connection may not be null"); 1.119 + } 1.120 + if (target == null) { 1.121 + throw new IllegalArgumentException("Target host may not be null"); 1.122 + } 1.123 + if (params == null) { 1.124 + throw new IllegalArgumentException("Parameters may not be null"); 1.125 + } 1.126 + if (conn.isOpen()) { 1.127 + throw new IllegalStateException("Connection must not be open"); 1.128 + } 1.129 + 1.130 + Scheme schm = schemeRegistry.getScheme(target.getSchemeName()); 1.131 + SchemeSocketFactory sf = schm.getSchemeSocketFactory(); 1.132 + 1.133 + InetAddress[] addresses = resolveHostname(target.getHostName()); 1.134 + int port = schm.resolvePort(target.getPort()); 1.135 + for (int i = 0; i < addresses.length; i++) { 1.136 + InetAddress address = addresses[i]; 1.137 + boolean last = i == addresses.length - 1; 1.138 + 1.139 + Socket sock = sf.createSocket(params); 1.140 + conn.opening(sock, target); 1.141 + 1.142 + InetSocketAddress remoteAddress = new HttpInetSocketAddress(target, address, port); 1.143 + InetSocketAddress localAddress = null; 1.144 + if (local != null) { 1.145 + localAddress = new InetSocketAddress(local, 0); 1.146 + } 1.147 + if (this.log.isDebugEnabled()) { 1.148 + this.log.debug("Connecting to " + remoteAddress); 1.149 + } 1.150 + try { 1.151 + Socket connsock = sf.connectSocket(sock, remoteAddress, localAddress, params); 1.152 + if (sock != connsock) { 1.153 + sock = connsock; 1.154 + conn.opening(sock, target); 1.155 + } 1.156 + prepareSocket(sock, context, params); 1.157 + conn.openCompleted(sf.isSecure(sock), params); 1.158 + return; 1.159 + } catch (ConnectException ex) { 1.160 + if (last) { 1.161 + throw new HttpHostConnectException(target, ex); 1.162 + } 1.163 + } catch (ConnectTimeoutException ex) { 1.164 + if (last) { 1.165 + throw ex; 1.166 + } 1.167 + } 1.168 + if (this.log.isDebugEnabled()) { 1.169 + this.log.debug("Connect to " + remoteAddress + " timed out. " + 1.170 + "Connection will be retried using another IP address"); 1.171 + } 1.172 + } 1.173 + } 1.174 + 1.175 + public void updateSecureConnection( 1.176 + final OperatedClientConnection conn, 1.177 + final HttpHost target, 1.178 + final HttpContext context, 1.179 + final HttpParams params) throws IOException { 1.180 + if (conn == null) { 1.181 + throw new IllegalArgumentException("Connection may not be null"); 1.182 + } 1.183 + if (target == null) { 1.184 + throw new IllegalArgumentException("Target host may not be null"); 1.185 + } 1.186 + if (params == null) { 1.187 + throw new IllegalArgumentException("Parameters may not be null"); 1.188 + } 1.189 + if (!conn.isOpen()) { 1.190 + throw new IllegalStateException("Connection must be open"); 1.191 + } 1.192 + 1.193 + final Scheme schm = schemeRegistry.getScheme(target.getSchemeName()); 1.194 + if (!(schm.getSchemeSocketFactory() instanceof LayeredSchemeSocketFactory)) { 1.195 + throw new IllegalArgumentException 1.196 + ("Target scheme (" + schm.getName() + 1.197 + ") must have layered socket factory."); 1.198 + } 1.199 + 1.200 + LayeredSchemeSocketFactory lsf = (LayeredSchemeSocketFactory) schm.getSchemeSocketFactory(); 1.201 + Socket sock; 1.202 + try { 1.203 + sock = lsf.createLayeredSocket( 1.204 + conn.getSocket(), target.getHostName(), target.getPort(), true); 1.205 + } catch (ConnectException ex) { 1.206 + throw new HttpHostConnectException(target, ex); 1.207 + } 1.208 + prepareSocket(sock, context, params); 1.209 + conn.update(sock, target, lsf.isSecure(sock), params); 1.210 + } 1.211 + 1.212 + /** 1.213 + * Performs standard initializations on a newly created socket. 1.214 + * 1.215 + * @param sock the socket to prepare 1.216 + * @param context the context for the connection 1.217 + * @param params the parameters from which to prepare the socket 1.218 + * 1.219 + * @throws IOException in case of an IO problem 1.220 + */ 1.221 + protected void prepareSocket( 1.222 + final Socket sock, 1.223 + final HttpContext context, 1.224 + final HttpParams params) throws IOException { 1.225 + sock.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params)); 1.226 + sock.setSoTimeout(HttpConnectionParams.getSoTimeout(params)); 1.227 + 1.228 + int linger = HttpConnectionParams.getLinger(params); 1.229 + if (linger >= 0) { 1.230 + sock.setSoLinger(linger > 0, linger); 1.231 + } 1.232 + } 1.233 + 1.234 + /** 1.235 + * Resolves the given host name to an array of corresponding IP addresses, based on the 1.236 + * configured name service on the system. 1.237 + * 1.238 + * @param host host name to resolve 1.239 + * @return array of IP addresses 1.240 + * @exception UnknownHostException if no IP address for the host could be determined. 1.241 + * 1.242 + * @since 4.1 1.243 + */ 1.244 + protected InetAddress[] resolveHostname(final String host) throws UnknownHostException { 1.245 + return InetAddress.getAllByName(host); 1.246 + } 1.247 + 1.248 +} 1.249 +