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 package org.apache.http.impl.execchain;
28
29 import java.io.ByteArrayInputStream;
30 import java.io.ByteArrayOutputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.InterruptedIOException;
34 import java.util.Arrays;
35 import java.util.HashMap;
36 import java.util.LinkedList;
37 import java.util.Map;
38 import java.util.concurrent.ExecutionException;
39 import java.util.concurrent.TimeUnit;
40
41 import org.apache.http.ConnectionReuseStrategy;
42 import org.apache.http.Header;
43 import org.apache.http.HttpClientConnection;
44 import org.apache.http.HttpEntityEnclosingRequest;
45 import org.apache.http.HttpException;
46 import org.apache.http.HttpHost;
47 import org.apache.http.HttpRequest;
48 import org.apache.http.HttpResponse;
49 import org.apache.http.HttpVersion;
50 import org.apache.http.auth.AUTH;
51 import org.apache.http.auth.AuthOption;
52 import org.apache.http.auth.AuthProtocolState;
53 import org.apache.http.auth.AuthState;
54 import org.apache.http.auth.NTCredentials;
55 import org.apache.http.auth.UsernamePasswordCredentials;
56 import org.apache.http.client.AuthenticationStrategy;
57 import org.apache.http.client.NonRepeatableRequestException;
58 import org.apache.http.client.UserTokenHandler;
59 import org.apache.http.client.config.RequestConfig;
60 import org.apache.http.client.entity.EntityBuilder;
61 import org.apache.http.client.methods.CloseableHttpResponse;
62 import org.apache.http.client.methods.HttpExecutionAware;
63 import org.apache.http.client.methods.HttpGet;
64 import org.apache.http.client.methods.HttpPost;
65 import org.apache.http.client.methods.HttpRequestWrapper;
66 import org.apache.http.client.protocol.HttpClientContext;
67 import org.apache.http.concurrent.Cancellable;
68 import org.apache.http.conn.ConnectionKeepAliveStrategy;
69 import org.apache.http.conn.ConnectionRequest;
70 import org.apache.http.conn.HttpClientConnectionManager;
71 import org.apache.http.conn.routing.HttpRoute;
72 import org.apache.http.conn.routing.RouteInfo;
73 import org.apache.http.entity.StringEntity;
74 import org.apache.http.impl.auth.BasicScheme;
75 import org.apache.http.impl.auth.NTLMScheme;
76 import org.apache.http.impl.conn.ConnectionShutdownException;
77 import org.apache.http.message.BasicHeader;
78 import org.apache.http.message.BasicHttpResponse;
79 import org.apache.http.protocol.HttpContext;
80 import org.apache.http.protocol.HttpProcessor;
81 import org.apache.http.protocol.HttpRequestExecutor;
82 import org.apache.http.util.EntityUtils;
83 import org.junit.Assert;
84 import org.junit.Before;
85 import org.junit.Test;
86 import org.mockito.ArgumentCaptor;
87 import org.mockito.Mock;
88 import org.mockito.Mockito;
89 import org.mockito.MockitoAnnotations;
90 import org.mockito.invocation.InvocationOnMock;
91 import org.mockito.stubbing.Answer;
92
93 @SuppressWarnings({"boxing","static-access"})
94 public class TestMainClientExec {
95
96 @Mock
97 private HttpRequestExecutor requestExecutor;
98 @Mock
99 private HttpClientConnectionManager connManager;
100 @Mock
101 private ConnectionReuseStrategy reuseStrategy;
102 @Mock
103 private ConnectionKeepAliveStrategy keepAliveStrategy;
104 @Mock
105 private HttpProcessor proxyHttpProcessor;
106 @Mock
107 private AuthenticationStrategy targetAuthStrategy;
108 @Mock
109 private AuthenticationStrategy proxyAuthStrategy;
110 @Mock
111 private UserTokenHandler userTokenHandler;
112 @Mock
113 private HttpExecutionAware execAware;
114 @Mock
115 private ConnectionRequest connRequest;
116 @Mock
117 private HttpClientConnection managedConn;
118
119 private MainClientExec mainClientExec;
120 private HttpHost target;
121 private HttpHost proxy;
122
123 @Before
124 public void setup() throws Exception {
125 MockitoAnnotations.initMocks(this);
126 mainClientExec = new MainClientExec(requestExecutor, connManager, reuseStrategy,
127 keepAliveStrategy, proxyHttpProcessor, targetAuthStrategy, proxyAuthStrategy, userTokenHandler);
128 target = new HttpHost("foo", 80);
129 proxy = new HttpHost("bar", 8888);
130
131 Mockito.when(connManager.requestConnection(
132 Mockito.<HttpRoute>any(), Mockito.any())).thenReturn(connRequest);
133 Mockito.when(connRequest.get(
134 Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(managedConn);
135 final Map<String, Header> challenges = new HashMap<String, Header>();
136 challenges.put("basic", new BasicHeader(AUTH.WWW_AUTH, "Basic realm=test"));
137 final AuthOption authOption = new AuthOption(
138 new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
139 Mockito.when(targetAuthStrategy.getChallenges(
140 Mockito.eq(target),
141 Mockito.<HttpResponse>any(),
142 Mockito.<HttpClientContext>any())).thenReturn(challenges);
143 Mockito.when(targetAuthStrategy.getChallenges(
144 Mockito.eq(target),
145 Mockito.<HttpResponse>any(),
146 Mockito.<HttpClientContext>any())).thenReturn(challenges);
147 Mockito.when(targetAuthStrategy.select(
148 Mockito.same(challenges),
149 Mockito.eq(target),
150 Mockito.<HttpResponse>any(),
151 Mockito.<HttpClientContext>any())).thenReturn(
152 new LinkedList<AuthOption>(Arrays.asList(authOption)));
153 Mockito.when(proxyAuthStrategy.getChallenges(
154 Mockito.eq(proxy),
155 Mockito.<HttpResponse>any(),
156 Mockito.<HttpClientContext>any())).thenReturn(challenges);
157 Mockito.when(proxyAuthStrategy.getChallenges(
158 Mockito.eq(proxy),
159 Mockito.<HttpResponse>any(),
160 Mockito.<HttpClientContext>any())).thenReturn(challenges);
161 Mockito.when(proxyAuthStrategy.select(
162 Mockito.same(challenges),
163 Mockito.eq(proxy),
164 Mockito.<HttpResponse>any(),
165 Mockito.<HttpClientContext>any())).thenReturn(
166 new LinkedList<AuthOption>(Arrays.asList(authOption)));
167
168 }
169
170 @Test
171 public void testExecRequestNonPersistentConnection() throws Exception {
172 final HttpRoute route = new HttpRoute(target);
173 final HttpClientContext context = new HttpClientContext();
174 final RequestConfig config = RequestConfig.custom()
175 .setConnectTimeout(123)
176 .setSocketTimeout(234)
177 .setConnectionRequestTimeout(345)
178 .build();
179 context.setRequestConfig(config);
180 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
181 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
182 Mockito.when(requestExecutor.execute(
183 Mockito.same(request),
184 Mockito.<HttpClientConnection>any(),
185 Mockito.<HttpClientContext>any())).thenReturn(response);
186
187 final CloseableHttpResponse finalResponse = mainClientExec.execute(
188 route, request, context, execAware);
189 Mockito.verify(connManager).requestConnection(route, null);
190 Mockito.verify(connRequest).get(345, TimeUnit.MILLISECONDS);
191 Mockito.verify(execAware, Mockito.times(1)).setCancellable(connRequest);
192 Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
193 Mockito.verify(connManager).connect(managedConn, route, 123, context);
194 Mockito.verify(connManager).routeComplete(managedConn, route, context);
195 Mockito.verify(managedConn).setSocketTimeout(234);
196 Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
197 Mockito.verify(managedConn, Mockito.times(1)).close();
198 Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
199
200 Assert.assertNotNull(context.getTargetAuthState());
201 Assert.assertNotNull(context.getProxyAuthState());
202 Assert.assertSame(managedConn, context.getConnection());
203 Assert.assertNull(context.getUserToken());
204 Assert.assertNotNull(finalResponse);
205 Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
206 }
207
208 @Test
209 public void testExecRequestPersistentConnection() throws Exception {
210 final HttpRoute route = new HttpRoute(target);
211 final HttpClientContext context = new HttpClientContext();
212 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
213 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
214
215 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
216 Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
217 Mockito.when(requestExecutor.execute(
218 Mockito.same(request),
219 Mockito.<HttpClientConnection>any(),
220 Mockito.<HttpClientContext>any())).thenReturn(response);
221 Mockito.when(reuseStrategy.keepAlive(
222 Mockito.same(response),
223 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
224 Mockito.when(keepAliveStrategy.getKeepAliveDuration(
225 Mockito.same(response),
226 Mockito.<HttpClientContext>any())).thenReturn(678L);
227
228 final CloseableHttpResponse finalResponse = mainClientExec.execute(
229 route, request, context, execAware);
230 Mockito.verify(connManager).requestConnection(route, null);
231 Mockito.verify(connRequest).get(0, TimeUnit.MILLISECONDS);
232 Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
233 Mockito.verify(connManager).releaseConnection(managedConn, null, 678L, TimeUnit.MILLISECONDS);
234 Mockito.verify(managedConn, Mockito.never()).close();
235
236 Assert.assertNotNull(finalResponse);
237 Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
238 }
239
240 @Test
241 public void testExecRequestPersistentStatefulConnection() throws Exception {
242 final HttpRoute route = new HttpRoute(target);
243 final HttpClientContext context = new HttpClientContext();
244 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
245 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
246
247 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
248 Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
249 Mockito.when(requestExecutor.execute(
250 Mockito.same(request),
251 Mockito.<HttpClientConnection>any(),
252 Mockito.<HttpClientContext>any())).thenReturn(response);
253 Mockito.when(reuseStrategy.keepAlive(
254 Mockito.same(response),
255 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
256 Mockito.when(userTokenHandler.getUserToken(
257 Mockito.<HttpClientContext>any())).thenReturn("this and that");
258
259 mainClientExec.execute(route, request, context, execAware);
260 Mockito.verify(connManager).requestConnection(route, null);
261 Mockito.verify(connRequest).get(0, TimeUnit.MILLISECONDS);
262 Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
263 Mockito.verify(connManager).releaseConnection(managedConn, "this and that", 0, TimeUnit.MILLISECONDS);
264 Mockito.verify(managedConn, Mockito.never()).close();
265
266 Assert.assertEquals("this and that", context.getUserToken());
267 }
268
269 @Test
270 public void testExecRequestConnectionRelease() throws Exception {
271 final HttpRoute route = new HttpRoute(target);
272 final HttpClientContext context = new HttpClientContext();
273 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
274 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
275
276 response.setEntity(EntityBuilder.create()
277 .setStream(new ByteArrayInputStream(new byte[]{}))
278 .build());
279
280 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
281 Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
282 Mockito.when(requestExecutor.execute(
283 Mockito.same(request),
284 Mockito.<HttpClientConnection>any(),
285 Mockito.<HttpClientContext>any())).thenReturn(response);
286 Mockito.when(reuseStrategy.keepAlive(
287 Mockito.same(response),
288 Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
289
290 final CloseableHttpResponse finalResponse = mainClientExec.execute(
291 route, request, context, execAware);
292 Mockito.verify(connManager).requestConnection(route, null);
293 Mockito.verify(connRequest).get(0, TimeUnit.MILLISECONDS);
294 Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
295 Mockito.verify(connManager, Mockito.never()).releaseConnection(
296 Mockito.same(managedConn),
297 Mockito.any(),
298 Mockito.anyInt(),
299 Mockito.<TimeUnit>any());
300 Mockito.verify(managedConn, Mockito.never()).close();
301
302 Assert.assertNotNull(finalResponse);
303 Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
304 finalResponse.close();
305
306 Mockito.verify(connManager, Mockito.times(1)).releaseConnection(
307 managedConn, null, 0, TimeUnit.MILLISECONDS);
308 Mockito.verify(managedConn, Mockito.times(1)).close();
309 }
310
311 @Test
312 public void testSocketTimeoutExistingConnection() throws Exception {
313 final HttpRoute route = new HttpRoute(target);
314 final HttpClientContext context = new HttpClientContext();
315 final RequestConfig config = RequestConfig.custom().setSocketTimeout(3000).build();
316 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
317 context.setRequestConfig(config);
318 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
319 Mockito.when(managedConn.isOpen()).thenReturn(true);
320 Mockito.when(requestExecutor.execute(
321 Mockito.same(request),
322 Mockito.<HttpClientConnection>any(),
323 Mockito.<HttpClientContext>any())).thenReturn(response);
324
325 mainClientExec.execute(route, request, context, execAware);
326 Mockito.verify(managedConn).setSocketTimeout(3000);
327 }
328
329 @Test
330 public void testSocketTimeoutReset() throws Exception {
331 final HttpRoute route = new HttpRoute(target);
332 final HttpClientContext context = new HttpClientContext();
333 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
334 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
335 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
336 Mockito.when(requestExecutor.execute(
337 Mockito.same(request),
338 Mockito.<HttpClientConnection>any(),
339 Mockito.<HttpClientContext>any())).thenReturn(response);
340
341 mainClientExec.execute(route, request, context, execAware);
342 Mockito.verify(managedConn, Mockito.never()).setSocketTimeout(Mockito.anyInt());
343 }
344
345 @Test(expected=RequestAbortedException.class)
346 public void testExecAbortedPriorToConnectionLease() throws Exception {
347 final HttpRoute route = new HttpRoute(target);
348 final HttpClientContext context = new HttpClientContext();
349 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
350
351 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.FALSE);
352 Mockito.when(execAware.isAborted()).thenReturn(Boolean.TRUE);
353 try {
354 mainClientExec.execute(route, request, context, execAware);
355 } catch (final IOException ex) {
356 Mockito.verify(connRequest, Mockito.times(1)).cancel();
357 throw ex;
358 }
359 }
360
361 @Test(expected=RequestAbortedException.class)
362 public void testExecAbortedPriorToConnectionSetup() throws Exception {
363 final HttpRoute route = new HttpRoute(target);
364 final HttpClientContext context = new HttpClientContext();
365 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
366
367 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.FALSE);
368 Mockito.when(execAware.isAborted()).thenReturn(Boolean.FALSE, Boolean.TRUE);
369 try {
370 mainClientExec.execute(route, request, context, execAware);
371 } catch (final IOException ex) {
372 Mockito.verify(connRequest, Mockito.times(1)).get(0, TimeUnit.MILLISECONDS);
373 Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
374 Mockito.verify(connManager, Mockito.never()).connect(
375 Mockito.same(managedConn),
376 Mockito.<HttpRoute>any(),
377 Mockito.anyInt(),
378 Mockito.<HttpContext>any());
379 throw ex;
380 }
381 }
382
383 @Test(expected=RequestAbortedException.class)
384 public void testExecAbortedPriorToRequestExecution() throws Exception {
385 final HttpRoute route = new HttpRoute(target);
386 final HttpClientContext context = new HttpClientContext();
387 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
388
389 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.FALSE);
390 Mockito.when(execAware.isAborted()).thenReturn(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE);
391 try {
392 mainClientExec.execute(route, request, context, execAware);
393 } catch (final IOException ex) {
394 Mockito.verify(connRequest, Mockito.times(1)).get(0, TimeUnit.MILLISECONDS);
395 Mockito.verify(connManager, Mockito.times(1)).connect(managedConn, route, 0, context);
396 Mockito.verify(requestExecutor, Mockito.never()).execute(
397 Mockito.same(request),
398 Mockito.<HttpClientConnection>any(),
399 Mockito.<HttpClientContext>any());
400 throw ex;
401 }
402 }
403
404 @Test(expected=RequestAbortedException.class)
405 public void testExecConnectionRequestFailed() throws Exception {
406 final HttpRoute route = new HttpRoute(target);
407 final HttpClientContext context = new HttpClientContext();
408 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
409
410 Mockito.when(connRequest.get(Mockito.anyInt(), Mockito.<TimeUnit>any()))
411 .thenThrow(new ExecutionException("Opppsie", null));
412 mainClientExec.execute(route, request, context, execAware);
413 }
414
415 @Test
416 public void testExecRequestRetryOnAuthChallenge() throws Exception {
417 final HttpRoute route = new HttpRoute(target);
418 final HttpClientContext context = new HttpClientContext();
419 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
420 final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
421 final InputStream inStream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
422 response1.setEntity(EntityBuilder.create()
423 .setStream(inStream1)
424 .build());
425 final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
426 final InputStream inStream2 = Mockito.spy(new ByteArrayInputStream(new byte[] {2, 3, 4}));
427 response2.setEntity(EntityBuilder.create()
428 .setStream(inStream2)
429 .build());
430
431 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
432 Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
433 Mockito.when(requestExecutor.execute(
434 Mockito.same(request),
435 Mockito.<HttpClientConnection>any(),
436 Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
437 Mockito.when(reuseStrategy.keepAlive(
438 Mockito.<HttpResponse>any(),
439 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
440 Mockito.when(targetAuthStrategy.isAuthenticationRequested(
441 Mockito.eq(target),
442 Mockito.same(response1),
443 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
444
445 final CloseableHttpResponse finalResponse = mainClientExec.execute(
446 route, request, context, execAware);
447 Mockito.verify(requestExecutor, Mockito.times(2)).execute(request, managedConn, context);
448 Mockito.verify(inStream1).close();
449 Mockito.verify(inStream2, Mockito.never()).close();
450
451 Assert.assertNotNull(finalResponse);
452 Assert.assertEquals(200, finalResponse.getStatusLine().getStatusCode());
453 }
454
455 @Test
456 public void testExecEntityEnclosingRequestRetryOnAuthChallenge() throws Exception {
457 final HttpRoute route = new HttpRoute(target);
458 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
459 final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
460 final InputStream inStream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
461 response1.setEntity(EntityBuilder.create()
462 .setStream(inStream1)
463 .build());
464 final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
465 final InputStream inStream2 = Mockito.spy(new ByteArrayInputStream(new byte[] {2, 3, 4}));
466 response2.setEntity(EntityBuilder.create()
467 .setStream(inStream2)
468 .build());
469
470 final AuthState proxyAuthState = new AuthState();
471 proxyAuthState.setState(AuthProtocolState.SUCCESS);
472 proxyAuthState.update(new NTLMScheme(), new NTCredentials("user:pass"));
473
474 final HttpClientContext context = new HttpClientContext();
475 context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, proxyAuthState);
476
477 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
478 Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
479 Mockito.when(requestExecutor.execute(
480 Mockito.same(request),
481 Mockito.<HttpClientConnection>any(),
482 Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
483 Mockito.when(reuseStrategy.keepAlive(
484 Mockito.<HttpResponse>any(),
485 Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
486 Mockito.when(targetAuthStrategy.isAuthenticationRequested(
487 Mockito.eq(target),
488 Mockito.same(response1),
489 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
490
491 final CloseableHttpResponse finalResponse = mainClientExec.execute(
492 route, request, context, execAware);
493 Mockito.verify(requestExecutor, Mockito.times(2)).execute(request, managedConn, context);
494 Mockito.verify(managedConn).close();
495 Mockito.verify(inStream2, Mockito.never()).close();
496
497 Assert.assertNotNull(finalResponse);
498 Assert.assertEquals(200, finalResponse.getStatusLine().getStatusCode());
499 Assert.assertNull(proxyAuthState.getAuthScheme());
500 Assert.assertNull(proxyAuthState.getCredentials());
501 }
502
503 @Test(expected = NonRepeatableRequestException.class)
504 public void testExecEntityEnclosingRequest() throws Exception {
505 final HttpRoute route = new HttpRoute(target);
506 final HttpClientContext context = new HttpClientContext();
507 final HttpPost post = new HttpPost("http://bar/test");
508 final InputStream inStream0 = new ByteArrayInputStream(new byte[] {1, 2, 3});
509 post.setEntity(EntityBuilder.create()
510 .setStream(inStream0)
511 .build());
512 final HttpRequestWrapper request = HttpRequestWrapper.wrap(post);
513
514 final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
515 final InputStream inStream1 = new ByteArrayInputStream(new byte[] {1, 2, 3});
516 response1.setEntity(EntityBuilder.create()
517 .setStream(inStream1)
518 .build());
519
520 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
521 Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
522 Mockito.when(requestExecutor.execute(
523 Mockito.same(request),
524 Mockito.<HttpClientConnection>any(),
525 Mockito.<HttpClientContext>any())).thenAnswer(new Answer<HttpResponse>() {
526
527 @Override
528 public HttpResponse answer(final InvocationOnMock invocationOnMock) throws Throwable {
529 final Object[] args = invocationOnMock.getArguments();
530 final HttpEntityEnclosingRequest requestEE = (HttpEntityEnclosingRequest) args[0];
531 requestEE.getEntity().writeTo(new ByteArrayOutputStream());
532 return response1;
533 }
534
535 });
536 Mockito.when(reuseStrategy.keepAlive(
537 Mockito.<HttpResponse>any(),
538 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
539 Mockito.when(targetAuthStrategy.isAuthenticationRequested(
540 Mockito.eq(target),
541 Mockito.same(response1),
542 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
543
544 mainClientExec.execute(route, request, context, execAware);
545 }
546
547 @Test(expected=InterruptedIOException.class)
548 public void testExecConnectionShutDown() throws Exception {
549 final HttpRoute route = new HttpRoute(target);
550 final HttpClientContext context = new HttpClientContext();
551 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
552
553 Mockito.when(requestExecutor.execute(
554 Mockito.<HttpRequest>any(),
555 Mockito.<HttpClientConnection>any(),
556 Mockito.<HttpClientContext>any())).thenThrow(new ConnectionShutdownException());
557
558 mainClientExec.execute(route, request, context, execAware);
559 }
560
561 @Test(expected=RuntimeException.class)
562 public void testExecRuntimeException() throws Exception {
563 final HttpRoute route = new HttpRoute(target);
564 final HttpClientContext context = new HttpClientContext();
565 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
566
567 Mockito.when(requestExecutor.execute(
568 Mockito.<HttpRequest>any(),
569 Mockito.<HttpClientConnection>any(),
570 Mockito.<HttpClientContext>any())).thenThrow(new RuntimeException("Ka-boom"));
571
572 try {
573 mainClientExec.execute(route, request, context, execAware);
574 } catch (final Exception ex) {
575 Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
576
577 throw ex;
578 }
579 }
580
581 @Test(expected=HttpException.class)
582 public void testExecHttpException() throws Exception {
583 final HttpRoute route = new HttpRoute(target);
584 final HttpClientContext context = new HttpClientContext();
585 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
586
587 Mockito.when(requestExecutor.execute(
588 Mockito.<HttpRequest>any(),
589 Mockito.<HttpClientConnection>any(),
590 Mockito.<HttpClientContext>any())).thenThrow(new HttpException("Ka-boom"));
591
592 try {
593 mainClientExec.execute(route, request, context, execAware);
594 } catch (final Exception ex) {
595 Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
596
597 throw ex;
598 }
599 }
600
601 @Test(expected=IOException.class)
602 public void testExecIOException() throws Exception {
603 final HttpRoute route = new HttpRoute(target);
604 final HttpClientContext context = new HttpClientContext();
605 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
606
607 Mockito.when(requestExecutor.execute(
608 Mockito.<HttpRequest>any(),
609 Mockito.<HttpClientConnection>any(),
610 Mockito.<HttpClientContext>any())).thenThrow(new IOException("Ka-boom"));
611
612 try {
613 mainClientExec.execute(route, request, context, execAware);
614 } catch (final Exception ex) {
615 Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
616
617 throw ex;
618 }
619 }
620
621 @Test
622 public void testEstablishDirectRoute() throws Exception {
623 final AuthState authState = new AuthState();
624 final HttpRoute route = new HttpRoute(target);
625 final HttpClientContext context = new HttpClientContext();
626 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
627
628 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
629
630 mainClientExec.establishRoute(authState, managedConn, route, request, context);
631
632 Mockito.verify(connManager).connect(managedConn, route, 0, context);
633 Mockito.verify(connManager).routeComplete(managedConn, route, context);
634 }
635
636 @Test
637 public void testEstablishRouteDirectProxy() throws Exception {
638 final AuthState authState = new AuthState();
639 final HttpRoute route = new HttpRoute(target, null, proxy, false);
640 final HttpClientContext context = new HttpClientContext();
641 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
642
643 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
644
645 mainClientExec.establishRoute(authState, managedConn, route, request, context);
646
647 Mockito.verify(connManager).connect(managedConn, route, 0, context);
648 Mockito.verify(connManager).routeComplete(managedConn, route, context);
649 }
650
651 @Test
652 public void testEstablishRouteViaProxyTunnel() throws Exception {
653 final AuthState authState = new AuthState();
654 final HttpRoute route = new HttpRoute(target, null, proxy, true);
655 final HttpClientContext context = new HttpClientContext();
656 final RequestConfig config = RequestConfig.custom()
657 .setConnectTimeout(321)
658 .build();
659 context.setRequestConfig(config);
660 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
661 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
662
663 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
664 Mockito.when(requestExecutor.execute(
665 Mockito.<HttpRequest>any(),
666 Mockito.<HttpClientConnection>any(),
667 Mockito.<HttpClientContext>any())).thenReturn(response);
668
669 mainClientExec.establishRoute(authState, managedConn, route, request, context);
670
671 Mockito.verify(connManager).connect(managedConn, route, 321, context);
672 Mockito.verify(connManager).routeComplete(managedConn, route, context);
673 final ArgumentCaptor<HttpRequest> reqCaptor = ArgumentCaptor.forClass(HttpRequest.class);
674 Mockito.verify(requestExecutor).execute(
675 reqCaptor.capture(),
676 Mockito.same(managedConn),
677 Mockito.same(context));
678 final HttpRequest connect = reqCaptor.getValue();
679 Assert.assertNotNull(connect);
680 Assert.assertEquals("CONNECT", connect.getRequestLine().getMethod());
681 Assert.assertEquals(HttpVersion.HTTP_1_1, connect.getRequestLine().getProtocolVersion());
682 Assert.assertEquals("foo:80", connect.getRequestLine().getUri());
683 }
684
685 @Test(expected = HttpException.class)
686 public void testEstablishRouteViaProxyTunnelUnexpectedResponse() throws Exception {
687 final AuthState authState = new AuthState();
688 final HttpRoute route = new HttpRoute(target, null, proxy, true);
689 final HttpClientContext context = new HttpClientContext();
690 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
691 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 101, "Lost");
692
693 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
694 Mockito.when(requestExecutor.execute(
695 Mockito.<HttpRequest>any(),
696 Mockito.<HttpClientConnection>any(),
697 Mockito.<HttpClientContext>any())).thenReturn(response);
698
699 mainClientExec.establishRoute(authState, managedConn, route, request, context);
700 }
701
702 @Test(expected = HttpException.class)
703 public void testEstablishRouteViaProxyTunnelFailure() throws Exception {
704 final AuthState authState = new AuthState();
705 final HttpRoute route = new HttpRoute(target, null, proxy, true);
706 final HttpClientContext context = new HttpClientContext();
707 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
708 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 500, "Boom");
709 response.setEntity(new StringEntity("Ka-boom"));
710
711 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
712 Mockito.when(requestExecutor.execute(
713 Mockito.<HttpRequest>any(),
714 Mockito.<HttpClientConnection>any(),
715 Mockito.<HttpClientContext>any())).thenReturn(response);
716
717 try {
718 mainClientExec.establishRoute(authState, managedConn, route, request, context);
719 } catch (final TunnelRefusedException ex) {
720 final HttpResponse r = ex.getResponse();
721 Assert.assertEquals("Ka-boom", EntityUtils.toString(r.getEntity()));
722
723 Mockito.verify(managedConn).close();
724
725 throw ex;
726 }
727 }
728
729 @Test
730 public void testEstablishRouteViaProxyTunnelRetryOnAuthChallengePersistentConnection() throws Exception {
731 final AuthState authState = new AuthState();
732 final HttpRoute route = new HttpRoute(target, null, proxy, true);
733 final HttpClientContext context = new HttpClientContext();
734 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
735 final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
736 final InputStream inStream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
737 response1.setEntity(EntityBuilder.create()
738 .setStream(inStream1)
739 .build());
740 final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
741
742 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
743 Mockito.when(proxyAuthStrategy.isAuthenticationRequested(
744 Mockito.eq(proxy),
745 Mockito.same(response1),
746 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
747 Mockito.when(reuseStrategy.keepAlive(
748 Mockito.<HttpResponse>any(),
749 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
750 Mockito.when(requestExecutor.execute(
751 Mockito.<HttpRequest>any(),
752 Mockito.<HttpClientConnection>any(),
753 Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
754
755 mainClientExec.establishRoute(authState, managedConn, route, request, context);
756
757 Mockito.verify(connManager).connect(managedConn, route, 0, context);
758 Mockito.verify(connManager).routeComplete(managedConn, route, context);
759 Mockito.verify(inStream1).close();
760 }
761
762 @Test
763 public void testEstablishRouteViaProxyTunnelRetryOnAuthChallengeNonPersistentConnection() throws Exception {
764 final AuthState authState = new AuthState();
765 final HttpRoute route = new HttpRoute(target, null, proxy, true);
766 final HttpClientContext context = new HttpClientContext();
767 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
768 final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
769 final InputStream inStream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
770 response1.setEntity(EntityBuilder.create()
771 .setStream(inStream1)
772 .build());
773 final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
774
775 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
776 Mockito.when(proxyAuthStrategy.isAuthenticationRequested(
777 Mockito.eq(proxy),
778 Mockito.same(response1),
779 Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
780 Mockito.when(reuseStrategy.keepAlive(
781 Mockito.<HttpResponse>any(),
782 Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
783 Mockito.when(requestExecutor.execute(
784 Mockito.<HttpRequest>any(),
785 Mockito.<HttpClientConnection>any(),
786 Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
787
788 mainClientExec.establishRoute(authState, managedConn, route, request, context);
789
790 Mockito.verify(connManager).connect(managedConn, route, 0, context);
791 Mockito.verify(connManager).routeComplete(managedConn, route, context);
792 Mockito.verify(inStream1, Mockito.never()).close();
793 Mockito.verify(managedConn).close();
794 }
795
796 @Test(expected = HttpException.class)
797 public void testEstablishRouteViaProxyTunnelMultipleHops() throws Exception {
798 final AuthState authState = new AuthState();
799 final HttpHost proxy1 = new HttpHost("this", 8888);
800 final HttpHost proxy2 = new HttpHost("that", 8888);
801 final HttpRoute route = new HttpRoute(target, null, new HttpHost[] {proxy1, proxy2},
802 true, RouteInfo.TunnelType.TUNNELLED, RouteInfo.LayerType.LAYERED);
803 final HttpClientContext context = new HttpClientContext();
804 final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
805
806 Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
807
808 mainClientExec.establishRoute(authState, managedConn, route, request, context);
809 }
810
811 }