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.nio.integration;
29  
30  import java.io.IOException;
31  import java.net.InetSocketAddress;
32  import java.util.Arrays;
33  import java.util.Collection;
34  import java.util.Queue;
35  import java.util.concurrent.ConcurrentLinkedQueue;
36  import java.util.concurrent.Future;
37  import java.util.concurrent.TimeUnit;
38  
39  import org.apache.http.HttpException;
40  import org.apache.http.HttpHeaders;
41  import org.apache.http.HttpHost;
42  import org.apache.http.HttpRequest;
43  import org.apache.http.HttpRequestInterceptor;
44  import org.apache.http.HttpResponse;
45  import org.apache.http.HttpStatus;
46  import org.apache.http.HttpVersion;
47  import org.apache.http.ProtocolVersion;
48  import org.apache.http.entity.ContentType;
49  import org.apache.http.message.BasicHttpEntityEnclosingRequest;
50  import org.apache.http.message.BasicHttpRequest;
51  import org.apache.http.message.BasicHttpResponse;
52  import org.apache.http.nio.entity.NStringEntity;
53  import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
54  import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
55  import org.apache.http.nio.protocol.BasicAsyncResponseProducer;
56  import org.apache.http.nio.protocol.HttpAsyncExchange;
57  import org.apache.http.nio.protocol.HttpAsyncExpectationVerifier;
58  import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
59  import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
60  import org.apache.http.nio.reactor.ListenerEndpoint;
61  import org.apache.http.nio.testserver.HttpCoreNIOTestBase;
62  import org.apache.http.protocol.BasicHttpContext;
63  import org.apache.http.protocol.HTTP;
64  import org.apache.http.protocol.HttpContext;
65  import org.apache.http.protocol.HttpRequestHandler;
66  import org.apache.http.protocol.ImmutableHttpProcessor;
67  import org.apache.http.protocol.RequestConnControl;
68  import org.apache.http.protocol.RequestExpectContinue;
69  import org.apache.http.protocol.RequestTargetHost;
70  import org.apache.http.protocol.RequestUserAgent;
71  import org.apache.http.protocol.ResponseServer;
72  import org.apache.http.util.EntityUtils;
73  import org.junit.After;
74  import org.junit.Assert;
75  import org.junit.Before;
76  import org.junit.Test;
77  import org.junit.runner.RunWith;
78  import org.junit.runners.Parameterized;
79  
80  /**
81   * HttpCore NIO integration tests for async handlers.
82   */
83  @RunWith(Parameterized.class)
84  public class TestHttpAsyncHandlers extends HttpCoreNIOTestBase {
85  
86      private final static long RESULT_TIMEOUT_SEC = 30;
87      private final static int REQ_NUM = 25;
88  
89      @Parameterized.Parameters(name = "{0}")
90      public static Collection<Object[]> protocols() {
91          return Arrays.asList(new Object[][]{
92                  { ProtocolScheme.http },
93                  { ProtocolScheme.https },
94          });
95      }
96  
97      public TestHttpAsyncHandlers(final ProtocolScheme scheme) {
98          super(scheme);
99      }
100 
101     @Before
102     public void setUp() throws Exception {
103         initServer();
104         initClient();
105     }
106 
107     @After
108     public void tearDown() throws Exception {
109         shutDownClient();
110         shutDownServer();
111     }
112 
113     private HttpHost start() throws IOException, InterruptedException {
114         this.server.start();
115         this.client.start();
116 
117         final ListenerEndpoint endpoint = this.server.getListenerEndpoint();
118         endpoint.waitFor();
119 
120         final InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
121         return new HttpHost("localhost", address.getPort(), getScheme().name());
122     }
123 
124     private static String createRequestUri(final String pattern, final int count) {
125         return pattern + "x" + count;
126     }
127 
128     private static String createExpectedString(final String pattern, final int count) {
129         final StringBuilder buffer = new StringBuilder();
130         for (int i = 0; i < count; i++) {
131             buffer.append(pattern);
132         }
133         return buffer.toString();
134     }
135 
136     @Test
137     public void testHttpGets() throws Exception {
138         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
139         final HttpHost target = start();
140 
141         this.client.setMaxPerRoute(3);
142         this.client.setMaxTotal(3);
143 
144         final String pattern = RndTestPatternGenerator.generateText();
145         final int count = RndTestPatternGenerator.generateCount(1000);
146 
147         final String expectedPattern = createExpectedString(pattern, count);
148 
149         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
150         for (int i = 0; i < REQ_NUM; i++) {
151             final BasicHttpRequest request = new BasicHttpRequest("GET", createRequestUri(pattern, count));
152             final Future<HttpResponse> future = this.client.execute(target, request);
153             queue.add(future);
154         }
155 
156         while (!queue.isEmpty()) {
157             final Future<HttpResponse> future = queue.remove();
158             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
159             Assert.assertNotNull(response);
160             Assert.assertEquals(expectedPattern, EntityUtils.toString(response.getEntity()));
161         }
162     }
163 
164     @Test
165     public void testHttpGetsCloseConnection() throws Exception {
166         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
167         final HttpHost target = start();
168 
169         this.client.setMaxPerRoute(3);
170         this.client.setMaxTotal(3);
171 
172         final String pattern = RndTestPatternGenerator.generateText();
173         final int count = RndTestPatternGenerator.generateCount(1000);
174 
175         final String expectedPattern = createExpectedString(pattern, count);
176 
177         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
178         for (int i = 0; i < REQ_NUM; i++) {
179             final BasicHttpRequest request = new BasicHttpRequest("GET", createRequestUri(pattern, count));
180             request.addHeader(HttpHeaders.CONNECTION, "Close");
181             final Future<HttpResponse> future = this.client.execute(target, request);
182             queue.add(future);
183         }
184 
185         while (!queue.isEmpty()) {
186             final Future<HttpResponse> future = queue.remove();
187             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
188             Assert.assertNotNull(response);
189             Assert.assertEquals(expectedPattern, EntityUtils.toString(response.getEntity()));
190         }
191     }
192 
193     @Test
194     public void testHttpGetIdentityTransfer() throws Exception {
195         this.server.setHttpProcessor(new ImmutableHttpProcessor(new ResponseServer("TEST-SERVER/1.1")));
196         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
197         final HttpHost target = start();
198 
199         this.client.setMaxPerRoute(3);
200         this.client.setMaxTotal(3);
201 
202         final String pattern = RndTestPatternGenerator.generateText();
203         final int count = RndTestPatternGenerator.generateCount(1000);
204 
205         final String expectedPattern = createExpectedString(pattern, count);
206 
207         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
208         for (int i = 0; i < REQ_NUM; i++) {
209             final BasicHttpRequest request = new BasicHttpRequest("GET", createRequestUri(pattern, count));
210             final Future<HttpResponse> future = this.client.execute(target, request);
211             queue.add(future);
212         }
213 
214         while (!queue.isEmpty()) {
215             final Future<HttpResponse> future = queue.remove();
216             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
217             Assert.assertNotNull(response);
218             Assert.assertEquals(expectedPattern, EntityUtils.toString(response.getEntity()));
219         }
220     }
221 
222     @Test
223     public void testHttpHeads() throws Exception {
224         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
225         final HttpHost target = start();
226 
227         this.client.setMaxPerRoute(3);
228         this.client.setMaxTotal(3);
229 
230         final String pattern = RndTestPatternGenerator.generateText();
231         final int count = RndTestPatternGenerator.generateCount(1000);
232 
233         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
234         for (int i = 0; i < REQ_NUM; i++) {
235             final BasicHttpRequest request = new BasicHttpRequest("HEAD", createRequestUri(pattern, count));
236             final Future<HttpResponse> future = this.client.execute(target, request);
237             queue.add(future);
238         }
239 
240         while (!queue.isEmpty()) {
241             final Future<HttpResponse> future = queue.remove();
242             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
243             Assert.assertNotNull(response);
244             Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
245         }
246     }
247 
248     @Test
249     public void testHttpHeadsCloseConnection() throws Exception {
250         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
251         final HttpHost target = start();
252 
253         this.client.setMaxPerRoute(3);
254         this.client.setMaxTotal(3);
255 
256         final String pattern = RndTestPatternGenerator.generateText();
257         final int count = RndTestPatternGenerator.generateCount(1000);
258 
259         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
260         for (int i = 0; i < REQ_NUM; i++) {
261             final BasicHttpRequest request = new BasicHttpRequest("HEAD", createRequestUri(pattern, count));
262             request.addHeader(HttpHeaders.CONNECTION, "Close");
263             final Future<HttpResponse> future = this.client.execute(target, request);
264             queue.add(future);
265         }
266 
267         while (!queue.isEmpty()) {
268             final Future<HttpResponse> future = queue.remove();
269             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
270             Assert.assertNotNull(response);
271             Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
272             Assert.assertNull(response.getEntity());
273         }
274     }
275 
276     @Test
277     public void testHttpPostsWithContentLength() throws Exception {
278         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
279         final HttpHost target = start();
280 
281         this.client.setMaxPerRoute(3);
282         this.client.setMaxTotal(3);
283 
284         final String pattern = RndTestPatternGenerator.generateText();
285         final int count = RndTestPatternGenerator.generateCount(1000);
286 
287         final String expectedPattern = createExpectedString(pattern, count);
288 
289         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
290         for (int i = 0; i < REQ_NUM; i++) {
291             final BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest(
292                     "POST", createRequestUri(pattern, count));
293             final NStringEntity entity = new NStringEntity(expectedPattern, ContentType.DEFAULT_TEXT);
294             request.setEntity(entity);
295             final Future<HttpResponse> future = this.client.execute(target, request);
296             queue.add(future);
297         }
298 
299         while (!queue.isEmpty()) {
300             final Future<HttpResponse> future = queue.remove();
301             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
302             Assert.assertNotNull(response);
303             Assert.assertEquals(expectedPattern, EntityUtils.toString(response.getEntity()));
304         }
305     }
306 
307     @Test
308     public void testHttpPostsChunked() throws Exception {
309         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
310         final HttpHost target = start();
311 
312         this.client.setMaxPerRoute(3);
313         this.client.setMaxTotal(3);
314 
315         final String pattern = RndTestPatternGenerator.generateText();
316         final int count = RndTestPatternGenerator.generateCount(1000);
317 
318         final String expectedPattern = createExpectedString(pattern, count);
319 
320         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
321         for (int i = 0; i < REQ_NUM; i++) {
322             final BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest(
323                     "POST", createRequestUri(pattern, count));
324             final NStringEntity entity = new NStringEntity(expectedPattern, ContentType.DEFAULT_TEXT);
325             entity.setChunked(true);
326             request.setEntity(entity);
327             final Future<HttpResponse> future = this.client.execute(target, request);
328             queue.add(future);
329         }
330 
331         while (!queue.isEmpty()) {
332             final Future<HttpResponse> future = queue.remove();
333             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
334             Assert.assertNotNull(response);
335             Assert.assertEquals(expectedPattern, EntityUtils.toString(response.getEntity()));
336         }
337     }
338 
339     @Test
340     public void testHttpPostsHTTP10() throws Exception {
341         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
342         final HttpHost target = start();
343 
344         this.client.setMaxPerRoute(3);
345         this.client.setMaxTotal(3);
346 
347         final String pattern = RndTestPatternGenerator.generateText();
348         final int count = RndTestPatternGenerator.generateCount(1000);
349 
350         final String expectedPattern = createExpectedString(pattern, count);
351 
352         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
353         for (int i = 0; i < REQ_NUM; i++) {
354             final BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest(
355                     "POST", createRequestUri(pattern, count), HttpVersion.HTTP_1_0);
356             final NStringEntity entity = new NStringEntity(expectedPattern, ContentType.DEFAULT_TEXT);
357             request.setEntity(entity);
358             final Future<HttpResponse> future = this.client.execute(target, request);
359             queue.add(future);
360         }
361 
362         while (!queue.isEmpty()) {
363             final Future<HttpResponse> future = queue.remove();
364             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
365             Assert.assertNotNull(response);
366             Assert.assertEquals(expectedPattern, EntityUtils.toString(response.getEntity()));
367         }
368     }
369 
370     @Test
371     public void testHttpPostsNoEntity() throws Exception {
372         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
373         final HttpHost target = start();
374 
375         this.client.setMaxPerRoute(3);
376         this.client.setMaxTotal(3);
377 
378         final String pattern = RndTestPatternGenerator.generateText();
379         final int count = RndTestPatternGenerator.generateCount(1000);
380 
381         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
382         for (int i = 0; i < REQ_NUM; i++) {
383             final BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest(
384                     "POST", createRequestUri(pattern, count));
385             request.setEntity(null);
386             final Future<HttpResponse> future = this.client.execute(target, request);
387             queue.add(future);
388         }
389 
390         while (!queue.isEmpty()) {
391             final Future<HttpResponse> future = queue.remove();
392             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
393             Assert.assertNotNull(response);
394             Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
395         }
396     }
397 
398     @Test
399     public void testHttpPostNoContentLength() throws Exception {
400         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
401 
402         this.client.setHttpProcessor(new ImmutableHttpProcessor(
403                 new RequestTargetHost(),
404                 new RequestConnControl(),
405                 new RequestUserAgent(),
406                 new RequestExpectContinue(true)));
407 
408         final HttpHost target = start();
409 
410         this.client.setMaxPerRoute(3);
411         this.client.setMaxTotal(3);
412 
413         final String pattern = RndTestPatternGenerator.generateText();
414         final int count = RndTestPatternGenerator.generateCount(1000);
415 
416         final BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest(
417                 "POST", createRequestUri(pattern, count));
418         request.setEntity(null);
419 
420         final Future<HttpResponse> future = this.client.execute(target, request);
421 
422         final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
423         Assert.assertNotNull(response);
424         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
425     }
426 
427     @Test
428     public void testHttpPostIdentity() throws Exception {
429         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
430 
431         this.client.setHttpProcessor(new ImmutableHttpProcessor(
432                 new HttpRequestInterceptor() {
433 
434                     @Override
435                     public void process(
436                             final HttpRequest request,
437                             final HttpContext context) throws HttpException, IOException {
438                         request.addHeader(HTTP.TRANSFER_ENCODING, "identity");
439                     }
440 
441                 },
442                 new RequestTargetHost(),
443                 new RequestConnControl(),
444                 new RequestUserAgent(),
445                 new RequestExpectContinue(true)));
446 
447         final HttpHost target = start();
448 
449         this.client.setMaxPerRoute(3);
450         this.client.setMaxTotal(3);
451 
452         final String pattern = RndTestPatternGenerator.generateText();
453         final int count = RndTestPatternGenerator.generateCount(1000);
454 
455         final BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest(
456                 "POST", createRequestUri(pattern, count));
457         request.setEntity(null);
458 
459         final Future<HttpResponse> future = this.client.execute(target, request);
460 
461         final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
462         Assert.assertNotNull(response);
463         Assert.assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatusLine().getStatusCode());
464     }
465 
466     @Test
467     public void testHttpPostsWithExpectContinue() throws Exception {
468         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
469         final HttpHost target = start();
470 
471         this.client.setMaxPerRoute(3);
472         this.client.setMaxTotal(3);
473 
474         final String pattern = RndTestPatternGenerator.generateText();
475         final int count = RndTestPatternGenerator.generateCount(1000);
476 
477         final String expectedPattern = createExpectedString(pattern, count);
478 
479         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
480         for (int i = 0; i < REQ_NUM; i++) {
481             final BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest(
482                     "POST", createRequestUri(pattern, count));
483             final NStringEntity entity = new NStringEntity(expectedPattern, ContentType.DEFAULT_TEXT);
484             request.setEntity(entity);
485 
486             final HttpContext context = new BasicHttpContext();
487             final Future<HttpResponse> future = this.client.execute(target, request, context);
488             queue.add(future);
489         }
490 
491         while (!queue.isEmpty()) {
492             final Future<HttpResponse> future = queue.remove();
493             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
494             Assert.assertNotNull(response);
495             Assert.assertEquals(expectedPattern, EntityUtils.toString(response.getEntity()));
496         }
497     }
498 
499     @Test
500     public void testHttpPostsWithExpectationVerification() throws Exception {
501         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
502         this.server.setExpectationVerifier(new HttpAsyncExpectationVerifier() {
503 
504             @Override
505             public void verify(
506                     final HttpAsyncExchange httpexchange,
507                     final HttpContext context) throws HttpException {
508                 final HttpRequest request = httpexchange.getRequest();
509                 ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
510                 final String s = request.getRequestLine().getUri();
511                 if (!s.equals("AAAAAx10")) {
512                     if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
513                         ver = HttpVersion.HTTP_1_1;
514                     }
515                     final BasicHttpResponse response = new BasicHttpResponse(ver,
516                             HttpStatus.SC_EXPECTATION_FAILED, "Expectation failed");
517                     response.setEntity(new NStringEntity("Expectation failed", ContentType.TEXT_PLAIN));
518                     httpexchange.submitResponse(new BasicAsyncResponseProducer(response));
519                 } else {
520                     httpexchange.submitResponse();
521                 }
522             }
523 
524         });
525 
526         final HttpHost target = start();
527 
528         final BasicHttpEntityEnclosingRequest request1 = new BasicHttpEntityEnclosingRequest(
529                 "POST", createRequestUri("AAAAA", 10));
530         request1.setEntity(new NStringEntity(createExpectedString("AAAAA", 10)));
531         final BasicHttpEntityEnclosingRequest request2 = new BasicHttpEntityEnclosingRequest(
532                 "POST", createRequestUri("AAAAA", 10));
533         request2.setEntity(new NStringEntity(createExpectedString("AAAAA", 10)));
534         final BasicHttpEntityEnclosingRequest request3 = new BasicHttpEntityEnclosingRequest(
535                 "POST", createRequestUri("BBBBB", 10));
536         request3.setEntity(new NStringEntity(createExpectedString("BBBBB", 10)));
537 
538         final HttpRequest[] requests = new HttpRequest[] { request1, request2, request3 };
539 
540         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
541         for (final HttpRequest request : requests) {
542             final HttpContext context = new BasicHttpContext();
543             final Future<HttpResponse> future = this.client.execute(target, request, context);
544             queue.add(future);
545         }
546 
547         final Future<HttpResponse> future1 = queue.remove();
548         final HttpResponse response1 = future1.get();
549         Assert.assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
550 
551         final Future<HttpResponse> future2 = queue.remove();
552         final HttpResponse response2 = future2.get();
553         Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
554 
555         final Future<HttpResponse> future3 = queue.remove();
556         final HttpResponse response3 = future3.get();
557         Assert.assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response3.getStatusLine().getStatusCode());
558     }
559 
560     @Test
561     public void testHttpHeadsDelayedResponse() throws Exception {
562 
563         class DelayedRequestHandler implements HttpAsyncRequestHandler<HttpRequest> {
564 
565             private final SimpleRequestHandler requestHandler;
566 
567             public DelayedRequestHandler() {
568                 super();
569                 this.requestHandler = new SimpleRequestHandler();
570             }
571 
572             @Override
573             public HttpAsyncRequestConsumer<HttpRequest> processRequest(
574                     final HttpRequest request,
575                     final HttpContext context) {
576                 return new BasicAsyncRequestConsumer();
577             }
578 
579             @Override
580             public void handle(
581                     final HttpRequest request,
582                     final HttpAsyncExchange httpexchange,
583                     final HttpContext context) throws HttpException, IOException {
584                 ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
585                 if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
586                     ver = HttpVersion.HTTP_1_1;
587                 }
588                 final BasicHttpResponse response = new BasicHttpResponse(ver, HttpStatus.SC_OK, "OK");
589                 new Thread() {
590                     @Override
591                     public void run() {
592                         // Wait a bit, to make sure this is delayed.
593                         try { Thread.sleep(100); } catch(final InterruptedException ie) {}
594                         // Set the entity after delaying...
595                         try {
596                             requestHandler.handle(request, response, context);
597                         } catch (final Exception ex) {
598                             response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
599                         }
600                         httpexchange.submitResponse(new BasicAsyncResponseProducer(response));
601                     }
602                 }.start();
603             }
604 
605         }
606 
607         this.server.registerHandler("*", new DelayedRequestHandler());
608         final HttpHost target = start();
609 
610         this.client.setMaxPerRoute(3);
611         this.client.setMaxTotal(3);
612 
613         final String pattern = RndTestPatternGenerator.generateText();
614         final int count = RndTestPatternGenerator.generateCount(1000);
615 
616         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
617         for (int i = 0; i < REQ_NUM; i++) {
618             final BasicHttpRequest request = new BasicHttpRequest("HEAD", createRequestUri(pattern, count));
619             final Future<HttpResponse> future = this.client.execute(target, request);
620             queue.add(future);
621         }
622 
623         while (!queue.isEmpty()) {
624             final Future<HttpResponse> future = queue.remove();
625             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
626             Assert.assertNotNull(response);
627             Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
628         }
629     }
630 
631     @Test
632     public void testHttpPostsWithExpectationVerificationDelayedResponse() throws Exception {
633         this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
634         this.server.setExpectationVerifier(new HttpAsyncExpectationVerifier() {
635 
636             @Override
637             public void verify(
638                     final HttpAsyncExchange httpexchange,
639                     final HttpContext context) throws HttpException {
640                 new Thread() {
641                     @Override
642                     public void run() {
643                         // Wait a bit, to make sure this is delayed.
644                         try {
645                             Thread.sleep(100);
646                         } catch (final InterruptedException ie) {
647                         }
648                         // Set the entity after delaying...
649                         final HttpRequest request = httpexchange.getRequest();
650                         ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
651                         final String s = request.getRequestLine().getUri();
652                         if (!s.equals("AAAAAx10")) {
653                             if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
654                                 ver = HttpVersion.HTTP_1_1;
655                             }
656                             final BasicHttpResponse response = new BasicHttpResponse(ver,
657                                     HttpStatus.SC_EXPECTATION_FAILED, "Expectation failed");
658                             response.setEntity(new NStringEntity("Expectation failed", ContentType.TEXT_PLAIN));
659                             httpexchange.submitResponse(new BasicAsyncResponseProducer(response));
660                         } else {
661                             httpexchange.submitResponse();
662                         }
663                     }
664                 }.start();
665             }
666 
667         });
668         final HttpHost target = start();
669 
670         final BasicHttpEntityEnclosingRequest request1 = new BasicHttpEntityEnclosingRequest(
671                 "POST", createRequestUri("AAAAA", 10));
672         request1.setEntity(new NStringEntity(createExpectedString("AAAAA", 10)));
673         final BasicHttpEntityEnclosingRequest request2 = new BasicHttpEntityEnclosingRequest(
674                 "POST", createRequestUri("AAAAA", 10));
675         request2.setEntity(new NStringEntity(createExpectedString("AAAAA", 10)));
676         final BasicHttpEntityEnclosingRequest request3 = new BasicHttpEntityEnclosingRequest(
677                 "POST", createRequestUri("BBBBB", 10));
678         request3.setEntity(new NStringEntity(createExpectedString("BBBBB", 10)));
679 
680         final HttpRequest[] requests = new HttpRequest[] { request1, request2, request3 };
681 
682         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
683         for (final HttpRequest request : requests) {
684             final HttpContext context = new BasicHttpContext();
685             final Future<HttpResponse> future = this.client.execute(target, request, context);
686             queue.add(future);
687         }
688 
689         final Future<HttpResponse> future1 = queue.remove();
690         final HttpResponse response1 = future1.get();
691         Assert.assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
692 
693         final Future<HttpResponse> future2 = queue.remove();
694         final HttpResponse response2 = future2.get();
695         Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
696 
697         final Future<HttpResponse> future3 = queue.remove();
698         final HttpResponse response3 = future3.get();
699         Assert.assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response3.getStatusLine().getStatusCode());
700     }
701 
702     @Test
703     public void testHttpExceptionInHandler() throws Exception {
704 
705         class FailingRequestHandler implements HttpAsyncRequestHandler<HttpRequest> {
706 
707             public FailingRequestHandler() {
708                 super();
709             }
710 
711             @Override
712             public HttpAsyncRequestConsumer<HttpRequest> processRequest(
713                     final HttpRequest request,
714                     final HttpContext context) {
715                 return new BasicAsyncRequestConsumer();
716             }
717 
718             @Override
719             public void handle(
720                     final HttpRequest request,
721                     final HttpAsyncExchange httpexchange,
722                     final HttpContext context) throws HttpException, IOException {
723                 throw new HttpException("Boom");
724             }
725 
726         }
727 
728         this.server.registerHandler("*", new FailingRequestHandler());
729         final HttpHost target = start();
730 
731         this.client.setMaxPerRoute(3);
732         this.client.setMaxTotal(3);
733 
734         final String pattern = RndTestPatternGenerator.generateText();
735         final int count = RndTestPatternGenerator.generateCount(1000);
736 
737         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
738         for (int i = 0; i < 1; i++) {
739             final BasicHttpRequest request = new BasicHttpRequest("GET", createRequestUri(pattern, count));
740             final Future<HttpResponse> future = this.client.execute(target, request);
741             queue.add(future);
742         }
743 
744         while (!queue.isEmpty()) {
745             final Future<HttpResponse> future = queue.remove();
746             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
747             Assert.assertNotNull(response);
748             Assert.assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatusLine().getStatusCode());
749         }
750     }
751 
752     @Test
753     public void testNoServiceHandler() throws Exception {
754         final HttpHost target = start();
755 
756         this.client.setMaxPerRoute(3);
757         this.client.setMaxTotal(3);
758 
759         final String pattern = RndTestPatternGenerator.generateText();
760         final int count = RndTestPatternGenerator.generateCount(1000);
761 
762         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
763         for (int i = 0; i < REQ_NUM; i++) {
764             final BasicHttpRequest request = new BasicHttpRequest("GET", createRequestUri(pattern, count));
765             final Future<HttpResponse> future = this.client.execute(target, request);
766             queue.add(future);
767         }
768 
769         while (!queue.isEmpty()) {
770             final Future<HttpResponse> future = queue.remove();
771             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
772             Assert.assertNotNull(response);
773             Assert.assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, response.getStatusLine().getStatusCode());
774         }
775     }
776 
777     @Test
778     public void testResponseNoContent() throws Exception {
779         this.server.registerHandler("*", new BasicAsyncRequestHandler(new HttpRequestHandler() {
780 
781             @Override
782             public void handle(
783                     final HttpRequest request,
784                     final HttpResponse response,
785                     final HttpContext context) throws HttpException, IOException {
786                 response.setStatusCode(HttpStatus.SC_NO_CONTENT);
787             }
788 
789         }));
790         final HttpHost target = start();
791 
792         this.client.setMaxPerRoute(3);
793         this.client.setMaxTotal(3);
794 
795         final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
796         for (int i = 0; i < REQ_NUM; i++) {
797             final BasicHttpRequest request = new BasicHttpRequest("GET", "/");
798             final Future<HttpResponse> future = this.client.execute(target, request);
799             queue.add(future);
800         }
801 
802         while (!queue.isEmpty()) {
803             final Future<HttpResponse> future = queue.remove();
804             final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
805             Assert.assertNotNull(response);
806             Assert.assertNull(response.getEntity());
807         }
808     }
809 
810 }