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
28 package org.apache.http.nio.protocol;
29
30 import java.io.IOException;
31 import java.net.SocketTimeoutException;
32 import java.util.Queue;
33
34 import org.apache.http.ConnectionReuseStrategy;
35 import org.apache.http.HttpEntityEnclosingRequest;
36 import org.apache.http.HttpException;
37 import org.apache.http.HttpRequest;
38 import org.apache.http.HttpResponse;
39 import org.apache.http.HttpResponseFactory;
40 import org.apache.http.HttpStatus;
41 import org.apache.http.HttpVersion;
42 import org.apache.http.concurrent.Cancellable;
43 import org.apache.http.impl.DefaultHttpResponseFactory;
44 import org.apache.http.message.BasicHttpEntityEnclosingRequest;
45 import org.apache.http.message.BasicHttpRequest;
46 import org.apache.http.message.BasicHttpResponse;
47 import org.apache.http.nio.ContentDecoder;
48 import org.apache.http.nio.ContentEncoder;
49 import org.apache.http.nio.NHttpConnection;
50 import org.apache.http.nio.NHttpServerConnection;
51 import org.apache.http.nio.entity.NStringEntity;
52 import org.apache.http.nio.protocol.HttpAsyncService.Incoming;
53 import org.apache.http.nio.protocol.HttpAsyncService.Outgoing;
54 import org.apache.http.nio.protocol.HttpAsyncService.PipelineEntry;
55 import org.apache.http.nio.protocol.HttpAsyncService.State;
56 import org.apache.http.nio.reactor.SessionBufferStatus;
57 import org.apache.http.protocol.BasicHttpContext;
58 import org.apache.http.protocol.HTTP;
59 import org.apache.http.protocol.HttpContext;
60 import org.apache.http.protocol.HttpCoreContext;
61 import org.apache.http.protocol.HttpProcessor;
62 import org.junit.After;
63 import org.junit.Assert;
64 import org.junit.Before;
65 import org.junit.Test;
66 import org.mockito.ArgumentCaptor;
67 import org.mockito.ArgumentMatcher;
68 import org.mockito.Matchers;
69 import org.mockito.Mockito;
70
71 public class TestHttpAsyncService {
72
73 private UriHttpAsyncRequestHandlerMapper handlerResolver;
74 private HttpAsyncService protocolHandler;
75 private HttpProcessor httpProcessor;
76 private ConnectionReuseStrategy reuseStrategy;
77 private HttpResponseFactory responseFactory;
78 private HttpContext connContext;
79 private NHttpServerConnection conn;
80 private HttpAsyncRequestHandler<Object> requestHandler;
81 private HttpAsyncRequestConsumer<Object> requestConsumer;
82 private HttpAsyncResponseProducer responseProducer;
83 private ContentEncoder encoder;
84 private ContentDecoder decoder;
85 private Cancellable cancellable;
86
87 @Before
88 public void setUp() throws Exception {
89 this.requestHandler = Mockito.mock(HttpAsyncRequestHandler.class);
90 this.requestConsumer = Mockito.mock(HttpAsyncRequestConsumer.class);
91 this.responseProducer = Mockito.mock(HttpAsyncResponseProducer.class);
92 this.handlerResolver = new UriHttpAsyncRequestHandlerMapper();
93 this.handlerResolver.register("/", this.requestHandler);
94 this.httpProcessor = Mockito.mock(HttpProcessor.class);
95 this.reuseStrategy = Mockito.mock(ConnectionReuseStrategy.class);
96 this.responseFactory = DefaultHttpResponseFactory.INSTANCE;
97 this.protocolHandler = new HttpAsyncService(
98 this.httpProcessor, this.reuseStrategy, this.responseFactory, this.handlerResolver, null);
99 this.connContext = new BasicHttpContext();
100 this.conn = Mockito.mock(NHttpServerConnection.class);
101 this.encoder = Mockito.mock(ContentEncoder.class);
102 this.decoder = Mockito.mock(ContentDecoder.class);
103 this.cancellable = Mockito.mock(Cancellable.class);
104
105 Mockito.when(this.conn.getContext()).thenReturn(this.connContext);
106 }
107
108 @After
109 public void tearDown() throws Exception {
110 }
111
112 @Test(expected=IllegalArgumentException.class)
113 public void testInvalidConstruction() throws Exception {
114 new HttpAsyncService(null, this.reuseStrategy, this.responseFactory, this.handlerResolver, null);
115 }
116
117 @Test
118 public void testConnected() throws Exception {
119 this.protocolHandler.connected(this.conn);
120
121 final State state = (State) this.connContext.getAttribute(
122 HttpAsyncService.HTTP_EXCHANGE_STATE);
123 Assert.assertNotNull(state);
124 Assert.assertEquals(MessageState.READY, state.getRequestState());
125 Assert.assertEquals(MessageState.READY, state.getResponseState());
126 Assert.assertEquals("[incoming READY; outgoing READY]", state.toString());
127 }
128
129 @Test
130 public void testClosed() throws Exception {
131 final State state = new State();
132 state.setRequestState(MessageState.COMPLETED);
133 state.setResponseState(MessageState.COMPLETED);
134 final HttpContext exchangeContext = new BasicHttpContext();
135
136 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
137 final Incoming incoming = new Incoming(
138 request, this.requestHandler, this.requestConsumer, exchangeContext);
139 state.setIncoming(incoming);
140 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
141 final Outgoing outgoing = new Outgoing(
142 request, response, this.responseProducer, exchangeContext);
143 state.setOutgoing(outgoing);
144 state.setCancellable(this.cancellable);
145 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
146
147 this.protocolHandler.closed(this.conn);
148
149 Mockito.verify(this.requestConsumer).close();
150 Mockito.verify(this.responseProducer).close();
151 Mockito.verify(this.cancellable).cancel();
152 }
153
154 @Test
155 public void testHttpExceptionHandling() throws Exception {
156 final State state = new State();
157 state.setRequestState(MessageState.READY);
158 state.setResponseState(MessageState.READY);
159 final HttpContext exchangeContext = new BasicHttpContext();
160 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
161 final Incoming incoming = new Incoming(
162 request, this.requestHandler, this.requestConsumer, exchangeContext);
163 state.setIncoming(incoming);
164 state.setCancellable(this.cancellable);
165 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
166 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
167
168 final HttpException httpex = new HttpException();
169 this.protocolHandler.exception(this.conn, httpex);
170
171 Assert.assertEquals(MessageState.READY, state.getRequestState());
172 Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
173 final Outgoing outgoing = state.getOutgoing();
174 Assert.assertNotNull(outgoing);
175 Assert.assertNotNull(outgoing.getProducer());
176 Assert.assertNotNull(outgoing.getResponse());
177 Assert.assertEquals(500, outgoing.getResponse().getStatusLine().getStatusCode());
178
179 Mockito.verify(this.requestConsumer).failed(httpex);
180 Mockito.verify(this.requestConsumer).close();
181 Mockito.verify(this.cancellable).cancel();
182 Mockito.verify(this.conn, Mockito.never()).shutdown();
183 Mockito.verify(this.conn, Mockito.never()).close();
184 }
185
186 @Test
187 public void testExceptionHandlingNoState() throws Exception {
188 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, null);
189
190 final Exception ex = new Exception("Oopsie");
191 this.protocolHandler.exception(conn, ex);
192
193 Mockito.verify(conn).getContext();
194 Mockito.verify(conn).shutdown();
195 Mockito.verifyNoMoreInteractions(conn);
196 }
197
198 @Test
199 public void testExceptionHandlingRuntimeException() throws Exception {
200 final State state = new State();
201 state.setRequestState(MessageState.READY);
202 state.setResponseState(MessageState.READY);
203 final HttpContext exchangeContext = new BasicHttpContext();
204 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
205 final Incoming incoming = new Incoming(
206 request, this.requestHandler, this.requestConsumer, exchangeContext);
207 state.setIncoming(incoming);
208 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
209 final Outgoing outgoing = new Outgoing(
210 request, response, this.responseProducer, exchangeContext);
211 state.setOutgoing(outgoing);
212 state.setCancellable(this.cancellable);
213 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
214 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
215
216 Mockito.doThrow(new RuntimeException()).when(this.httpProcessor).process(
217 Matchers.any(HttpResponse.class), Matchers.any(HttpContext.class));
218 final HttpException httpex = new HttpException();
219 try {
220 this.protocolHandler.exception(this.conn, httpex);
221 Assert.fail("RuntimeException expected");
222 } catch (final RuntimeException ex) {
223 Mockito.verify(this.conn).shutdown();
224 Mockito.verify(this.requestConsumer).failed(httpex);
225 Mockito.verify(this.requestConsumer, Mockito.atLeastOnce()).close();
226 Mockito.verify(this.responseProducer).failed(httpex);
227 Mockito.verify(this.responseProducer, Mockito.atLeastOnce()).close();
228 Mockito.verify(this.cancellable).cancel();
229 }
230 }
231
232 @Test
233 public void testHttpExceptionHandlingIOException() throws Exception {
234 final State state = new State();
235 state.setRequestState(MessageState.READY);
236 state.setResponseState(MessageState.READY);
237 final HttpContext exchangeContext = new BasicHttpContext();
238 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
239 final Incoming incoming = new Incoming(
240 request, this.requestHandler, this.requestConsumer, exchangeContext);
241 state.setIncoming(incoming);
242 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
243 final Outgoing outgoing = new Outgoing(
244 request, response, this.responseProducer, exchangeContext);
245 state.setOutgoing(outgoing);
246 state.setCancellable(this.cancellable);
247 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
248 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
249
250 Mockito.doThrow(new IOException()).when(this.httpProcessor).process(
251 Matchers.any(HttpResponse.class), Matchers.any(HttpContext.class));
252 final HttpException httpex = new HttpException();
253
254 this.protocolHandler.exception(this.conn, httpex);
255
256 Mockito.verify(this.conn).shutdown();
257 Mockito.verify(this.requestConsumer).failed(httpex);
258 Mockito.verify(this.requestConsumer, Mockito.atLeastOnce()).close();
259 Mockito.verify(this.responseProducer).failed(httpex);
260 Mockito.verify(this.responseProducer, Mockito.atLeastOnce()).close();
261 Mockito.verify(this.cancellable).cancel();
262 }
263
264 @Test
265 public void testHttpExceptionHandlingResponseSubmitted() throws Exception {
266 final State state = new State();
267 state.setRequestState(MessageState.READY);
268 state.setResponseState(MessageState.READY);
269 final HttpContext exchangeContext = new BasicHttpContext();
270 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
271 final Incoming incoming = new Incoming(
272 request, this.requestHandler, this.requestConsumer, exchangeContext);
273 state.setIncoming(incoming);
274 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
275 final Outgoing outgoing = new Outgoing(
276 request, response, this.responseProducer, exchangeContext);
277 state.setOutgoing(outgoing);
278 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
279 Mockito.when(this.conn.isResponseSubmitted()).thenReturn(Boolean.TRUE);
280
281 final HttpException httpex = new HttpException();
282 this.protocolHandler.exception(this.conn, httpex);
283
284 Assert.assertEquals(MessageState.READY, state.getRequestState());
285 Assert.assertEquals(MessageState.READY, state.getResponseState());
286 Mockito.verify(this.conn).close();
287 Mockito.verify(this.requestConsumer).failed(httpex);
288 Mockito.verify(this.requestConsumer).close();
289 Mockito.verify(this.responseProducer).failed(httpex);
290 Mockito.verify(this.responseProducer).close();
291 }
292
293 @Test
294 public void testBasicRequest() throws Exception {
295 final State state = new State();
296 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
297
298 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
299 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
300 Mockito.when(this.requestHandler.processRequest(
301 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
302 Mockito.when(this.requestConsumer.getException()).thenReturn(null);
303 final Object data = new Object();
304 Mockito.when(this.requestConsumer.getResult()).thenReturn(data);
305
306 this.protocolHandler.requestReceived(this.conn);
307
308 Assert.assertEquals(MessageState.READY, state.getRequestState());
309 Assert.assertEquals(MessageState.READY, state.getResponseState());
310
311 final Incoming incoming = state.getIncoming();
312 Assert.assertNull(incoming);
313
314 final ArgumentCaptor<HttpContext> argumentCaptor = ArgumentCaptor.forClass(HttpContext.class);
315 Mockito.verify(this.httpProcessor).process(Matchers.eq(request), argumentCaptor.capture());
316 final HttpContext exchangeContext = argumentCaptor.getValue();
317 Assert.assertNotNull(exchangeContext);
318
319 Assert.assertSame(request, exchangeContext.getAttribute(HttpCoreContext.HTTP_REQUEST));
320 Assert.assertSame(this.conn, exchangeContext.getAttribute(HttpCoreContext.HTTP_CONNECTION));
321
322 Mockito.verify(this.requestConsumer).requestReceived(request);
323 Mockito.verify(this.requestConsumer).requestCompleted(exchangeContext);
324 Mockito.verify(this.conn).requestOutput();
325
326 final PipelineEntry entry = state.getPipeline().poll();
327 Assert.assertNotNull(entry);
328 Assert.assertSame(request, entry.getRequest());
329 Assert.assertSame(requestHandler, entry.getHandler());
330 Assert.assertNotNull(entry.getResult());
331 Assert.assertNull(entry.getException());
332 }
333
334 @Test
335 public void testRequestPipelineIfResponseInitiated() throws Exception {
336 final State state = new State();
337 state.setRequestState(MessageState.READY);
338 state.setResponseState(MessageState.INIT);
339 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
340
341 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
342 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
343 Mockito.when(this.requestHandler.processRequest(
344 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
345 Mockito.when(this.requestConsumer.getException()).thenReturn(null);
346 final Object data = new Object();
347 Mockito.when(this.requestConsumer.getResult()).thenReturn(data);
348
349 this.protocolHandler.requestReceived(this.conn);
350
351 Assert.assertEquals(MessageState.READY, state.getRequestState());
352 Assert.assertEquals(MessageState.INIT, state.getResponseState());
353
354 final Incoming incoming = state.getIncoming();
355 Assert.assertNull(incoming);
356
357 Mockito.verify(this.requestConsumer).requestReceived(request);
358 Mockito.verify(this.requestConsumer).requestCompleted(Matchers.<HttpContext>any());
359 Mockito.verify(this.requestHandler, Mockito.never()).handle(
360 Matchers.any(),
361 Matchers.any(HttpAsyncExchange.class),
362 Matchers.any(HttpContext.class));
363
364 Assert.assertFalse(state.getPipeline().isEmpty());
365 final PipelineEntry entry = state.getPipeline().remove();
366 Assert.assertSame(request, entry.getRequest());
367 Assert.assertSame(data, entry.getResult());
368 }
369
370 @Test
371 public void testRequestPipelineIfPipelineNotEmpty() throws Exception {
372 final State state = new State();
373 state.setRequestState(MessageState.READY);
374 state.setResponseState(MessageState.READY);
375
376 final Queue<PipelineEntry> pipeline = state.getPipeline();
377
378 final HttpContext exchangeContext = new BasicHttpContext();
379 final HttpRequest pipelinedRequest = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
380 final PipelineEntry entry = new PipelineEntry(pipelinedRequest, pipelinedRequest,
381 null, requestHandler, exchangeContext);
382 pipeline.add(entry);
383
384 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
385
386 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
387 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
388 Mockito.when(this.requestHandler.processRequest(
389 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
390 Mockito.when(this.requestConsumer.getException()).thenReturn(null);
391 final Object data = new Object();
392 Mockito.when(this.requestConsumer.getResult()).thenReturn(data);
393
394 this.protocolHandler.requestReceived(this.conn);
395
396 Assert.assertEquals(MessageState.READY, state.getRequestState());
397 Assert.assertEquals(MessageState.READY, state.getResponseState());
398
399 final Incoming incoming = state.getIncoming();
400 Assert.assertNull(incoming);
401
402 Mockito.verify(this.requestConsumer).requestReceived(request);
403 Mockito.verify(this.requestConsumer).requestCompleted(Matchers.<HttpContext>any());
404 Mockito.verify(this.requestHandler, Mockito.never()).handle(
405 Matchers.any(),
406 Matchers.any(HttpAsyncExchange.class),
407 Matchers.any(HttpContext.class));
408
409 Assert.assertFalse(state.getPipeline().isEmpty());
410 final PipelineEntry entry1 = state.getPipeline().remove();
411 Assert.assertSame(entry, entry1);
412 final PipelineEntry entry2 = state.getPipeline().remove();
413 Assert.assertSame(request, entry2.getRequest());
414 Assert.assertSame(data, entry2.getResult());
415 }
416
417 @Test
418 public void testRequestNoMatchingHandler() throws Exception {
419 final State state = new State();
420 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
421
422 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST",
423 "/stuff", HttpVersion.HTTP_1_1);
424 request.setEntity(new NStringEntity("stuff"));
425 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
426 Mockito.when(this.requestHandler.processRequest(
427 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
428
429 this.protocolHandler.requestReceived(this.conn);
430
431 Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
432 Assert.assertEquals(MessageState.READY, state.getResponseState());
433
434 final Incoming incoming = state.getIncoming();
435 Assert.assertNotNull(incoming);
436 Assert.assertSame(request, incoming.getRequest());
437 Assert.assertTrue(incoming.getHandler() instanceof NullRequestHandler);
438 }
439
440 @Test
441 public void testEntityEnclosingRequest() throws Exception {
442 final State state = new State();
443 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
444
445 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
446 HttpVersion.HTTP_1_1);
447 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
448 Mockito.when(this.requestHandler.processRequest(
449 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
450
451 this.protocolHandler.requestReceived(this.conn);
452
453 Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
454 Assert.assertEquals(MessageState.READY, state.getResponseState());
455
456 final Incoming incoming = state.getIncoming();
457 Assert.assertNotNull(incoming);
458 Assert.assertSame(request, incoming.getRequest());
459 Assert.assertSame(this.requestHandler, incoming.getHandler());
460 Assert.assertSame(this.requestConsumer, incoming.getConsumer());
461
462 final HttpContext exchangeContext = incoming.getContext();
463 Assert.assertNotNull(exchangeContext);
464
465 Assert.assertSame(request, exchangeContext.getAttribute(HttpCoreContext.HTTP_REQUEST));
466 Assert.assertSame(this.conn, exchangeContext.getAttribute(HttpCoreContext.HTTP_CONNECTION));
467
468 Mockito.verify(this.httpProcessor).process(request, exchangeContext);
469 Mockito.verify(this.requestConsumer).requestReceived(request);
470 Mockito.verify(this.conn, Mockito.never()).suspendInput();
471 }
472
473 @Test
474 public void testEntityEnclosingRequestContinueWithoutVerification() throws Exception {
475 final State state = new State();
476 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
477
478 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
479 HttpVersion.HTTP_1_1);
480 request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
481 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
482 Mockito.when(this.requestHandler.processRequest(
483 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
484
485 this.protocolHandler.requestReceived(this.conn);
486
487 Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
488 Assert.assertEquals(MessageState.READY, state.getResponseState());
489
490 final Incoming incoming = state.getIncoming();
491 Assert.assertNotNull(incoming);
492 Assert.assertSame(request, incoming.getRequest());
493 Assert.assertSame(this.requestHandler, incoming.getHandler());
494 Assert.assertSame(this.requestConsumer, incoming.getConsumer());
495
496 final HttpContext exchangeContext = incoming.getContext();
497 Assert.assertNotNull(exchangeContext);
498
499 Assert.assertSame(request, exchangeContext.getAttribute(HttpCoreContext.HTTP_REQUEST));
500 Assert.assertSame(this.conn, exchangeContext.getAttribute(HttpCoreContext.HTTP_CONNECTION));
501
502 Mockito.verify(this.httpProcessor).process(request, exchangeContext);
503 Mockito.verify(this.requestConsumer).requestReceived(request);
504 Mockito.verify(this.conn, Mockito.never()).suspendInput();
505 Mockito.verify(this.conn).submitResponse(Matchers.argThat(new ArgumentMatcher<HttpResponse>() {
506
507 @Override
508 public boolean matches(final Object argument) {
509 final int status = ((HttpResponse) argument).getStatusLine().getStatusCode();
510 return status == 100;
511 }
512
513 }));
514 }
515
516 @Test
517 public void testEntityEnclosingRequestExpectationVerification() throws Exception {
518 final HttpAsyncExpectationVerifier expectationVerifier = Mockito.mock(HttpAsyncExpectationVerifier.class);
519 this.protocolHandler = new HttpAsyncService(
520 this.httpProcessor, this.reuseStrategy, this.responseFactory,
521 this.handlerResolver, expectationVerifier);
522
523 final State state = new State();
524 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
525
526 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
527 HttpVersion.HTTP_1_1);
528 request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
529 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
530 Mockito.when(this.requestHandler.processRequest(
531 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
532
533 this.protocolHandler.requestReceived(this.conn);
534
535 Assert.assertEquals(MessageState.ACK_EXPECTED, state.getRequestState());
536 Assert.assertEquals(MessageState.READY, state.getResponseState());
537
538 final Incoming incoming = state.getIncoming();
539 Assert.assertNotNull(incoming);
540 Assert.assertSame(request, incoming.getRequest());
541 Assert.assertSame(this.requestHandler, incoming.getHandler());
542 Assert.assertSame(this.requestConsumer, incoming.getConsumer());
543
544 final HttpContext exchangeContext = incoming.getContext();
545 Assert.assertNotNull(exchangeContext);
546
547 Assert.assertSame(request, exchangeContext.getAttribute(HttpCoreContext.HTTP_REQUEST));
548 Assert.assertSame(this.conn, exchangeContext.getAttribute(HttpCoreContext.HTTP_CONNECTION));
549
550 Mockito.verify(this.httpProcessor).process(request, exchangeContext);
551 Mockito.verify(this.requestConsumer).requestReceived(request);
552 Mockito.verify(this.conn).suspendInput();
553 Mockito.verify(expectationVerifier).verify(
554 Matchers.any(HttpAsyncExchange.class),
555 Matchers.eq(exchangeContext));
556 }
557
558 @Test
559 public void testRequestExpectationFailed() throws Exception {
560 final State state = new State();
561 state.setRequestState(MessageState.ACK_EXPECTED);
562 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
563
564 final HttpContext exchangeContext = new BasicHttpContext();
565 final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
566 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
567 new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"),
568 state, this.conn, exchangeContext);
569 Assert.assertFalse(httpexchanage.isCompleted());
570 httpexchanage.submitResponse(this.responseProducer);
571 Assert.assertTrue(httpexchanage.isCompleted());
572
573 Assert.assertEquals(MessageState.ACK_EXPECTED, state.getRequestState());
574 Assert.assertEquals(MessageState.READY, state.getResponseState());
575 final Outgoing outgoing = state.getOutgoing();
576 Assert.assertNotNull(outgoing);
577 Assert.assertSame(this.responseProducer, outgoing.getProducer());
578
579 Mockito.verify(this.conn).requestOutput();
580
581 try {
582 httpexchanage.submitResponse();
583 Assert.fail("IllegalStateException expected");
584 } catch (final IllegalStateException ex) {
585 }
586 }
587
588 @Test(expected=IllegalArgumentException.class)
589 public void testRequestExpectationFailedInvalidResponseProducer() throws Exception {
590 final State state = new State();
591 state.setRequestState(MessageState.ACK_EXPECTED);
592 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
593
594 final HttpContext exchangeContext = new BasicHttpContext();
595 final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
596 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
597 new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"),
598 state, this.conn, exchangeContext);
599 httpexchanage.submitResponse(null);
600 }
601
602 @Test
603 public void testRequestExpectationNoHandshakeIfResponseInitiated() throws Exception {
604 final State state = new State();
605 state.setRequestState(MessageState.READY);
606 state.setResponseState(MessageState.INIT);
607 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
608
609 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
610 HttpVersion.HTTP_1_1);
611 request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
612
613 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
614 Mockito.when(this.requestHandler.processRequest(
615 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
616
617 this.protocolHandler.requestReceived(this.conn);
618
619 Mockito.verify(this.requestConsumer).requestReceived(request);
620
621 Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
622 Assert.assertEquals(MessageState.INIT, state.getResponseState());
623 }
624
625 @Test
626 public void testRequestExpectationNoHandshakeIfPipelineNotEmpty() throws Exception {
627 final State state = new State();
628 state.setRequestState(MessageState.READY);
629 state.setResponseState(MessageState.READY);
630
631 final Queue<PipelineEntry> pipeline = state.getPipeline();
632
633 final HttpContext exchangeContext = new BasicHttpContext();
634 final HttpRequest pipelinedRequest = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
635 final PipelineEntry entry = new PipelineEntry(pipelinedRequest, pipelinedRequest,
636 null, requestHandler, exchangeContext);
637 pipeline.add(entry);
638
639 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
640
641 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
642 HttpVersion.HTTP_1_1);
643 request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
644
645 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
646 Mockito.when(this.requestHandler.processRequest(
647 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
648
649 this.protocolHandler.requestReceived(this.conn);
650
651 Mockito.verify(this.requestConsumer).requestReceived(request);
652
653 Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
654 Assert.assertEquals(MessageState.READY, state.getResponseState());
655 }
656
657 @Test
658 public void testRequestExpectationNoHandshakeIfMoreInputAvailable() throws Exception {
659 final State state = new State();
660 state.setRequestState(MessageState.READY);
661 state.setResponseState(MessageState.READY);
662
663 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
664
665 this.conn = Mockito.mock(NHttpServerConnection.class,
666 Mockito.withSettings().extraInterfaces(SessionBufferStatus.class));
667
668 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
669 HttpVersion.HTTP_1_1);
670 request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
671
672 Mockito.when(this.conn.getContext()).thenReturn(this.connContext);
673 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
674 Mockito.when(this.requestHandler.processRequest(
675 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
676 Mockito.when(((SessionBufferStatus) this.conn).hasBufferedInput()).thenReturn(Boolean.TRUE);
677
678 this.protocolHandler.requestReceived(this.conn);
679
680 Mockito.verify(this.requestConsumer).requestReceived(request);
681
682 Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
683 Assert.assertEquals(MessageState.READY, state.getResponseState());
684 }
685
686 @Test
687 public void testRequestContinue() throws Exception {
688 final State state = new State();
689 state.setRequestState(MessageState.ACK_EXPECTED);
690 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
691
692 final HttpContext exchangeContext = new BasicHttpContext();
693 final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
694 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
695 new BasicHttpResponse(HttpVersion.HTTP_1_1, 100, "Continue"),
696 state, this.conn, exchangeContext);
697 Assert.assertFalse(httpexchanage.isCompleted());
698 httpexchanage.submitResponse();
699 Assert.assertTrue(httpexchanage.isCompleted());
700
701 final Outgoing outgoing = state.getOutgoing();
702 Assert.assertNotNull(outgoing);
703 final HttpAsyncResponseProducer responseProducer = outgoing.getProducer();
704 Assert.assertNotNull(responseProducer);
705 Assert.assertEquals(MessageState.ACK_EXPECTED, state.getRequestState());
706 Assert.assertEquals(MessageState.READY, state.getResponseState());
707 final HttpResponse response = responseProducer.generateResponse();
708 Assert.assertEquals(HttpStatus.SC_CONTINUE, response.getStatusLine().getStatusCode());
709
710 Mockito.verify(this.conn).requestOutput();
711
712 try {
713 httpexchanage.submitResponse(this.responseProducer);
714 Assert.fail("IllegalStateException expected");
715 } catch (final IllegalStateException ex) {
716 }
717 }
718
719 @Test
720 public void testRequestContent() throws Exception {
721 final State state = new State();
722 final HttpContext exchangeContext = new BasicHttpContext();
723 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
724 HttpVersion.HTTP_1_1);
725 state.setRequestState(MessageState.BODY_STREAM);
726 final Incoming incoming = new Incoming(
727 request, this.requestHandler, this.requestConsumer, exchangeContext);
728 state.setIncoming(incoming);
729 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
730 Mockito.when(this.decoder.isCompleted()).thenReturn(Boolean.FALSE);
731
732 this.protocolHandler.inputReady(conn, this.decoder);
733
734 Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
735 Assert.assertEquals(MessageState.READY, state.getResponseState());
736
737 Mockito.verify(this.requestConsumer).consumeContent(this.decoder, this.conn);
738 Mockito.verify(this.conn, Mockito.never()).suspendInput();
739 }
740
741 @Test
742 public void testRequestContentCompleted() throws Exception {
743 final State state = new State();
744 final HttpContext exchangeContext = new BasicHttpContext();
745 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
746 HttpVersion.HTTP_1_1);
747 state.setRequestState(MessageState.BODY_STREAM);
748 final Incoming incoming = new Incoming(
749 request, this.requestHandler, this.requestConsumer, exchangeContext);
750 state.setIncoming(incoming);
751 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
752 Mockito.when(this.decoder.isCompleted()).thenReturn(Boolean.TRUE);
753 Mockito.when(this.requestConsumer.getException()).thenReturn(null);
754 final Object data = new Object();
755 Mockito.when(this.requestConsumer.getResult()).thenReturn(data);
756
757 this.protocolHandler.inputReady(conn, this.decoder);
758
759 Assert.assertEquals(MessageState.READY, state.getRequestState());
760 Assert.assertEquals(MessageState.READY, state.getResponseState());
761
762 Mockito.verify(this.requestConsumer).consumeContent(this.decoder, this.conn);
763 Mockito.verify(this.requestConsumer).requestCompleted(exchangeContext);
764 Mockito.verify(this.conn).requestOutput();
765
766 final PipelineEntry entry = state.getPipeline().poll();
767 Assert.assertNotNull(entry);
768 Assert.assertSame(request, entry.getRequest());
769 Assert.assertSame(requestHandler, entry.getHandler());
770 Assert.assertNotNull(entry.getResult());
771 Assert.assertNull(entry.getException());
772 }
773
774 @Test
775 public void testRequestCompletedWithException() throws Exception {
776 final State state = new State();
777 final HttpContext exchangeContext = new BasicHttpContext();
778 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
779 HttpVersion.HTTP_1_1);
780 state.setRequestState(MessageState.BODY_STREAM);
781 final Incoming incoming = new Incoming(
782 request, this.requestHandler, this.requestConsumer, exchangeContext);
783 state.setIncoming(incoming);
784 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
785 Mockito.when(this.decoder.isCompleted()).thenReturn(Boolean.TRUE);
786 Mockito.when(this.requestConsumer.getException()).thenReturn(new HttpException());
787 Mockito.when(this.requestConsumer.getResult()).thenReturn(null);
788
789 this.protocolHandler.inputReady(conn, this.decoder);
790
791 Assert.assertEquals(MessageState.READY, state.getRequestState());
792 Assert.assertEquals(MessageState.READY, state.getResponseState());
793
794 Mockito.verify(this.requestConsumer).consumeContent(this.decoder, this.conn);
795 Mockito.verify(this.requestConsumer).requestCompleted(exchangeContext);
796 Mockito.verify(this.conn).requestOutput();
797
798 final PipelineEntry entry = state.getPipeline().poll();
799 Assert.assertNotNull(entry);
800 Assert.assertSame(request, entry.getRequest());
801 Assert.assertSame(requestHandler, entry.getHandler());
802 Assert.assertNull(entry.getResult());
803 Assert.assertNotNull(entry.getException());
804 }
805
806 @Test
807 public void testBasicResponse() throws Exception {
808 final State state = new State();
809 final HttpContext exchangeContext = new BasicHttpContext();
810 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
811 final Incoming incoming = new Incoming(
812 request, this.requestHandler, this.requestConsumer, exchangeContext);
813 state.setIncoming(incoming);
814 state.setRequestState(MessageState.COMPLETED);
815 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
816 final Outgoing outgoing = new Outgoing(
817 request, response, this.responseProducer, exchangeContext);
818 state.setOutgoing(outgoing);
819 state.setResponseState(MessageState.INIT);
820 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
821
822 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
823 Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
824
825 this.protocolHandler.responseReady(this.conn);
826
827 Assert.assertEquals(MessageState.READY, state.getResponseState());
828
829 Mockito.verify(this.httpProcessor).process(response, exchangeContext);
830 Mockito.verify(this.conn).submitResponse(response);
831 Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
832 Mockito.verify(this.conn).requestInput();
833 Mockito.verify(this.conn, Mockito.never()).close();
834 }
835
836 @Test
837 public void testBasicResponseWithPipelining() throws Exception {
838 final State state = new State();
839 final HttpContext exchangeContext = new BasicHttpContext();
840 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
841 final Incoming incoming = new Incoming(
842 request, this.requestHandler, this.requestConsumer, exchangeContext);
843 state.setIncoming(incoming);
844 state.setRequestState(MessageState.COMPLETED);
845 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
846 final Outgoing outgoing = new Outgoing(
847 request, response, this.responseProducer, exchangeContext);
848 response.setEntity(new NStringEntity("stuff"));
849 state.setOutgoing(outgoing);
850
851 final Queue<PipelineEntry> pipeline = state.getPipeline();
852
853 final HttpContext exchangeContext2 = new BasicHttpContext();
854 final HttpRequest pipelinedRequest = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
855 final PipelineEntry entry = new PipelineEntry(pipelinedRequest, pipelinedRequest,
856 null, requestHandler, exchangeContext2);
857 pipeline.add(entry);
858
859 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
860
861 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
862 Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
863
864 this.protocolHandler.responseReady(this.conn);
865
866 Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
867
868 Mockito.verify(this.httpProcessor).process(response, exchangeContext);
869 Mockito.verify(this.conn).suspendOutput();
870 Mockito.verify(this.conn).submitResponse(response);
871 Mockito.verify(this.conn, Mockito.never()).close();
872 }
873
874 @Test
875 public void testBasicResponseNoKeepAlive() throws Exception {
876 final State state = new State();
877 final HttpContext exchangeContext = new BasicHttpContext();
878 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
879 final Incoming incoming = new Incoming(
880 request, this.requestHandler, this.requestConsumer, exchangeContext);
881 state.setIncoming(incoming);
882 state.setRequestState(MessageState.COMPLETED);
883 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
884 final Outgoing outgoing = new Outgoing(
885 request, response, this.responseProducer, exchangeContext);
886 state.setOutgoing(outgoing);
887 state.setResponseState(MessageState.INIT);
888 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
889
890 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
891 Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.FALSE);
892
893 this.protocolHandler.responseReady(this.conn);
894
895 Assert.assertEquals(MessageState.READY, state.getResponseState());
896
897 Mockito.verify(this.httpProcessor).process(response, exchangeContext);
898 Mockito.verify(this.conn).submitResponse(response);
899 Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
900 Mockito.verify(this.conn).close();
901 }
902
903 @Test
904 public void testEntityEnclosingResponse() throws Exception {
905 final State state = new State();
906 final HttpContext exchangeContext = new BasicHttpContext();
907 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
908 final Incoming incoming = new Incoming(
909 request, this.requestHandler, this.requestConsumer, exchangeContext);
910 state.setIncoming(incoming);
911 state.setRequestState(MessageState.COMPLETED);
912 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
913 final Outgoing outgoing = new Outgoing(
914 request, response, this.responseProducer, exchangeContext);
915 state.setOutgoing(outgoing);
916 state.setResponseState(MessageState.INIT);
917 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
918
919 response.setEntity(new NStringEntity("stuff"));
920 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
921
922 this.protocolHandler.responseReady(this.conn);
923
924 Assert.assertEquals(MessageState.COMPLETED, state.getRequestState());
925 Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
926 Assert.assertEquals("[incoming COMPLETED GET / HTTP/1.1; outgoing BODY_STREAM HTTP/1.1 200 OK]",
927 state.toString());
928
929 Mockito.verify(this.httpProcessor).process(response, exchangeContext);
930 Mockito.verify(this.conn).submitResponse(response);
931 Mockito.verify(this.responseProducer, Mockito.never()).responseCompleted(exchangeContext);
932 }
933
934 @Test
935 public void testResponseToHead() throws Exception {
936 final State state = new State();
937 final HttpContext exchangeContext = new BasicHttpContext();
938 final HttpRequest request = new BasicHttpRequest("HEAD", "/", HttpVersion.HTTP_1_1);
939 final Incoming incoming = new Incoming(
940 request, this.requestHandler, this.requestConsumer, exchangeContext);
941 state.setIncoming(incoming);
942 state.setRequestState(MessageState.COMPLETED);
943 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
944 final Outgoing outgoing = new Outgoing(
945 request, response, this.responseProducer, exchangeContext);
946 state.setOutgoing(outgoing);
947 state.setResponseState(MessageState.INIT);
948 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
949
950 response.setEntity(new NStringEntity("stuff"));
951 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
952 Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
953
954 this.protocolHandler.responseReady(this.conn);
955
956 Assert.assertEquals(MessageState.READY, state.getResponseState());
957
958 Mockito.verify(this.httpProcessor).process(response, exchangeContext);
959 Mockito.verify(this.conn).submitResponse(response);
960 Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
961 Mockito.verify(this.conn).requestInput();
962 Mockito.verify(this.conn, Mockito.never()).close();
963 }
964
965 @Test
966 public void testResponseNotModified() throws Exception {
967 final State state = new State();
968 final HttpContext exchangeContext = new BasicHttpContext();
969 final HttpRequest request = new BasicHttpRequest("HEAD", "/", HttpVersion.HTTP_1_1);
970 final Incoming incoming = new Incoming(
971 request, this.requestHandler, this.requestConsumer, exchangeContext);
972 state.setIncoming(incoming);
973 state.setRequestState(MessageState.COMPLETED);
974 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
975 HttpStatus.SC_NOT_MODIFIED, "Not modified");
976 final Outgoing outgoing = new Outgoing(
977 request, response, this.responseProducer, exchangeContext);
978 state.setOutgoing(outgoing);
979 state.setResponseState(MessageState.INIT);
980 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
981
982 response.setEntity(new NStringEntity("stuff"));
983 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
984 Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
985
986 this.protocolHandler.responseReady(this.conn);
987
988 Assert.assertEquals(MessageState.READY, state.getResponseState());
989
990 Mockito.verify(this.httpProcessor).process(response, exchangeContext);
991 Mockito.verify(this.conn).submitResponse(response);
992 Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
993 Mockito.verify(this.conn).requestInput();
994 Mockito.verify(this.conn, Mockito.never()).close();
995 }
996
997 @Test
998 public void testResponseContinue() throws Exception {
999 final State state = new State();
1000 final HttpContext exchangeContext = new BasicHttpContext();
1001 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
1002 HttpVersion.HTTP_1_1);
1003 final Incoming incoming = new Incoming(
1004 request, this.requestHandler, this.requestConsumer, exchangeContext);
1005 state.setIncoming(incoming);
1006 state.setRequestState(MessageState.ACK_EXPECTED);
1007 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
1008 HttpStatus.SC_CONTINUE, "Continue");
1009 final Outgoing outgoing = new Outgoing(
1010 request, response, this.responseProducer, exchangeContext);
1011 state.setOutgoing(outgoing);
1012 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1013
1014 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
1015
1016 this.protocolHandler.responseReady(this.conn);
1017
1018 Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
1019 Assert.assertEquals(MessageState.READY, state.getResponseState());
1020
1021 Mockito.verify(this.conn).requestInput();
1022 Mockito.verify(this.conn).submitResponse(Matchers.argThat(new ArgumentMatcher<HttpResponse>() {
1023
1024 @Override
1025 public boolean matches(final Object argument) {
1026 final int status = ((HttpResponse) argument).getStatusLine().getStatusCode();
1027 return status == 100;
1028 }
1029
1030 }));
1031 }
1032
1033 @Test
1034 public void testResponseFailedExpectation() throws Exception {
1035 final State state = new State();
1036 final HttpContext exchangeContext = new BasicHttpContext();
1037 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
1038 HttpVersion.HTTP_1_1);
1039 final Incoming incoming = new Incoming(
1040 request, this.requestHandler, this.requestConsumer, exchangeContext);
1041 state.setIncoming(incoming);
1042 state.setRequestState(MessageState.ACK_EXPECTED);
1043 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
1044 417, "Expectation failed");
1045 final Outgoing outgoing = new Outgoing(
1046 request, response, this.responseProducer, exchangeContext);
1047 state.setOutgoing(outgoing);
1048 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1049
1050 response.setEntity(new NStringEntity("stuff"));
1051 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
1052
1053 this.protocolHandler.responseReady(this.conn);
1054
1055 Assert.assertEquals(MessageState.READY, state.getRequestState());
1056 Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
1057
1058 Mockito.verify(this.conn).resetInput();
1059 Mockito.verify(this.httpProcessor).process(response, exchangeContext);
1060 Mockito.verify(this.conn).submitResponse(response);
1061 Mockito.verify(this.responseProducer, Mockito.never()).responseCompleted(exchangeContext);
1062 }
1063
1064 @Test
1065 public void testResponsePipelinedEmpty() throws Exception {
1066 final State state = new State();
1067
1068 state.setRequestState(MessageState.READY);
1069 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1070
1071 this.protocolHandler.responseReady(this.conn);
1072
1073 Assert.assertEquals(MessageState.READY, state.getRequestState());
1074 Assert.assertEquals(MessageState.READY, state.getResponseState());
1075 Assert.assertNull(state.getOutgoing());
1076
1077 Mockito.verify(conn).suspendOutput();
1078 Mockito.verifyNoMoreInteractions(requestHandler);
1079 }
1080
1081 @Test
1082 public void testResponseHandlePipelinedRequest() throws Exception {
1083 final State state = new State();
1084 final Queue<PipelineEntry> pipeline = state.getPipeline();
1085
1086 final HttpContext exchangeContext = new BasicHttpContext();
1087 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1088 final PipelineEntry entry = new PipelineEntry(request, request, null, requestHandler, exchangeContext);
1089 pipeline.add(entry);
1090
1091 state.setRequestState(MessageState.READY);
1092 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1093
1094 this.protocolHandler.responseReady(this.conn);
1095
1096 Assert.assertEquals(MessageState.READY, state.getRequestState());
1097 Assert.assertEquals(MessageState.INIT, state.getResponseState());
1098 Assert.assertNull(state.getOutgoing());
1099
1100 final ArgumentCaptor<HttpAsyncExchange> argCaptor = ArgumentCaptor.forClass(HttpAsyncExchange.class);
1101 Mockito.verify(this.requestHandler).handle(Matchers.same(request),
1102 argCaptor.capture(), Matchers.same(exchangeContext));
1103 final HttpAsyncExchange exchange = argCaptor.getValue();
1104
1105 Assert.assertNotNull(exchange);
1106 Assert.assertSame(request, exchange.getRequest());
1107 Assert.assertNotNull(exchange.getResponse());
1108 Assert.assertEquals(200, exchange.getResponse().getStatusLine().getStatusCode());
1109 }
1110
1111 @Test
1112 public void testResponseHandleFailedPipelinedRequest() throws Exception {
1113 final State state = new State();
1114 final Queue<PipelineEntry> pipeline = state.getPipeline();
1115
1116 final HttpContext exchangeContext = new BasicHttpContext();
1117 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1118 final Exception ex = new Exception("Opppsie");
1119 final PipelineEntry entry = new PipelineEntry(request, null, ex, requestHandler, exchangeContext);
1120 pipeline.add(entry);
1121
1122 state.setRequestState(MessageState.READY);
1123 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1124
1125 this.protocolHandler.responseReady(this.conn);
1126
1127 Assert.assertEquals(MessageState.READY, state.getRequestState());
1128 Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
1129
1130 final Outgoing outgoing = state.getOutgoing();
1131 Assert.assertNotNull(outgoing.getProducer());
1132 final HttpResponse response = outgoing.getResponse();
1133 Assert.assertNotNull(response);
1134 Assert.assertEquals(500, response.getStatusLine().getStatusCode());
1135
1136 Mockito.verify(this.requestHandler, Mockito.never()).handle(Matchers.<HttpRequest>any(),
1137 Matchers.<HttpAsyncExchange>any(), Matchers.<HttpContext>any());
1138 Mockito.verify(this.conn).submitResponse(Matchers.same(response));
1139 }
1140
1141 @Test(expected=HttpException.class)
1142 public void testInvalidResponseStatus() throws Exception {
1143 final State state = new State();
1144 final HttpContext exchangeContext = new BasicHttpContext();
1145 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
1146 HttpVersion.HTTP_1_1);
1147 final Incoming incoming = new Incoming(
1148 request, this.requestHandler, this.requestConsumer, exchangeContext);
1149 state.setIncoming(incoming);
1150 state.setRequestState(MessageState.COMPLETED);
1151 state.setResponseState(MessageState.INIT);
1152 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 112, "Something stupid");
1153 final Outgoing outgoing = new Outgoing(
1154 request, response, this.responseProducer, exchangeContext);
1155 state.setOutgoing(outgoing);
1156 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1157
1158 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
1159 Mockito.when(this.conn.isResponseSubmitted()).thenReturn(Boolean.FALSE);
1160
1161 this.protocolHandler.responseReady(this.conn);
1162 }
1163
1164 @Test(expected=HttpException.class)
1165 public void testInvalidResponseStatusToExpection() throws Exception {
1166 final State state = new State();
1167 final HttpContext exchangeContext = new BasicHttpContext();
1168 final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
1169 HttpVersion.HTTP_1_1);
1170 final Incoming incoming = new Incoming(
1171 request, this.requestHandler, this.requestConsumer, exchangeContext);
1172 state.setIncoming(incoming);
1173 state.setRequestState(MessageState.ACK_EXPECTED);
1174 state.setResponseState(MessageState.READY);
1175 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1176 response.setEntity(new NStringEntity("stuff"));
1177 final Outgoing outgoing = new Outgoing(
1178 request, response, this.responseProducer, exchangeContext);
1179 state.setOutgoing(outgoing);
1180 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1181
1182 Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
1183 Mockito.when(this.conn.isResponseSubmitted()).thenReturn(Boolean.FALSE);
1184
1185 this.protocolHandler.responseReady(this.conn);
1186 }
1187
1188 @Test
1189 public void testResponseTrigger() throws Exception {
1190 final State state = new State();
1191 state.setRequestState(MessageState.COMPLETED);
1192 state.setResponseState(MessageState.READY);
1193 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1194
1195 final HttpContext exchangeContext = new BasicHttpContext();
1196 final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
1197 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
1198 new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"),
1199 state, this.conn, exchangeContext);
1200 Assert.assertFalse(httpexchanage.isCompleted());
1201 httpexchanage.submitResponse(this.responseProducer);
1202 Assert.assertTrue(httpexchanage.isCompleted());
1203
1204 Assert.assertEquals(MessageState.COMPLETED, state.getRequestState());
1205 Assert.assertEquals(MessageState.READY, state.getResponseState());
1206 final Outgoing outgoing = state.getOutgoing();
1207 Assert.assertNotNull(outgoing);
1208 Assert.assertSame(this.responseProducer, outgoing.getProducer());
1209
1210 Mockito.verify(this.conn).requestOutput();
1211
1212 try {
1213 httpexchanage.submitResponse(Mockito.mock(HttpAsyncResponseProducer.class));
1214 Assert.fail("IllegalStateException expected");
1215 } catch (final IllegalStateException ex) {
1216 }
1217 }
1218
1219 @Test(expected=IllegalArgumentException.class)
1220 public void testResponseTriggerInvalidResponseProducer() throws Exception {
1221 final State state = new State();
1222 state.setRequestState(MessageState.ACK_EXPECTED);
1223 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1224
1225 final HttpContext exchangeContext = new BasicHttpContext();
1226 final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
1227 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
1228 new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"),
1229 state, this.conn, exchangeContext);
1230 httpexchanage.submitResponse(null);
1231 }
1232
1233 @Test
1234 public void testResponseContent() throws Exception {
1235 final State state = new State();
1236 state.setRequestState(MessageState.COMPLETED);
1237 state.setResponseState(MessageState.BODY_STREAM);
1238 final HttpContext exchangeContext = new BasicHttpContext();
1239 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1240 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1241 response.setEntity(new NStringEntity("stuff"));
1242 final Outgoing outgoing = new Outgoing(
1243 request, response, this.responseProducer, exchangeContext);
1244 state.setOutgoing(outgoing);
1245 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1246 Mockito.when(this.encoder.isCompleted()).thenReturn(Boolean.FALSE);
1247
1248 this.protocolHandler.outputReady(conn, this.encoder);
1249
1250 Assert.assertEquals(MessageState.COMPLETED, state.getRequestState());
1251 Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
1252
1253 Mockito.verify(this.responseProducer).produceContent(this.encoder, this.conn);
1254 Mockito.verify(this.conn, Mockito.never()).requestInput();
1255 Mockito.verify(this.conn, Mockito.never()).close();
1256 }
1257
1258 @Test
1259 public void testResponseContentCompleted() throws Exception {
1260 final State state = new State();
1261 state.setRequestState(MessageState.COMPLETED);
1262 state.setResponseState(MessageState.BODY_STREAM);
1263 final HttpContext exchangeContext = new BasicHttpContext();
1264 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1265 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1266 response.setEntity(new NStringEntity("stuff"));
1267 final Outgoing outgoing = new Outgoing(
1268 request, response, this.responseProducer, exchangeContext);
1269 state.setOutgoing(outgoing);
1270 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1271 Mockito.when(this.encoder.isCompleted()).thenReturn(true);
1272 Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
1273
1274 this.protocolHandler.outputReady(conn, this.encoder);
1275
1276 Assert.assertEquals(MessageState.READY, state.getResponseState());
1277
1278 Mockito.verify(this.responseProducer).produceContent(this.encoder, this.conn);
1279 Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
1280 Mockito.verify(this.conn).requestInput();
1281 Mockito.verify(this.conn, Mockito.never()).close();
1282 }
1283
1284 @Test
1285 public void testResponseContentCompletedNoKeepAlive() throws Exception {
1286 final State state = new State();
1287 state.setRequestState(MessageState.COMPLETED);
1288 state.setResponseState(MessageState.BODY_STREAM);
1289 final HttpContext exchangeContext = new BasicHttpContext();
1290 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1291 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1292 response.setEntity(new NStringEntity("stuff"));
1293 final Outgoing outgoing = new Outgoing(
1294 request, response, this.responseProducer, exchangeContext);
1295 state.setOutgoing(outgoing);
1296 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1297 Mockito.when(this.encoder.isCompleted()).thenReturn(true);
1298 Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.FALSE);
1299
1300 this.protocolHandler.outputReady(conn, this.encoder);
1301
1302 Assert.assertEquals(MessageState.READY, state.getResponseState());
1303
1304 Mockito.verify(this.responseProducer).produceContent(this.encoder, this.conn);
1305 Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
1306 Mockito.verify(this.conn, Mockito.never()).requestInput();
1307 Mockito.verify(this.conn).close();
1308 }
1309
1310 @Test
1311 public void testEndOfInput() throws Exception {
1312
1313 Mockito.when(this.conn.getSocketTimeout()).thenReturn(1000);
1314
1315 this.protocolHandler.endOfInput(this.conn);
1316
1317 Mockito.verify(this.conn, Mockito.never()).setSocketTimeout(Matchers.anyInt());
1318 Mockito.verify(this.conn).close();
1319 }
1320
1321 @Test
1322 public void testEndOfInputNoTimeout() throws Exception {
1323
1324 Mockito.when(this.conn.getSocketTimeout()).thenReturn(0);
1325
1326 this.protocolHandler.endOfInput(this.conn);
1327
1328 Mockito.verify(this.conn).setSocketTimeout(1000);
1329 Mockito.verify(this.conn).close();
1330 }
1331
1332 @Test
1333 public void testTimeoutActiveConnection() throws Exception {
1334 final State state = new State();
1335 final HttpContext exchangeContext = new BasicHttpContext();
1336 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1337 final Incoming incoming = new Incoming(
1338 request, this.requestHandler, this.requestConsumer, exchangeContext);
1339 state.setIncoming(incoming);
1340 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1341 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
1342 Mockito.when(this.conn.getStatus()).thenReturn(NHttpConnection.ACTIVE, NHttpConnection.CLOSED);
1343
1344 this.protocolHandler.timeout(this.conn);
1345
1346 Mockito.verify(this.conn, Mockito.atLeastOnce()).close();
1347 Mockito.verify(this.conn, Mockito.never()).setSocketTimeout(Matchers.anyInt());
1348 }
1349
1350 @Test
1351 public void testTimeoutActiveConnectionBufferedData() throws Exception {
1352 final State state = new State();
1353 final HttpContext exchangeContext = new BasicHttpContext();
1354 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1355 final Incoming incoming = new Incoming(
1356 request, this.requestHandler, this.requestConsumer, exchangeContext);
1357 state.setIncoming(incoming);
1358 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1359 Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
1360 Mockito.when(this.conn.getStatus()).thenReturn(NHttpConnection.ACTIVE, NHttpConnection.CLOSING);
1361
1362 this.protocolHandler.timeout(this.conn);
1363
1364 Mockito.verify(this.conn).close();
1365 Mockito.verify(this.conn).setSocketTimeout(250);
1366 }
1367
1368 @Test
1369 public void testTimeoutClosingConnection() throws Exception {
1370 final State state = new State();
1371 final HttpContext exchangeContext = new BasicHttpContext();
1372 final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1373 final Incoming incoming = new Incoming(
1374 request, this.requestHandler, this.requestConsumer, exchangeContext);
1375 state.setIncoming(incoming);
1376 final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1377 final Outgoing outgoing = new Outgoing(
1378 request, response, this.responseProducer, exchangeContext);
1379 state.setOutgoing(outgoing);
1380 this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1381 Mockito.when(this.conn.getStatus()).thenReturn(NHttpConnection.CLOSING);
1382
1383 this.protocolHandler.timeout(this.conn);
1384
1385 Mockito.verify(this.conn).shutdown();
1386 Mockito.verify(this.requestConsumer).failed(Matchers.any(SocketTimeoutException.class));
1387 Mockito.verify(this.requestConsumer).close();
1388 Mockito.verify(this.responseProducer).failed(Matchers.any(SocketTimeoutException.class));
1389 Mockito.verify(this.responseProducer).close();
1390 }
1391
1392 }