View Javadoc
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   */
27  
28  package org.apache.http.impl.conn;
29  
30  import java.net.ConnectException;
31  import java.net.InetAddress;
32  import java.net.InetSocketAddress;
33  import java.net.Socket;
34  import java.net.SocketTimeoutException;
35  
36  import org.apache.http.HttpHost;
37  import org.apache.http.config.Lookup;
38  import org.apache.http.config.SocketConfig;
39  import org.apache.http.conn.ConnectTimeoutException;
40  import org.apache.http.conn.DnsResolver;
41  import org.apache.http.conn.HttpHostConnectException;
42  import org.apache.http.conn.SchemePortResolver;
43  import org.apache.http.conn.ManagedHttpClientConnection;
44  import org.apache.http.conn.UnsupportedSchemeException;
45  import org.apache.http.conn.socket.ConnectionSocketFactory;
46  import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
47  import org.apache.http.protocol.BasicHttpContext;
48  import org.apache.http.protocol.HttpContext;
49  import org.junit.Before;
50  import org.junit.Test;
51  import org.mockito.Mockito;
52  
53  @SuppressWarnings({"boxing","static-access"}) // test code
54  public class TestHttpClientConnectionOperator {
55  
56      private ManagedHttpClientConnection conn;
57      private Socket socket;
58      private ConnectionSocketFactory plainSocketFactory;
59      private LayeredConnectionSocketFactory sslSocketFactory;
60      private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
61      private SchemePortResolver schemePortResolver;
62      private DnsResolver dnsResolver;
63      private DefaultHttpClientConnectionOperator connectionOperator;
64  
65      @SuppressWarnings("unchecked")
66      @Before
67      public void setup() throws Exception {
68          conn = Mockito.mock(ManagedHttpClientConnection.class);
69          socket = Mockito.mock(Socket.class);
70          plainSocketFactory = Mockito.mock(ConnectionSocketFactory.class);
71          sslSocketFactory = Mockito.mock(LayeredConnectionSocketFactory.class);
72          socketFactoryRegistry = Mockito.mock(Lookup.class);
73          schemePortResolver = Mockito.mock(SchemePortResolver.class);
74          dnsResolver = Mockito.mock(DnsResolver.class);
75          connectionOperator = new DefaultHttpClientConnectionOperator(
76                  socketFactoryRegistry, schemePortResolver, dnsResolver);
77      }
78  
79      @Test
80      public void testConnect() throws Exception {
81          final HttpContext context = new BasicHttpContext();
82          final HttpHost host = new HttpHost("somehost");
83          final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
84          final InetAddress ip1 = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
85          final InetAddress ip2 = InetAddress.getByAddress(new byte[] {127, 0, 0, 2});
86  
87          Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
88          Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
89          Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
90          Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
91          Mockito.when(plainSocketFactory.connectSocket(
92                  Mockito.anyInt(),
93                  Mockito.<Socket>any(),
94                  Mockito.<HttpHost>any(),
95                  Mockito.<InetSocketAddress>any(),
96                  Mockito.<InetSocketAddress>any(),
97                  Mockito.<HttpContext>any())).thenReturn(socket);
98  
99          final SocketConfig socketConfig = SocketConfig.custom()
100             .setSoKeepAlive(true)
101             .setSoReuseAddress(true)
102             .setSoTimeout(5000)
103             .setTcpNoDelay(true)
104             .setSoLinger(50)
105             .build();
106         final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
107         connectionOperator.connect(conn, host, localAddress, 1000, socketConfig, context);
108 
109         Mockito.verify(socket).setKeepAlive(true);
110         Mockito.verify(socket).setReuseAddress(true);
111         Mockito.verify(socket).setSoTimeout(5000);
112         Mockito.verify(socket).setSoLinger(true, 50);
113         Mockito.verify(socket).setTcpNoDelay(true);
114 
115         Mockito.verify(plainSocketFactory).connectSocket(
116                 1000,
117                 socket,
118                 host,
119                 new InetSocketAddress(ip1, 80),
120                 localAddress,
121                 context);
122         Mockito.verify(conn, Mockito.times(2)).bind(socket);
123     }
124 
125     @Test(expected=ConnectTimeoutException.class)
126     public void testConnectTimeout() throws Exception {
127         final HttpContext context = new BasicHttpContext();
128         final HttpHost host = new HttpHost("somehost");
129         final InetAddress ip1 = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
130         final InetAddress ip2 = InetAddress.getByAddress(new byte[] {10, 0, 0, 2});
131 
132         Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
133         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
134         Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
135         Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
136         Mockito.when(plainSocketFactory.connectSocket(
137                 Mockito.anyInt(),
138                 Mockito.<Socket>any(),
139                 Mockito.<HttpHost>any(),
140                 Mockito.<InetSocketAddress>any(),
141                 Mockito.<InetSocketAddress>any(),
142                 Mockito.<HttpContext>any())).thenThrow(new SocketTimeoutException());
143 
144         connectionOperator.connect(conn, host, null, 1000, SocketConfig.DEFAULT, context);
145     }
146 
147     @Test(expected=HttpHostConnectException.class)
148     public void testConnectFailure() throws Exception {
149         final HttpContext context = new BasicHttpContext();
150         final HttpHost host = new HttpHost("somehost");
151         final InetAddress ip1 = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
152         final InetAddress ip2 = InetAddress.getByAddress(new byte[] {10, 0, 0, 2});
153 
154         Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
155         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
156         Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
157         Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
158         Mockito.when(plainSocketFactory.connectSocket(
159                 Mockito.anyInt(),
160                 Mockito.<Socket>any(),
161                 Mockito.<HttpHost>any(),
162                 Mockito.<InetSocketAddress>any(),
163                 Mockito.<InetSocketAddress>any(),
164                 Mockito.<HttpContext>any())).thenThrow(new ConnectException());
165 
166         connectionOperator.connect(conn, host, null, 1000, SocketConfig.DEFAULT, context);
167     }
168 
169     @Test
170     public void testConnectFailover() throws Exception {
171         final HttpContext context = new BasicHttpContext();
172         final HttpHost host = new HttpHost("somehost");
173         final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
174         final InetAddress ip1 = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
175         final InetAddress ip2 = InetAddress.getByAddress(new byte[] {10, 0, 0, 2});
176 
177         Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
178         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
179         Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
180         Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
181         Mockito.when(plainSocketFactory.connectSocket(
182                 Mockito.anyInt(),
183                 Mockito.<Socket>any(),
184                 Mockito.<HttpHost>any(),
185                 Mockito.eq(new InetSocketAddress(ip1, 80)),
186                 Mockito.<InetSocketAddress>any(),
187                 Mockito.<HttpContext>any())).thenThrow(new ConnectException());
188         Mockito.when(plainSocketFactory.connectSocket(
189                 Mockito.anyInt(),
190                 Mockito.<Socket>any(),
191                 Mockito.<HttpHost>any(),
192                 Mockito.eq(new InetSocketAddress(ip2, 80)),
193                 Mockito.<InetSocketAddress>any(),
194                 Mockito.<HttpContext>any())).thenReturn(socket);
195 
196         final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
197         connectionOperator.connect(conn, host, localAddress, 1000, SocketConfig.DEFAULT, context);
198 
199         Mockito.verify(plainSocketFactory).connectSocket(
200                 1000,
201                 socket,
202                 host,
203                 new InetSocketAddress(ip2, 80),
204                 localAddress,
205                 context);
206         Mockito.verify(conn, Mockito.times(3)).bind(socket);
207     }
208 
209     @Test
210     public void testConnectExplicitAddress() throws Exception {
211         final HttpContext context = new BasicHttpContext();
212         final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
213         final InetAddress ip = InetAddress.getByAddress(new byte[] {127, 0, 0, 23});
214         final HttpHost host = new HttpHost(ip);
215 
216         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
217         Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
218         Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
219         Mockito.when(plainSocketFactory.connectSocket(
220                 Mockito.anyInt(),
221                 Mockito.<Socket>any(),
222                 Mockito.<HttpHost>any(),
223                 Mockito.<InetSocketAddress>any(),
224                 Mockito.<InetSocketAddress>any(),
225                 Mockito.<HttpContext>any())).thenReturn(socket);
226 
227         final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
228         connectionOperator.connect(conn, host, localAddress, 1000, SocketConfig.DEFAULT, context);
229 
230         Mockito.verify(plainSocketFactory).connectSocket(
231                 1000,
232                 socket,
233                 host,
234                 new InetSocketAddress(ip, 80),
235                 localAddress,
236                 context);
237         Mockito.verify(dnsResolver, Mockito.never()).resolve(Mockito.anyString());
238         Mockito.verify(conn, Mockito.times(2)).bind(socket);
239     }
240 
241     @Test
242     public void testUpgrade() throws Exception {
243         final HttpContext context = new BasicHttpContext();
244         final HttpHost host = new HttpHost("somehost", -1, "https");
245 
246         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslSocketFactory);
247         Mockito.when(schemePortResolver.resolve(host)).thenReturn(443);
248         Mockito.when(sslSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
249         Mockito.when(sslSocketFactory.createLayeredSocket(
250                 Mockito.<Socket>any(),
251                 Mockito.eq("somehost"),
252                 Mockito.eq(443),
253                 Mockito.<HttpContext>any())).thenReturn(socket);
254 
255         connectionOperator.upgrade(conn, host, context);
256 
257         Mockito.verify(conn).bind(socket);
258     }
259 
260     @Test(expected=UnsupportedSchemeException.class)
261     public void testUpgradeUpsupportedScheme() throws Exception {
262         final HttpContext context = new BasicHttpContext();
263         final HttpHost host = new HttpHost("somehost", -1, "httpsssss");
264         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
265 
266         connectionOperator.upgrade(conn, host, context);
267     }
268 
269     @Test(expected=UnsupportedSchemeException.class)
270     public void testUpgradeNonLayeringScheme() throws Exception {
271         final HttpContext context = new BasicHttpContext();
272         final HttpHost host = new HttpHost("somehost", -1, "http");
273         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
274 
275         connectionOperator.upgrade(conn, host, context);
276     }
277 
278 }