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