1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.impl.io;
29
30 import java.net.InetAddress;
31 import java.net.InetSocketAddress;
32 import java.net.Socket;
33 import java.util.concurrent.Future;
34 import java.util.concurrent.TimeUnit;
35 import java.util.concurrent.TimeoutException;
36
37 import org.apache.hc.client5.http.DnsResolver;
38 import org.apache.hc.client5.http.HttpRoute;
39 import org.apache.hc.client5.http.SchemePortResolver;
40 import org.apache.hc.client5.http.io.ConnectionEndpoint;
41 import org.apache.hc.client5.http.io.LeaseRequest;
42 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
43 import org.apache.hc.client5.http.protocol.HttpClientContext;
44 import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
45 import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
46 import org.apache.hc.core5.concurrent.FutureCallback;
47 import org.apache.hc.core5.http.HttpHost;
48 import org.apache.hc.core5.http.config.Lookup;
49 import org.apache.hc.core5.http.io.SocketConfig;
50 import org.apache.hc.core5.http.protocol.HttpContext;
51 import org.apache.hc.core5.pool.PoolEntry;
52 import org.apache.hc.core5.pool.StrictConnPool;
53 import org.apache.hc.core5.util.TimeValue;
54 import org.apache.hc.core5.util.Timeout;
55 import org.junit.Assert;
56 import org.junit.Before;
57 import org.junit.Test;
58 import org.mockito.Mock;
59 import org.mockito.Mockito;
60 import org.mockito.MockitoAnnotations;
61
62
63
64
65 @SuppressWarnings({"boxing","static-access","resource"})
66 public class TestPoolingHttpClientConnectionManager {
67
68 @Mock
69 private ManagedHttpClientConnection conn;
70 @Mock
71 private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
72 @Mock
73 private ConnectionSocketFactory plainSocketFactory;
74 @Mock
75 private ConnectionSocketFactory sslSocketFactory;
76 @Mock
77 private Socket socket;
78 @Mock
79 private SchemePortResolver schemePortResolver;
80 @Mock
81 private DnsResolver dnsResolver;
82 @Mock
83 private Future<PoolEntry<HttpRoute, ManagedHttpClientConnection>> future;
84 @Mock
85 private StrictConnPool<HttpRoute, ManagedHttpClientConnection> pool;
86 private PoolingHttpClientConnectionManager mgr;
87
88 @Before
89 public void setup() throws Exception {
90 MockitoAnnotations.initMocks(this);
91 mgr = new PoolingHttpClientConnectionManager(
92 new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver), pool, null);
93 }
94
95 @Test
96 public void testLeaseRelease() throws Exception {
97 final HttpHost target = new HttpHost("localhost", 80);
98 final HttpRoute route = new HttpRoute(target);
99
100 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
101 entry.assignConnection(conn);
102
103 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
104 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
105 Mockito.when(schemePortResolver.resolve(target)).thenReturn(80);
106 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
107
108 Mockito.when(conn.isOpen()).thenReturn(true);
109 Mockito.when(conn.isConsistent()).thenReturn(true);
110 Mockito.when(future.isCancelled()).thenReturn(false);
111 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
112 Mockito.when(pool.lease(
113 Mockito.eq(route),
114 Mockito.eq(null),
115 Mockito.<Timeout>any(),
116 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
117 .thenReturn(future);
118
119 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
120 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
121 Assert.assertNotNull(endpoint1);
122 Assert.assertNotSame(conn, endpoint1);
123
124 mgr.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECOND);
125
126 Mockito.verify(pool).release(entry, true);
127 }
128
129 @Test
130 public void testReleaseRouteIncomplete() throws Exception {
131 final HttpHost target = new HttpHost("localhost", 80);
132 final HttpRoute route = new HttpRoute(target);
133
134 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
135
136 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
137 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
138 Mockito.when(schemePortResolver.resolve(target)).thenReturn(80);
139 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
140
141 Mockito.when(conn.isOpen()).thenReturn(true);
142 Mockito.when(future.isCancelled()).thenReturn(false);
143 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
144 Mockito.when(pool.lease(
145 Mockito.eq(route),
146 Mockito.eq(null),
147 Mockito.<Timeout>any(),
148 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
149 .thenReturn(future);
150
151 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
152 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
153 Assert.assertNotNull(endpoint1);
154 Assert.assertNotSame(conn, endpoint1);
155
156 mgr.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECOND);
157
158 Mockito.verify(pool).release(entry, false);
159 }
160
161 @Test(expected=TimeoutException.class)
162 public void testLeaseFutureTimeout() throws Exception {
163 final HttpHost target = new HttpHost("localhost", 80);
164 final HttpRoute route = new HttpRoute(target);
165
166 Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
167 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenThrow(new TimeoutException());
168 Mockito.when(pool.lease(
169 Mockito.eq(route),
170 Mockito.eq(null),
171 Mockito.<Timeout>any(),
172 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
173 .thenReturn(future);
174
175 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
176 connRequest1.get(Timeout.ofSeconds(1));
177 }
178
179 @Test
180 public void testReleaseReusable() throws Exception {
181 final HttpHost target = new HttpHost("localhost", 80);
182 final HttpRoute route = new HttpRoute(target);
183
184 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
185 entry.assignConnection(conn);
186
187 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
188 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
189 Mockito.when(pool.lease(
190 Mockito.eq(route),
191 Mockito.eq(null),
192 Mockito.<Timeout>any(),
193 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
194 .thenReturn(future);
195 Mockito.when(conn.isOpen()).thenReturn(true);
196 Mockito.when(conn.isConsistent()).thenReturn(true);
197
198 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
199 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
200 Assert.assertNotNull(endpoint1);
201 Assert.assertTrue(endpoint1.isConnected());
202
203 mgr.release(endpoint1, "some state", TimeValue.NEG_ONE_MILLISECOND);
204
205 Mockito.verify(pool).release(entry, true);
206 Assert.assertEquals("some state", entry.getState());
207 }
208
209 @Test
210 public void testReleaseNonReusable() throws Exception {
211 final HttpHost target = new HttpHost("localhost", 80);
212 final HttpRoute route = new HttpRoute(target);
213
214 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
215 entry.assignConnection(conn);
216
217 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
218 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
219 Mockito.when(pool.lease(
220 Mockito.eq(route),
221 Mockito.eq(null),
222 Mockito.<Timeout>any(),
223 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
224 .thenReturn(future);
225 Mockito.when(conn.isOpen()).thenReturn(Boolean.FALSE);
226
227 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
228 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
229 Assert.assertNotNull(endpoint1);
230 Assert.assertFalse(endpoint1.isConnected());
231
232 mgr.release(endpoint1, "some state", TimeValue.NEG_ONE_MILLISECOND);
233
234 Mockito.verify(pool).release(entry, false);
235 Assert.assertEquals(null, entry.getState());
236 }
237
238 @Test
239 public void testTargetConnect() throws Exception {
240 final HttpHost target = new HttpHost("https", "somehost", 443);
241 final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
242 final InetAddress local = InetAddress.getByAddress(new byte[]{127, 0, 0, 1});
243 final HttpRoute route = new HttpRoute(target, local, true);
244
245 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
246 entry.assignConnection(conn);
247
248 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
249 Mockito.when(conn.isOpen()).thenReturn(false);
250 Mockito.when(future.isCancelled()).thenReturn(false);
251 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
252 Mockito.when(pool.lease(
253 Mockito.eq(route),
254 Mockito.eq(null),
255 Mockito.<Timeout>any(),
256 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
257 .thenReturn(future);
258
259 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
260 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
261 Assert.assertNotNull(endpoint1);
262
263 final HttpClientContext context = HttpClientContext.create();
264 final SocketConfig sconfig = SocketConfig.custom().build();
265
266 mgr.setDefaultSocketConfig(sconfig);
267
268 Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[]{remote});
269 Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
270 Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory);
271 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
272 Mockito.when(plainSocketFactory.connectSocket(
273 Mockito.<TimeValue>any(),
274 Mockito.eq(socket),
275 Mockito.<HttpHost>any(),
276 Mockito.<InetSocketAddress>any(),
277 Mockito.<InetSocketAddress>any(),
278 Mockito.<HttpContext>any())).thenReturn(socket);
279
280 mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
281
282 Mockito.verify(dnsResolver, Mockito.times(1)).resolve("somehost");
283 Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
284 Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
285 Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), socket, target,
286 new InetSocketAddress(remote, 8443),
287 new InetSocketAddress(local, 0), context);
288 }
289
290 @Test
291 public void testProxyConnectAndUpgrade() throws Exception {
292 final HttpHost target = new HttpHost("https", "somehost", 443);
293 final HttpHost proxy = new HttpHost("someproxy", 8080);
294 final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
295 final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
296 final HttpRoute route = new HttpRoute(target, local, proxy, true);
297
298 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
299 entry.assignConnection(conn);
300
301 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
302 Mockito.when(conn.isOpen()).thenReturn(false);
303 Mockito.when(future.isCancelled()).thenReturn(false);
304 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
305 Mockito.when(pool.lease(
306 Mockito.eq(route),
307 Mockito.eq(null),
308 Mockito.<Timeout>any(),
309 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
310 .thenReturn(future);
311
312 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
313 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
314 Assert.assertNotNull(endpoint1);
315
316 final ConnectionSocketFactory plainsf = Mockito.mock(ConnectionSocketFactory.class);
317 final LayeredConnectionSocketFactory sslsf = Mockito.mock(LayeredConnectionSocketFactory.class);
318 final Socket mockSock = Mockito.mock(Socket.class);
319 final HttpClientContext context = HttpClientContext.create();
320 final SocketConfig sconfig = SocketConfig.custom().build();
321
322 mgr.setDefaultSocketConfig(sconfig);
323
324 Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
325 Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
326 Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
327 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainsf);
328 Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslsf);
329 Mockito.when(plainsf.createSocket(Mockito.<HttpContext>any())).thenReturn(mockSock);
330 Mockito.when(plainsf.connectSocket(
331 Mockito.<TimeValue>any(),
332 Mockito.eq(mockSock),
333 Mockito.<HttpHost>any(),
334 Mockito.<InetSocketAddress>any(),
335 Mockito.<InetSocketAddress>any(),
336 Mockito.<HttpContext>any())).thenReturn(mockSock);
337
338 mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
339
340 Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
341 Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
342 Mockito.verify(plainsf, Mockito.times(1)).createSocket(context);
343 Mockito.verify(plainsf, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), mockSock, proxy,
344 new InetSocketAddress(remote, 8080),
345 new InetSocketAddress(local, 0), context);
346
347 Mockito.when(conn.isOpen()).thenReturn(true);
348 Mockito.when(conn.getSocket()).thenReturn(mockSock);
349
350 mgr.upgrade(endpoint1, context);
351
352 Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
353 Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket(
354 mockSock, "somehost", 8443, context);
355 }
356
357 }