1e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt/*
2e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/DefaultClientConnectionOperator.java $
3e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * $Revision: 652193 $
4e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * $Date: 2008-04-29 17:10:36 -0700 (Tue, 29 Apr 2008) $
5e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt *
6e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * ====================================================================
7e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * Licensed to the Apache Software Foundation (ASF) under one
8f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * or more contributor license agreements.  See the NOTICE file
909cda4fad9681e8500485ef0b71974d16c28fcc3Elliott Hughes * 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
32package org.apache.http.impl.conn;
33
34import java.io.IOException;
35import java.net.ConnectException;
36import java.net.Socket;
37import java.net.InetAddress;
38
39import java.net.SocketException;
40import org.apache.http.HttpHost;
41import org.apache.http.params.HttpParams;
42import org.apache.http.params.HttpConnectionParams;
43import org.apache.http.protocol.HttpContext;
44
45import org.apache.http.conn.HttpHostConnectException;
46import org.apache.http.conn.OperatedClientConnection;
47import org.apache.http.conn.ClientConnectionOperator;
48import org.apache.http.conn.ConnectTimeoutException;
49import org.apache.http.conn.scheme.LayeredSocketFactory;
50import org.apache.http.conn.scheme.PlainSocketFactory;
51import org.apache.http.conn.scheme.Scheme;
52import org.apache.http.conn.scheme.SchemeRegistry;
53import 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
75public 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     */
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
99    public OperatedClientConnection createConnection() {
100        return new DefaultClientConnection();
101    }
102
103
104    // non-javadoc, see interface ClientConnectionOperator
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                    ConnectException cause = ex instanceof ConnectException
187                            ? (ConnectException) ex : new ConnectException(ex.getMessage(), ex);
188                    throw new HttpHostConnectException(target, cause);
189                }
190            // END android-changed
191            } catch (ConnectTimeoutException ex) {
192                if (i == addresses.length - 1) {
193                    throw ex;
194                }
195            }
196        }
197    } // openConnection
198
199
200    // non-javadoc, see interface ClientConnectionOperator
201    public void updateSecureConnection(OperatedClientConnection conn,
202                                       HttpHost target,
203                                       HttpContext context,
204                                       HttpParams params)
205        throws IOException {
206
207
208        if (conn == null) {
209            throw new IllegalArgumentException
210                ("Connection must not be null.");
211        }
212        if (target == null) {
213            throw new IllegalArgumentException
214                ("Target host must not be null.");
215        }
216        //@@@ is context allowed to be null?
217        if (params == null) {
218            throw new IllegalArgumentException
219                ("Parameters must not be null.");
220        }
221        if (!conn.isOpen()) {
222            throw new IllegalArgumentException
223                ("Connection must be open.");
224        }
225
226        final Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
227        if (!(schm.getSocketFactory() instanceof LayeredSocketFactory)) {
228            throw new IllegalArgumentException
229                ("Target scheme (" + schm.getName() +
230                 ") must have layered socket factory.");
231        }
232
233        final LayeredSocketFactory lsf = (LayeredSocketFactory) schm.getSocketFactory();
234        final Socket sock;
235        try {
236            sock = lsf.createSocket
237                (conn.getSocket(), target.getHostName(), schm.resolvePort(target.getPort()), true);
238        } catch (ConnectException ex) {
239            throw new HttpHostConnectException(target, ex);
240        }
241        prepareSocket(sock, context, params);
242        conn.update(sock, target, lsf.isSecure(sock), params);
243        //@@@ error handling: close the layered socket in case of exception?
244
245    } // updateSecureConnection
246
247
248    /**
249     * Performs standard initializations on a newly created socket.
250     *
251     * @param sock      the socket to prepare
252     * @param context   the context for the connection
253     * @param params    the parameters from which to prepare the socket
254     *
255     * @throws IOException      in case of an IO problem
256     */
257    protected void prepareSocket(Socket sock, HttpContext context,
258                                 HttpParams params)
259        throws IOException {
260
261        // context currently not used, but derived classes may need it
262        //@@@ is context allowed to be null?
263
264        sock.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params));
265        sock.setSoTimeout(HttpConnectionParams.getSoTimeout(params));
266
267        int linger = HttpConnectionParams.getLinger(params);
268        if (linger >= 0) {
269            sock.setSoLinger(linger > 0, linger);
270        }
271
272    } // prepareSocket
273
274
275} // class DefaultClientConnectionOperator
276