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.util.concurrent.CountDownLatch;
31  import java.util.concurrent.ExecutionException;
32  import java.util.concurrent.Future;
33  import java.util.concurrent.TimeUnit;
34  import java.util.concurrent.atomic.AtomicBoolean;
35  import java.util.concurrent.atomic.AtomicInteger;
36  
37  import org.apache.http.HttpConnection;
38  import org.apache.http.HttpException;
39  import org.apache.http.HttpHost;
40  import org.apache.http.HttpRequest;
41  import org.apache.http.HttpResponse;
42  import org.apache.http.client.methods.HttpGet;
43  import org.apache.http.concurrent.FutureCallback;
44  import org.apache.http.entity.ContentType;
45  import org.apache.http.impl.nio.client.HttpAsyncClients;
46  import org.apache.http.localserver.EchoHandler;
47  import org.apache.http.localserver.HttpAsyncTestBase;
48  import org.apache.http.localserver.RandomHandler;
49  import org.apache.http.nio.ContentDecoder;
50  import org.apache.http.nio.ContentEncoder;
51  import org.apache.http.nio.IOControl;
52  import org.apache.http.nio.client.methods.HttpAsyncMethods;
53  import org.apache.http.nio.entity.NStringEntity;
54  import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
55  import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
56  import org.apache.http.nio.protocol.BasicAsyncRequestProducer;
57  import org.apache.http.nio.protocol.BasicAsyncResponseProducer;
58  import org.apache.http.nio.protocol.HttpAsyncExchange;
59  import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
60  import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
61  import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
62  import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
63  import org.apache.http.protocol.HttpContext;
64  import org.apache.http.protocol.HttpCoreContext;
65  import org.junit.Assert;
66  import org.junit.Ignore;
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 @Ignore(value = "Fails on some Windows platforms")
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://0.0.0.0/");
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             final Throwable cause = e.getCause();
310             Assert.assertTrue("Unexpected cause: " + cause, cause instanceof IOException);
311         }
312         this.connMgr.shutdown(1000);
313 
314         Assert.assertTrue(closed.get());
315         Assert.assertFalse(cancelled.get());
316         Assert.assertTrue(failed.get());
317     }
318 
319     @Test
320     public void testConsumerIsDone() throws Exception {
321         this.serverBootstrap.registerHandler("/echo/*", new BasicAsyncRequestHandler(new EchoHandler()));
322         this.serverBootstrap.registerHandler("/random/*", new BasicAsyncRequestHandler(new RandomHandler()));
323 
324         final HttpHost target = start();
325 
326         final AtomicInteger producerClosed = new AtomicInteger(0);
327         final AtomicInteger consumerClosed = new AtomicInteger(0);
328 
329         final HttpAsyncRequestProducer producer = new BasicAsyncRequestProducer(target, new HttpGet("/")) {
330 
331             @Override
332             public synchronized void close() throws IOException {
333                 producerClosed.incrementAndGet();
334                 super.close();
335             }
336         };
337 
338         final HttpAsyncResponseConsumer<?> consumer = new HttpAsyncResponseConsumer<Object>() {
339 
340             @Override
341             public void close() throws IOException {
342                 consumerClosed.incrementAndGet();
343             }
344 
345             @Override
346             public boolean cancel() {
347                 return false;
348             }
349 
350             @Override
351             public void failed(final Exception ex) {
352             }
353 
354             @Override
355             public void responseReceived(
356                     final HttpResponse response) throws IOException, HttpException {
357             }
358 
359             @Override
360             public void consumeContent(
361                     final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
362             }
363 
364             @Override
365             public void responseCompleted(final HttpContext context) {
366             }
367 
368             @Override
369             public Exception getException() {
370                 return null;
371             }
372 
373             @Override
374             public String getResult() {
375                 return null;
376             }
377 
378             @Override
379             public boolean isDone() {
380                 return true; // cancels fetching the response-body
381             }
382         };
383 
384         final Future<?> future = this.httpclient.execute(producer, consumer, null, null);
385         future.get();
386 
387         connMgr.shutdown(1000);
388 
389         Assert.assertTrue(future.isCancelled());
390         Assert.assertTrue(future.isCancelled());
391 
392         Assert.assertEquals(1, producerClosed.get());
393         Assert.assertEquals(1, consumerClosed.get());
394     }
395 
396 }