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.InetAddress;
31  import java.net.InetSocketAddress;
32  import java.net.Socket;
33  import java.util.concurrent.TimeUnit;
34  
35  import org.apache.http.HttpClientConnection;
36  import org.apache.http.HttpHost;
37  import org.apache.http.client.protocol.HttpClientContext;
38  import org.apache.http.config.ConnectionConfig;
39  import org.apache.http.config.Lookup;
40  import org.apache.http.config.SocketConfig;
41  import org.apache.http.conn.ConnectionRequest;
42  import org.apache.http.conn.DnsResolver;
43  import org.apache.http.conn.HttpConnectionFactory;
44  import org.apache.http.conn.ManagedHttpClientConnection;
45  import org.apache.http.conn.SchemePortResolver;
46  import org.apache.http.conn.routing.HttpRoute;
47  import org.apache.http.conn.socket.ConnectionSocketFactory;
48  import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
49  import org.apache.http.protocol.HttpContext;
50  import org.junit.Assert;
51  import org.junit.Before;
52  import org.junit.Test;
53  import org.mockito.Mock;
54  import org.mockito.Mockito;
55  import org.mockito.MockitoAnnotations;
56  
57  @SuppressWarnings({"boxing","static-access"}) // test code
58  public class TestBasicHttpClientConnectionManager {
59  
60      @Mock
61      private ManagedHttpClientConnection conn;
62      @Mock
63      private HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
64      @Mock
65      private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
66      @Mock
67      private ConnectionSocketFactory plainSocketFactory;
68      @Mock
69      private LayeredConnectionSocketFactory sslSocketFactory;
70      @Mock
71      private Socket socket;
72      @Mock
73      private SchemePortResolver schemePortResolver;
74      @Mock
75      private DnsResolver dnsResolver;
76  
77      private BasicHttpClientConnectionManager mgr;
78  
79      @Before
80      public void setup() throws Exception {
81          MockitoAnnotations.initMocks(this);
82          mgr = new BasicHttpClientConnectionManager(
83                  socketFactoryRegistry, connFactory, schemePortResolver, dnsResolver);
84      }
85  
86      @Test
87      public void testLeaseReleaseNonReusable() throws Exception {
88          final HttpHost target = new HttpHost("localhost", 80);
89          final HttpRoute route = new HttpRoute(target);
90  
91          Mockito.when(connFactory.create(
92                  Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
93  
94          final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
95          final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
96          Assert.assertNotNull(conn1);
97          Assert.assertFalse(conn1.isOpen());
98  
99          mgr.releaseConnection(conn1, null, 100, TimeUnit.MILLISECONDS);
100 
101         Assert.assertNull(mgr.getRoute());
102         Assert.assertNull(mgr.getState());
103 
104         final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
105         final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
106         Assert.assertNotNull(conn2);
107         Assert.assertFalse(conn2.isOpen());
108 
109         Mockito.verify(connFactory, Mockito.times(2)).create(
110                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
111     }
112 
113     @Test
114     public void testLeaseReleaseReusable() throws Exception {
115         final HttpHost target = new HttpHost("somehost", 80);
116         final HttpRoute route = new HttpRoute(target);
117 
118         Mockito.when(connFactory.create(Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
119 
120         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
121         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
122         Assert.assertNotNull(conn1);
123 
124         Mockito.verify(connFactory, Mockito.times(1)).create(
125                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
126 
127         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
128 
129         mgr.releaseConnection(conn1, null, 10000, TimeUnit.MILLISECONDS);
130 
131         Assert.assertEquals(route, mgr.getRoute());
132         Assert.assertEquals(null, mgr.getState());
133 
134         final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
135         final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
136         Assert.assertNotNull(conn2);
137         Assert.assertTrue(conn2.isOpen());
138 
139         Mockito.verify(connFactory, Mockito.times(1)).create(
140                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
141     }
142 
143     @Test
144     public void testLeaseReleaseReusableWithState() throws Exception {
145         final HttpHost target = new HttpHost("somehost", 80);
146         final HttpRoute route = new HttpRoute(target);
147 
148         Mockito.when(connFactory.create(
149                 Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
150 
151         final ConnectionRequest connRequest1 = mgr.requestConnection(route, "some state");
152         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
153         Assert.assertNotNull(conn1);
154 
155         Mockito.verify(connFactory, Mockito.times(1)).create(
156                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
157 
158         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
159 
160         mgr.releaseConnection(conn1, "some other state", 10000, TimeUnit.MILLISECONDS);
161 
162         Assert.assertEquals(route, mgr.getRoute());
163         Assert.assertEquals("some other state", mgr.getState());
164 
165         final ConnectionRequest connRequest2 = mgr.requestConnection(route, "some other state");
166         final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
167         Assert.assertNotNull(conn2);
168         Assert.assertTrue(conn2.isOpen());
169 
170         Mockito.verify(connFactory, Mockito.times(1)).create(
171                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
172     }
173 
174     @Test
175     public void testLeaseDifferentRoute() throws Exception {
176         final HttpHost target1 = new HttpHost("somehost", 80);
177         final HttpRoute route1 = new HttpRoute(target1);
178 
179         Mockito.when(connFactory.create(
180                 Mockito.<HttpRoute>any(), Mockito.<ConnectionConfig>any())).thenReturn(conn);
181 
182         final ConnectionRequest connRequest1 = mgr.requestConnection(route1, null);
183         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
184         Assert.assertNotNull(conn1);
185 
186         Mockito.verify(connFactory, Mockito.times(1)).create(
187                 Mockito.eq(route1), Mockito.<ConnectionConfig>any());
188 
189         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
190 
191         mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
192 
193         Assert.assertEquals(route1, mgr.getRoute());
194         Assert.assertEquals(null, mgr.getState());
195 
196         final HttpHost target2 = new HttpHost("otherhost", 80);
197         final HttpRoute route2 = new HttpRoute(target2);
198         final ConnectionRequest connRequest2 = mgr.requestConnection(route2, null);
199         final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
200         Assert.assertNotNull(conn2);
201         Assert.assertFalse(conn2.isOpen());
202 
203         Mockito.verify(conn).close();
204         Mockito.verify(connFactory, Mockito.times(1)).create(
205                 Mockito.eq(route1), Mockito.<ConnectionConfig>any());
206         Mockito.verify(connFactory, Mockito.times(1)).create(
207                 Mockito.eq(route2), Mockito.<ConnectionConfig>any());
208     }
209 
210     @Test
211     public void testLeaseExpired() throws Exception {
212         final HttpHost target = new HttpHost("somehost", 80);
213         final HttpRoute route = new HttpRoute(target);
214 
215         Mockito.when(connFactory.create(
216                 Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
217 
218         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
219         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
220         Assert.assertNotNull(conn1);
221 
222         Mockito.verify(connFactory, Mockito.times(1)).create(
223                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
224 
225         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
226 
227         mgr.releaseConnection(conn1, null, 10, TimeUnit.MILLISECONDS);
228 
229         Assert.assertEquals(route, mgr.getRoute());
230         Assert.assertEquals(null, mgr.getState());
231 
232         Thread.sleep(50);
233 
234         final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
235         final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
236         Assert.assertNotNull(conn2);
237         Assert.assertFalse(conn2.isOpen());
238 
239         Mockito.verify(conn).close();
240         Mockito.verify(connFactory, Mockito.times(2)).create(
241                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
242     }
243 
244     @Test(expected=IllegalArgumentException.class)
245     public void testLeaseInvalidArg() throws Exception {
246         mgr.requestConnection(null, null);
247     }
248 
249     @Test(expected=IllegalArgumentException.class)
250     public void testReleaseInvalidArg() throws Exception {
251         mgr.releaseConnection(null, null, 0, TimeUnit.MILLISECONDS);
252     }
253 
254     @Test(expected=IllegalStateException.class)
255     public void testReleaseAnotherConnection() throws Exception {
256         final HttpClientConnection wrongCon = Mockito.mock(HttpClientConnection.class);
257         mgr.releaseConnection(wrongCon, null, 0, TimeUnit.MILLISECONDS);
258     }
259 
260     @Test
261     public void testShutdown() throws Exception {
262         final HttpHost target = new HttpHost("somehost", 80);
263         final HttpRoute route = new HttpRoute(target);
264 
265         Mockito.when(connFactory.create(
266                 Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
267 
268         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
269         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
270         Assert.assertNotNull(conn1);
271 
272         Mockito.verify(connFactory, Mockito.times(1)).create(
273                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
274 
275         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
276 
277         mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
278 
279         mgr.shutdown();
280 
281         Mockito.verify(conn, Mockito.times(1)).shutdown();
282 
283         try {
284             final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
285             connRequest2.get(0, TimeUnit.MILLISECONDS);
286             Assert.fail("IllegalStateException expected");
287         } catch (final IllegalStateException ex) {
288         }
289 
290         // Should have no effect
291         mgr.closeExpiredConnections();
292         mgr.closeIdleConnections(0L, TimeUnit.MILLISECONDS);
293         mgr.shutdown();
294 
295         Mockito.verify(conn, Mockito.times(1)).shutdown();
296     }
297 
298     @Test
299     public void testCloseExpired() throws Exception {
300         final HttpHost target = new HttpHost("somehost", 80);
301         final HttpRoute route = new HttpRoute(target);
302 
303         Mockito.when(connFactory.create(
304                 Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
305 
306         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
307         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
308         Assert.assertNotNull(conn1);
309 
310         Mockito.verify(connFactory, Mockito.times(1)).create(
311                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
312 
313         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
314 
315         mgr.releaseConnection(conn1, null, 10, TimeUnit.MILLISECONDS);
316 
317         Assert.assertEquals(route, mgr.getRoute());
318         Assert.assertEquals(null, mgr.getState());
319 
320         Thread.sleep(50);
321 
322         mgr.closeExpiredConnections();
323 
324         Mockito.verify(conn).close();
325     }
326 
327     @Test
328     public void testCloseIdle() throws Exception {
329         final HttpHost target = new HttpHost("somehost", 80);
330         final HttpRoute route = new HttpRoute(target);
331 
332         Mockito.when(connFactory.create(
333                 Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
334 
335         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
336         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
337         Assert.assertNotNull(conn1);
338 
339         Mockito.verify(connFactory, Mockito.times(1)).create(
340                 Mockito.eq(route), Mockito.<ConnectionConfig>any());
341 
342         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
343 
344         mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
345 
346         Assert.assertEquals(route, mgr.getRoute());
347         Assert.assertEquals(null, mgr.getState());
348 
349         Thread.sleep(100);
350 
351         mgr.closeIdleConnections(50, TimeUnit.MILLISECONDS);
352 
353         Mockito.verify(conn).close();
354     }
355 
356     @Test(expected=IllegalStateException.class)
357     public void testAlreadyLeased() throws Exception {
358         final HttpHost target = new HttpHost("somehost", 80);
359         final HttpRoute route = new HttpRoute(target);
360 
361         Mockito.when(connFactory.create(
362                 Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
363 
364         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
365         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
366         Assert.assertNotNull(conn1);
367         mgr.releaseConnection(conn1, null, 100, TimeUnit.MILLISECONDS);
368 
369         mgr.getConnection(route, null);
370         mgr.getConnection(route, null);
371     }
372 
373     @Test
374     public void testTargetConnect() throws Exception {
375         final HttpHost target = new HttpHost("somehost", 443, "https");
376         final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
377         final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
378         final HttpRoute route = new HttpRoute(target, local, true);
379 
380         Mockito.when(connFactory.create(
381                 Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
382 
383         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
384         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
385         Assert.assertNotNull(conn1);
386 
387         final HttpClientContext context = HttpClientContext.create();
388         final SocketConfig sconfig = SocketConfig.custom().build();
389 
390         mgr.setSocketConfig(sconfig);
391 
392         Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] {remote});
393         Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
394         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory);
395         Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
396         Mockito.when(plainSocketFactory.connectSocket(
397                 Mockito.anyInt(),
398                 Mockito.eq(socket),
399                 Mockito.<HttpHost>any(),
400                 Mockito.<InetSocketAddress>any(),
401                 Mockito.<InetSocketAddress>any(),
402                 Mockito.<HttpContext>any())).thenReturn(socket);
403 
404         mgr.connect(conn1, route, 123, context);
405 
406         Mockito.verify(dnsResolver, Mockito.times(1)).resolve("somehost");
407         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
408         Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
409         Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(123, socket, target,
410                 new InetSocketAddress(remote, 8443),
411                 new InetSocketAddress(local, 0), context);
412 
413         mgr.routeComplete(conn1, route, context);
414     }
415 
416     @Test
417     public void testProxyConnectAndUpgrade() throws Exception {
418         final HttpHost target = new HttpHost("somehost", 443, "https");
419         final HttpHost proxy = new HttpHost("someproxy", 8080);
420         final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
421         final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
422         final HttpRoute route = new HttpRoute(target, local, proxy, true);
423 
424         Mockito.when(connFactory.create(
425                 Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
426 
427         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
428         final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
429         Assert.assertNotNull(conn1);
430 
431         final HttpClientContext context = HttpClientContext.create();
432         final SocketConfig sconfig = SocketConfig.custom().build();
433 
434         mgr.setSocketConfig(sconfig);
435 
436         Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
437         Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
438         Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
439         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
440         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslSocketFactory);
441         Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
442         Mockito.when(plainSocketFactory.connectSocket(
443                 Mockito.anyInt(),
444                 Mockito.eq(socket),
445                 Mockito.<HttpHost>any(),
446                 Mockito.<InetSocketAddress>any(),
447                 Mockito.<InetSocketAddress>any(),
448                 Mockito.<HttpContext>any())).thenReturn(socket);
449 
450         mgr.connect(conn1, route, 123, context);
451 
452         Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
453         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
454         Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
455         Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(123, socket, proxy,
456                 new InetSocketAddress(remote, 8080),
457                 new InetSocketAddress(local, 0), context);
458 
459         Mockito.when(conn.getSocket()).thenReturn(socket);
460 
461         mgr.upgrade(conn1, route, context);
462 
463         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
464         Mockito.verify(sslSocketFactory, Mockito.times(1)).createLayeredSocket(
465                 socket, "somehost", 8443, context);
466 
467         mgr.routeComplete(conn1, route, context);
468     }
469 
470 }