1 /*
2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/DefaultClientConnectionOperator.java $
3  * $Revision: 652193 $
4  * $Date: 2008-04-29 17:10:36 -0700 (Tue, 29 Apr 2008) $
5  *
6  * ====================================================================
7  * Licensed to the Apache Software Foundation (ASF) under one
8  * or more contributor license agreements.  See the NOTICE file
9  * distributed with this work for additional information
10  * regarding copyright ownership.  The ASF licenses this file
11  * to you under the Apache License, Version 2.0 (the
12  * "License"); you may not use this file except in compliance
13  * with the License.  You may obtain a copy of the License at
14  *
15  *   http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing,
18  * software distributed under the License is distributed on an
19  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20  * KIND, either express or implied.  See the License for the
21  * specific language governing permissions and limitations
22  * under the License.
23  * ====================================================================
24  *
25  * This software consists of voluntary contributions made by many
26  * individuals on behalf of the Apache Software Foundation.  For more
27  * information on the Apache Software Foundation, please see
28  * <http://www.apache.org/>.
29  *
30  */
31 
32 package org.apache.http.impl.conn;
33 
34 import java.io.IOException;
35 import java.net.ConnectException;
36 import java.net.Socket;
37 import java.net.InetAddress;
38 
39 import java.net.SocketException;
40 import org.apache.http.HttpHost;
41 import org.apache.http.params.HttpParams;
42 import org.apache.http.params.HttpConnectionParams;
43 import org.apache.http.protocol.HttpContext;
44 
45 import org.apache.http.conn.HttpHostConnectException;
46 import org.apache.http.conn.OperatedClientConnection;
47 import org.apache.http.conn.ClientConnectionOperator;
48 import org.apache.http.conn.ConnectTimeoutException;
49 import org.apache.http.conn.scheme.LayeredSocketFactory;
50 import org.apache.http.conn.scheme.PlainSocketFactory;
51 import org.apache.http.conn.scheme.Scheme;
52 import org.apache.http.conn.scheme.SchemeRegistry;
53 import org.apache.http.conn.scheme.SocketFactory;
54 
55 
56 /**
57  * Default implementation of a
58  * {@link ClientConnectionOperator ClientConnectionOperator}.
59  * It uses a {@link SchemeRegistry SchemeRegistry} to look up
60  * {@link SocketFactory SocketFactory} objects.
61  *
62  * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
63  *
64  *
65  * <!-- empty lines to avoid svn diff problems -->
66  * @version   $Revision: 652193 $ $Date: 2008-04-29 17:10:36 -0700 (Tue, 29 Apr 2008) $
67  *
68  * @since 4.0
69  *
70  * @deprecated Please use {@link java.net.URL#openConnection} instead.
71  *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
72  *     for further details.
73  */
74 @Deprecated
75 public class DefaultClientConnectionOperator
76     implements ClientConnectionOperator {
77 
78     private static final PlainSocketFactory staticPlainSocketFactory = new PlainSocketFactory();
79 
80     /** The scheme registry for looking up socket factories. */
81     protected SchemeRegistry schemeRegistry;
82 
83 
84     /**
85      * Creates a new client connection operator for the given scheme registry.
86      *
87      * @param schemes   the scheme registry
88      */
DefaultClientConnectionOperator(SchemeRegistry schemes)89     public DefaultClientConnectionOperator(SchemeRegistry schemes) {
90         if (schemes == null) {
91             throw new IllegalArgumentException
92                 ("Scheme registry must not be null.");
93         }
94         schemeRegistry = schemes;
95     }
96 
97 
98     // non-javadoc, see interface ClientConnectionOperator
createConnection()99     public OperatedClientConnection createConnection() {
100         return new DefaultClientConnection();
101     }
102 
103 
104     // non-javadoc, see interface ClientConnectionOperator
openConnection(OperatedClientConnection conn, HttpHost target, InetAddress local, HttpContext context, HttpParams params)105     public void openConnection(OperatedClientConnection conn,
106                                HttpHost target,
107                                InetAddress local,
108                                HttpContext context,
109                                HttpParams params)
110         throws IOException {
111 
112         if (conn == null) {
113             throw new IllegalArgumentException
114                 ("Connection must not be null.");
115         }
116         if (target == null) {
117             throw new IllegalArgumentException
118                 ("Target host must not be null.");
119         }
120         // local address may be null
121         //@@@ is context allowed to be null?
122         if (params == null) {
123             throw new IllegalArgumentException
124                 ("Parameters must not be null.");
125         }
126         if (conn.isOpen()) {
127             throw new IllegalArgumentException
128                 ("Connection must not be open.");
129         }
130 
131         final Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
132         final SocketFactory sf = schm.getSocketFactory();
133         final SocketFactory plain_sf;
134         final LayeredSocketFactory layered_sf;
135         if (sf instanceof LayeredSocketFactory) {
136             plain_sf = staticPlainSocketFactory;
137             layered_sf = (LayeredSocketFactory)sf;
138         } else {
139             plain_sf = sf;
140             layered_sf = null;
141         }
142         InetAddress[] addresses = InetAddress.getAllByName(target.getHostName());
143 
144         for (int i = 0; i < addresses.length; ++i) {
145             Socket sock = plain_sf.createSocket();
146             conn.opening(sock, target);
147 
148             try {
149                 Socket connsock = plain_sf.connectSocket(sock,
150                     addresses[i].getHostAddress(),
151                     schm.resolvePort(target.getPort()),
152                     local, 0, params);
153                 if (sock != connsock) {
154                     sock = connsock;
155                     conn.opening(sock, target);
156                 }
157                 /*
158                  * prepareSocket is called on the just connected
159                  * socket before the creation of the layered socket to
160                  * ensure that desired socket options such as
161                  * TCP_NODELAY, SO_RCVTIMEO, SO_LINGER will be set
162                  * before any I/O is performed on the socket. This
163                  * happens in the common case as
164                  * SSLSocketFactory.createSocket performs hostname
165                  * verification which requires that SSL handshaking be
166                  * performed.
167                  */
168                 prepareSocket(sock, context, params);
169                 if (layered_sf != null) {
170                     Socket layeredsock = layered_sf.createSocket(sock,
171                         target.getHostName(),
172                         schm.resolvePort(target.getPort()),
173                         true);
174                     if (layeredsock != sock) {
175                         conn.opening(layeredsock, target);
176                     }
177                     conn.openCompleted(sf.isSecure(layeredsock), params);
178                 } else {
179                     conn.openCompleted(sf.isSecure(sock), params);
180                 }
181                 break;
182             // BEGIN android-changed
183             //       catch SocketException to cover any kind of connect failure
184             } catch (SocketException ex) {
185                 if (i == addresses.length - 1) {
186                     final ConnectException cause;
187                     if (ex instanceof ConnectException) {
188                         cause = (ConnectException) ex;
189                     } else {
190                         cause = new ConnectException(ex.getMessage());
191                         cause.initCause(ex);
192                     }
193                     throw new HttpHostConnectException(target, cause);
194                 }
195             // END android-changed
196             } catch (ConnectTimeoutException ex) {
197                 if (i == addresses.length - 1) {
198                     throw ex;
199                 }
200             }
201         }
202     } // openConnection
203 
204 
205     // non-javadoc, see interface ClientConnectionOperator
updateSecureConnection(OperatedClientConnection conn, HttpHost target, HttpContext context, HttpParams params)206     public void updateSecureConnection(OperatedClientConnection conn,
207                                        HttpHost target,
208                                        HttpContext context,
209                                        HttpParams params)
210         throws IOException {
211 
212 
213         if (conn == null) {
214             throw new IllegalArgumentException
215                 ("Connection must not be null.");
216         }
217         if (target == null) {
218             throw new IllegalArgumentException
219                 ("Target host must not be null.");
220         }
221         //@@@ is context allowed to be null?
222         if (params == null) {
223             throw new IllegalArgumentException
224                 ("Parameters must not be null.");
225         }
226         if (!conn.isOpen()) {
227             throw new IllegalArgumentException
228                 ("Connection must be open.");
229         }
230 
231         final Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
232         if (!(schm.getSocketFactory() instanceof LayeredSocketFactory)) {
233             throw new IllegalArgumentException
234                 ("Target scheme (" + schm.getName() +
235                  ") must have layered socket factory.");
236         }
237 
238         final LayeredSocketFactory lsf = (LayeredSocketFactory) schm.getSocketFactory();
239         final Socket sock;
240         try {
241             sock = lsf.createSocket
242                 (conn.getSocket(), target.getHostName(), schm.resolvePort(target.getPort()), true);
243         } catch (ConnectException ex) {
244             throw new HttpHostConnectException(target, ex);
245         }
246         prepareSocket(sock, context, params);
247         conn.update(sock, target, lsf.isSecure(sock), params);
248         //@@@ error handling: close the layered socket in case of exception?
249 
250     } // updateSecureConnection
251 
252 
253     /**
254      * Performs standard initializations on a newly created socket.
255      *
256      * @param sock      the socket to prepare
257      * @param context   the context for the connection
258      * @param params    the parameters from which to prepare the socket
259      *
260      * @throws IOException      in case of an IO problem
261      */
prepareSocket(Socket sock, HttpContext context, HttpParams params)262     protected void prepareSocket(Socket sock, HttpContext context,
263                                  HttpParams params)
264         throws IOException {
265 
266         // context currently not used, but derived classes may need it
267         //@@@ is context allowed to be null?
268 
269         sock.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params));
270         sock.setSoTimeout(HttpConnectionParams.getSoTimeout(params));
271 
272         int linger = HttpConnectionParams.getLinger(params);
273         if (linger >= 0) {
274             sock.setSoLinger(linger > 0, linger);
275         }
276 
277     } // prepareSocket
278 
279 
280 } // class DefaultClientConnectionOperator
281