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  package org.apache.http.nio.client.integration;
28  
29  import java.io.IOException;
30  import java.net.UnknownHostException;
31  import java.util.concurrent.CountDownLatch;
32  import java.util.concurrent.ExecutionException;
33  import java.util.concurrent.Future;
34  import java.util.concurrent.TimeUnit;
35  import java.util.concurrent.atomic.AtomicBoolean;
36  import java.util.concurrent.atomic.AtomicInteger;
37  
38  import org.apache.http.HttpConnection;
39  import org.apache.http.HttpException;
40  import org.apache.http.HttpHost;
41  import org.apache.http.HttpRequest;
42  import org.apache.http.HttpResponse;
43  import org.apache.http.client.methods.HttpGet;
44  import org.apache.http.concurrent.FutureCallback;
45  import org.apache.http.entity.ContentType;
46  import org.apache.http.impl.nio.client.HttpAsyncClients;
47  import org.apache.http.localserver.EchoHandler;
48  import org.apache.http.localserver.HttpAsyncTestBase;
49  import org.apache.http.localserver.RandomHandler;
50  import org.apache.http.nio.ContentDecoder;
51  import org.apache.http.nio.ContentEncoder;
52  import org.apache.http.nio.IOControl;
53  import org.apache.http.nio.client.methods.HttpAsyncMethods;
54  import org.apache.http.nio.entity.NStringEntity;
55  import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
56  import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
57  import org.apache.http.nio.protocol.BasicAsyncRequestProducer;
58  import org.apache.http.nio.protocol.BasicAsyncResponseProducer;
59  import org.apache.http.nio.protocol.HttpAsyncExchange;
60  import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
61  import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
62  import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
63  import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
64  import org.apache.http.protocol.HttpContext;
65  import org.apache.http.protocol.HttpCoreContext;
66  import org.junit.Assert;
67  import org.junit.Test;
68  
69  public class TestHttpAsyncPrematureTermination extends HttpAsyncTestBase {
70  
71      @Test
72      public void testConnectionTerminatedProcessingRequest() throws Exception {
73          this.serverBootstrap.registerHandler("*", new HttpAsyncRequestHandler<HttpRequest>() {
74  
75              @Override
76              public HttpAsyncRequestConsumer<HttpRequest> processRequest(
77                      final HttpRequest request,
78                      final HttpContext context) throws HttpException, IOException {
79                  final HttpConnection conn = (HttpConnection) context.getAttribute(
80                          HttpCoreContext.HTTP_CONNECTION);
81                  conn.shutdown();
82                  return new BasicAsyncRequestConsumer();
83              }
84  
85              @Override
86              public void handle(
87                      final HttpRequest request,
88                      final HttpAsyncExchange httpExchange,
89                      final HttpContext context) throws HttpException, IOException {
90                  final HttpResponse response = httpExchange.getResponse();
91                  response.setEntity(new NStringEntity("all is well", ContentType.TEXT_PLAIN));
92                  httpExchange.submitResponse();
93              }
94  
95          });
96  
97          final HttpHost target = start();
98          final HttpGet httpget = new HttpGet("/");
99  
100         final CountDownLatch latch = new CountDownLatch(1);
101 
102         final FutureCallback<HttpResponse> callback = new FutureCallback<HttpResponse>() {
103 
104             @Override
105             public void cancelled() {
106                 latch.countDown();
107             }
108 
109             @Override
110             public void failed(final Exception ex) {
111                 latch.countDown();
112             }
113 
114             @Override
115             public void completed(final HttpResponse response) {
116                 Assert.fail();
117             }
118 
119         };
120 
121         this.httpclient.execute(target, httpget, callback);
122         Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
123     }
124 
125     @Test
126     public void testConnectionTerminatedHandlingRequest() throws Exception {
127         this.serverBootstrap.registerHandler("*", new HttpAsyncRequestHandler<HttpRequest>() {
128 
129             @Override
130             public HttpAsyncRequestConsumer<HttpRequest> processRequest(
131                     final HttpRequest request,
132                     final HttpContext context) throws HttpException, IOException {
133                 return new BasicAsyncRequestConsumer();
134             }
135 
136             @Override
137             public void handle(
138                     final HttpRequest request,
139                     final HttpAsyncExchange httpExchange,
140                     final HttpContext context) throws HttpException, IOException {
141                 final HttpConnection conn = (HttpConnection) context.getAttribute(
142                         HttpCoreContext.HTTP_CONNECTION);
143                 conn.shutdown();
144                 final HttpResponse response = httpExchange.getResponse();
145                 response.setEntity(new NStringEntity("all is well", ContentType.TEXT_PLAIN));
146                 httpExchange.submitResponse();
147             }
148 
149         });
150 
151         final HttpHost target = start();
152         final HttpGet httpget = new HttpGet("/");
153 
154         final CountDownLatch latch = new CountDownLatch(1);
155 
156         final FutureCallback<HttpResponse> callback = new FutureCallback<HttpResponse>() {
157 
158             @Override
159             public void cancelled() {
160                 latch.countDown();
161             }
162 
163             @Override
164             public void failed(final Exception ex) {
165                 latch.countDown();
166             }
167 
168             @Override
169             public void completed(final HttpResponse response) {
170                 Assert.fail();
171             }
172 
173         };
174 
175         this.httpclient.execute(target, httpget, callback);
176         Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
177     }
178 
179     @Test
180     public void testConnectionTerminatedSendingResponse() throws Exception {
181         this.serverBootstrap.registerHandler("*", new HttpAsyncRequestHandler<HttpRequest>() {
182 
183             @Override
184             public HttpAsyncRequestConsumer<HttpRequest> processRequest(
185                     final HttpRequest request,
186                     final HttpContext context) throws HttpException, IOException {
187                 return new BasicAsyncRequestConsumer();
188             }
189 
190             @Override
191             public void handle(
192                     final HttpRequest request,
193                     final HttpAsyncExchange httpExchange,
194                     final HttpContext context) throws HttpException, IOException {
195                 final HttpResponse response = httpExchange.getResponse();
196                 response.setEntity(new NStringEntity("all is well", ContentType.TEXT_PLAIN));
197                 httpExchange.submitResponse(new BasicAsyncResponseProducer(response) {
198 
199                     @Override
200                     public synchronized void produceContent(
201                             final ContentEncoder encoder,
202                             final IOControl ioctrl) throws IOException {
203                         ioctrl.shutdown();
204                     }
205 
206                 });
207             }
208 
209         });
210 
211         final HttpHost target = start();
212         final HttpGet httpget = new HttpGet("/");
213 
214         final CountDownLatch latch = new CountDownLatch(1);
215 
216         final FutureCallback<HttpResponse> callback = new FutureCallback<HttpResponse>() {
217 
218             @Override
219             public void cancelled() {
220                 latch.countDown();
221             }
222 
223             @Override
224             public void failed(final Exception ex) {
225                 latch.countDown();
226             }
227 
228             @Override
229             public void completed(final HttpResponse response) {
230                 Assert.fail();
231             }
232 
233         };
234 
235         this.httpclient.execute(target, httpget, callback);
236         Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
237     }
238 
239     @Test
240     public void testConnectionRequestFailure() throws Exception {
241         this.httpclient = HttpAsyncClients.custom()
242                 .setConnectionManager(this.connMgr)
243                 .build();
244         this.httpclient.start();
245 
246         final HttpGet get = new HttpGet("http://stuff.invalid/");
247         final HttpAsyncRequestProducer producer = HttpAsyncMethods.create(get);
248 
249         final AtomicBoolean closed = new AtomicBoolean(false);
250         final AtomicBoolean cancelled = new AtomicBoolean(false);
251         final AtomicBoolean failed = new AtomicBoolean(false);
252 
253         final HttpAsyncResponseConsumer<?> consumer = new HttpAsyncResponseConsumer<Object>() {
254 
255             @Override
256             public void close() throws IOException {
257                 closed.set(true);
258             }
259 
260             @Override
261             public boolean cancel() {
262                 cancelled.set(true);
263                 return false;
264             }
265 
266             @Override
267             public void failed(final Exception ex) {
268                 failed.set(true);
269             }
270 
271             @Override
272             public void responseReceived(
273                     final HttpResponse response) throws IOException, HttpException {
274                 throw new IllegalStateException();
275             }
276 
277             @Override
278             public void consumeContent(
279                     final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
280                 throw new IllegalStateException();
281             }
282 
283             @Override
284             public void responseCompleted(final HttpContext context) {
285                 throw new IllegalStateException();
286             }
287 
288             @Override
289             public Exception getException() {
290                 return null;
291             }
292 
293             @Override
294             public String getResult() {
295                 return null;
296             }
297 
298             @Override
299             public boolean isDone() {
300                 return false;
301             }
302         };
303 
304         final Future<?> future = this.httpclient.execute(producer, consumer, null, null);
305         try {
306             future.get();
307             Assert.fail();
308         } catch (ExecutionException e) {
309             Assert.assertTrue(e.getCause() instanceof UnknownHostException);
310         }
311         this.connMgr.shutdown(1000);
312 
313         Assert.assertTrue(closed.get());
314         Assert.assertFalse(cancelled.get());
315         Assert.assertTrue(failed.get());
316     }
317 
318     @Test
319     public void testConsumerIsDone() throws Exception {
320         this.serverBootstrap.registerHandler("/echo/*", new BasicAsyncRequestHandler(new EchoHandler()));
321         this.serverBootstrap.registerHandler("/random/*", new BasicAsyncRequestHandler(new RandomHandler()));
322 
323         final HttpHost target = start();
324 
325         final AtomicInteger producerClosed = new AtomicInteger(0);
326         final AtomicInteger consumerClosed = new AtomicInteger(0);
327 
328         final HttpAsyncRequestProducer producer = new BasicAsyncRequestProducer(target, new HttpGet("/")) {
329 
330             @Override
331             public synchronized void close() throws IOException {
332                 producerClosed.incrementAndGet();
333                 super.close();
334             }
335         };
336 
337         final HttpAsyncResponseConsumer<?> consumer = new HttpAsyncResponseConsumer<Object>() {
338 
339             @Override
340             public void close() throws IOException {
341                 consumerClosed.incrementAndGet();
342             }
343 
344             @Override
345             public boolean cancel() {
346                 return false;
347             }
348 
349             @Override
350             public void failed(final Exception ex) {
351             }
352 
353             @Override
354             public void responseReceived(
355                     final HttpResponse response) throws IOException, HttpException {
356             }
357 
358             @Override
359             public void consumeContent(
360                     final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
361             }
362 
363             @Override
364             public void responseCompleted(final HttpContext context) {
365             }
366 
367             @Override
368             public Exception getException() {
369                 return null;
370             }
371 
372             @Override
373             public String getResult() {
374                 return null;
375             }
376 
377             @Override
378             public boolean isDone() {
379                 return true; // cancels fetching the response-body
380             }
381         };
382 
383         final Future<?> future = this.httpclient.execute(producer, consumer, null, null);
384         future.get();
385 
386         connMgr.shutdown(1000);
387 
388         Assert.assertTrue(future.isCancelled());
389         Assert.assertTrue(future.isCancelled());
390 
391         Assert.assertEquals(1, producerClosed.get());
392         Assert.assertEquals(1, consumerClosed.get());
393     }
394 
395 }