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
32 import org.apache.http.ConnectionReuseStrategy;
33 import org.apache.http.HttpEntity;
34 import org.apache.http.HttpEntityEnclosingRequest;
35 import org.apache.http.HttpException;
36 import org.apache.http.HttpRequest;
37 import org.apache.http.HttpResponse;
38 import org.apache.http.HttpResponseFactory;
39 import org.apache.http.HttpStatus;
40 import org.apache.http.HttpVersion;
41 import org.apache.http.MethodNotSupportedException;
42 import org.apache.http.ProtocolException;
43 import org.apache.http.ProtocolVersion;
44 import org.apache.http.UnsupportedHttpVersionException;
45 import org.apache.http.annotation.ThreadingBehavior;
46 import org.apache.http.annotation.Contract;
47 import org.apache.http.nio.ContentDecoder;
48 import org.apache.http.nio.ContentEncoder;
49 import org.apache.http.nio.IOControl;
50 import org.apache.http.nio.NHttpServerConnection;
51 import org.apache.http.nio.NHttpServiceHandler;
52 import org.apache.http.nio.entity.ConsumingNHttpEntity;
53 import org.apache.http.nio.entity.NByteArrayEntity;
54 import org.apache.http.nio.entity.NHttpEntityWrapper;
55 import org.apache.http.nio.entity.ProducingNHttpEntity;
56 import org.apache.http.nio.util.ByteBufferAllocator;
57 import org.apache.http.nio.util.HeapByteBufferAllocator;
58 import org.apache.http.params.DefaultedHttpParams;
59 import org.apache.http.params.HttpParams;
60 import org.apache.http.protocol.ExecutionContext;
61 import org.apache.http.protocol.HttpContext;
62 import org.apache.http.protocol.HttpExpectationVerifier;
63 import org.apache.http.protocol.HttpProcessor;
64 import org.apache.http.util.Args;
65 import org.apache.http.util.Asserts;
66 import org.apache.http.util.EncodingUtils;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 @Deprecated
104 @Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL)
105 public class AsyncNHttpServiceHandler extends NHttpHandlerBase
106 implements NHttpServiceHandler {
107
108 protected final HttpResponseFactory responseFactory;
109
110 protected NHttpRequestHandlerResolver handlerResolver;
111 protected HttpExpectationVerifier expectationVerifier;
112
113 public AsyncNHttpServiceHandler(
114 final HttpProcessor httpProcessor,
115 final HttpResponseFactory responseFactory,
116 final ConnectionReuseStrategy connStrategy,
117 final ByteBufferAllocator allocator,
118 final HttpParams params) {
119 super(httpProcessor, connStrategy, allocator, params);
120 Args.notNull(responseFactory, "Response factory");
121 this.responseFactory = responseFactory;
122 }
123
124 public AsyncNHttpServiceHandler(
125 final HttpProcessor httpProcessor,
126 final HttpResponseFactory responseFactory,
127 final ConnectionReuseStrategy connStrategy,
128 final HttpParams params) {
129 this(httpProcessor, responseFactory, connStrategy, HeapByteBufferAllocator.INSTANCE, params);
130 }
131
132 public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
133 this.expectationVerifier = expectationVerifier;
134 }
135
136 public void setHandlerResolver(final NHttpRequestHandlerResolver handlerResolver) {
137 this.handlerResolver = handlerResolver;
138 }
139
140 @Override
141 public void connected(final NHttpServerConnection conn) {
142 final HttpContext context = conn.getContext();
143
144 final ServerConnState connState = new ServerConnState();
145 context.setAttribute(CONN_STATE, connState);
146 context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
147
148 if (this.eventListener != null) {
149 this.eventListener.connectionOpen(conn);
150 }
151 }
152
153 @Override
154 public void requestReceived(final NHttpServerConnection conn) {
155 final HttpContext context = conn.getContext();
156
157 final ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
158
159 final HttpRequest request = conn.getHttpRequest();
160 request.setParams(new DefaultedHttpParams(request.getParams(), this.params));
161
162 connState.setRequest(request);
163
164 final NHttpRequestHandler requestHandler = getRequestHandler(request);
165 connState.setRequestHandler(requestHandler);
166
167 ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
168 if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
169
170 ver = HttpVersion.HTTP_1_1;
171 }
172
173 HttpResponse response;
174
175 try {
176
177 if (request instanceof HttpEntityEnclosingRequest) {
178 final HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) request;
179 if (entityRequest.expectContinue()) {
180 response = this.responseFactory.newHttpResponse(
181 ver, HttpStatus.SC_CONTINUE, context);
182 response.setParams(
183 new DefaultedHttpParams(response.getParams(), this.params));
184
185 if (this.expectationVerifier != null) {
186 try {
187 this.expectationVerifier.verify(request, response, context);
188 } catch (final HttpException ex) {
189 response = this.responseFactory.newHttpResponse(
190 HttpVersion.HTTP_1_0,
191 HttpStatus.SC_INTERNAL_SERVER_ERROR,
192 context);
193 response.setParams(
194 new DefaultedHttpParams(response.getParams(), this.params));
195 handleException(ex, response);
196 }
197 }
198
199 if (response.getStatusLine().getStatusCode() < 200) {
200
201
202 conn.submitResponse(response);
203 } else {
204 conn.resetInput();
205 sendResponse(conn, request, response);
206 }
207 }
208
209 ConsumingNHttpEntity consumingEntity = null;
210
211
212 if (requestHandler != null) {
213 consumingEntity = requestHandler.entityRequest(entityRequest, context);
214 }
215 if (consumingEntity == null) {
216 consumingEntity = new NullNHttpEntity(entityRequest.getEntity());
217 }
218 entityRequest.setEntity(consumingEntity);
219 connState.setConsumingEntity(consumingEntity);
220
221 } else {
222
223
224 conn.suspendInput();
225 processRequest(conn, request);
226 }
227
228 } catch (final IOException ex) {
229 shutdownConnection(conn, ex);
230 if (this.eventListener != null) {
231 this.eventListener.fatalIOException(ex, conn);
232 }
233 } catch (final HttpException ex) {
234 closeConnection(conn, ex);
235 if (this.eventListener != null) {
236 this.eventListener.fatalProtocolException(ex, conn);
237 }
238 }
239
240 }
241
242 @Override
243 public void closed(final NHttpServerConnection conn) {
244 final HttpContext context = conn.getContext();
245
246 final ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
247 try {
248 connState.reset();
249 } catch (final IOException ex) {
250 if (this.eventListener != null) {
251 this.eventListener.fatalIOException(ex, conn);
252 }
253 }
254 if (this.eventListener != null) {
255 this.eventListener.connectionClosed(conn);
256 }
257 }
258
259 @Override
260 public void exception(final NHttpServerConnection conn, final HttpException httpex) {
261 if (conn.isResponseSubmitted()) {
262
263
264 closeConnection(conn, httpex);
265 if (eventListener != null) {
266 eventListener.fatalProtocolException(httpex, conn);
267 }
268 return;
269 }
270
271 final HttpContext context = conn.getContext();
272 try {
273 final HttpResponse response = this.responseFactory.newHttpResponse(
274 HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR, context);
275 response.setParams(
276 new DefaultedHttpParams(response.getParams(), this.params));
277 handleException(httpex, response);
278 response.setEntity(null);
279 sendResponse(conn, null, response);
280
281 } catch (final IOException ex) {
282 shutdownConnection(conn, ex);
283 if (this.eventListener != null) {
284 this.eventListener.fatalIOException(ex, conn);
285 }
286 } catch (final HttpException ex) {
287 closeConnection(conn, ex);
288 if (this.eventListener != null) {
289 this.eventListener.fatalProtocolException(ex, conn);
290 }
291 }
292 }
293
294 @Override
295 public void exception(final NHttpServerConnection conn, final IOException ex) {
296 shutdownConnection(conn, ex);
297
298 if (this.eventListener != null) {
299 this.eventListener.fatalIOException(ex, conn);
300 }
301 }
302
303 @Override
304 public void timeout(final NHttpServerConnection conn) {
305 handleTimeout(conn);
306 }
307
308 @Override
309 public void inputReady(final NHttpServerConnection conn, final ContentDecoder decoder) {
310 final HttpContext context = conn.getContext();
311 final ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
312
313 final HttpRequest request = connState.getRequest();
314 final ConsumingNHttpEntity consumingEntity = connState.getConsumingEntity();
315
316 try {
317
318 consumingEntity.consumeContent(decoder, conn);
319 if (decoder.isCompleted()) {
320 conn.suspendInput();
321 processRequest(conn, request);
322 }
323
324 } catch (final IOException ex) {
325 shutdownConnection(conn, ex);
326 if (this.eventListener != null) {
327 this.eventListener.fatalIOException(ex, conn);
328 }
329 } catch (final HttpException ex) {
330 closeConnection(conn, ex);
331 if (this.eventListener != null) {
332 this.eventListener.fatalProtocolException(ex, conn);
333 }
334 }
335 }
336
337 @Override
338 public void responseReady(final NHttpServerConnection conn) {
339 final HttpContext context = conn.getContext();
340 final ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
341
342 if (connState.isHandled()) {
343 return;
344 }
345
346 final HttpRequest request = connState.getRequest();
347
348 try {
349
350 final IOException ioex = connState.getIOException();
351 if (ioex != null) {
352 throw ioex;
353 }
354
355 final HttpException httpex = connState.getHttpException();
356 if (httpex != null) {
357 final HttpResponse response = this.responseFactory.newHttpResponse(HttpVersion.HTTP_1_0,
358 HttpStatus.SC_INTERNAL_SERVER_ERROR, context);
359 response.setParams(
360 new DefaultedHttpParams(response.getParams(), this.params));
361 handleException(httpex, response);
362 connState.setResponse(response);
363 }
364
365 final HttpResponse response = connState.getResponse();
366 if (response != null) {
367 connState.setHandled(true);
368 sendResponse(conn, request, response);
369 }
370
371 } catch (final IOException ex) {
372 shutdownConnection(conn, ex);
373 if (this.eventListener != null) {
374 this.eventListener.fatalIOException(ex, conn);
375 }
376 } catch (final HttpException ex) {
377 closeConnection(conn, ex);
378 if (this.eventListener != null) {
379 this.eventListener.fatalProtocolException(ex, conn);
380 }
381 }
382 }
383
384 @Override
385 public void outputReady(final NHttpServerConnection conn, final ContentEncoder encoder) {
386 final HttpContext context = conn.getContext();
387 final ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
388
389 final HttpResponse response = conn.getHttpResponse();
390
391 try {
392 final ProducingNHttpEntity entity = connState.getProducingEntity();
393 entity.produceContent(encoder, conn);
394
395 if (encoder.isCompleted()) {
396 connState.finishOutput();
397 if (!this.connStrategy.keepAlive(response, context)) {
398 conn.close();
399 } else {
400
401 connState.reset();
402 conn.requestInput();
403 }
404 responseComplete(response, context);
405 }
406
407 } catch (final IOException ex) {
408 shutdownConnection(conn, ex);
409 if (this.eventListener != null) {
410 this.eventListener.fatalIOException(ex, conn);
411 }
412 }
413 }
414
415 private void handleException(final HttpException ex, final HttpResponse response) {
416 int code = HttpStatus.SC_INTERNAL_SERVER_ERROR;
417 if (ex instanceof MethodNotSupportedException) {
418 code = HttpStatus.SC_NOT_IMPLEMENTED;
419 } else if (ex instanceof UnsupportedHttpVersionException) {
420 code = HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED;
421 } else if (ex instanceof ProtocolException) {
422 code = HttpStatus.SC_BAD_REQUEST;
423 }
424 response.setStatusCode(code);
425
426 final byte[] msg = EncodingUtils.getAsciiBytes(ex.getMessage());
427 final NByteArrayEntityayEntity.html#NByteArrayEntity">NByteArrayEntity entity = new NByteArrayEntity(msg);
428 entity.setContentType("text/plain; charset=US-ASCII");
429 response.setEntity(entity);
430 }
431
432
433
434
435 private void processRequest(
436 final NHttpServerConnection conn,
437 final HttpRequest request) throws IOException, HttpException {
438
439 final HttpContext context = conn.getContext();
440 final ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
441
442 ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
443
444 if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
445
446 ver = HttpVersion.HTTP_1_1;
447 }
448
449 final NHttpResponseTrigger trigger = new ResponseTriggerImpl(connState, conn);
450 try {
451 this.httpProcessor.process(request, context);
452
453 final NHttpRequestHandler handler = connState.getRequestHandler();
454 if (handler != null) {
455 final HttpResponse response = this.responseFactory.newHttpResponse(
456 ver, HttpStatus.SC_OK, context);
457 response.setParams(
458 new DefaultedHttpParams(response.getParams(), this.params));
459
460 handler.handle(
461 request,
462 response,
463 trigger,
464 context);
465 } else {
466 final HttpResponse response = this.responseFactory.newHttpResponse(ver,
467 HttpStatus.SC_NOT_IMPLEMENTED, context);
468 response.setParams(
469 new DefaultedHttpParams(response.getParams(), this.params));
470 trigger.submitResponse(response);
471 }
472
473 } catch (final HttpException ex) {
474 trigger.handleException(ex);
475 }
476 }
477
478 private void sendResponse(
479 final NHttpServerConnection conn,
480 final HttpRequest request,
481 final HttpResponse response) throws IOException, HttpException {
482 final HttpContext context = conn.getContext();
483 final ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
484
485
486 connState.finishInput();
487
488
489 context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
490 this.httpProcessor.process(response, context);
491 context.setAttribute(ExecutionContext.HTTP_REQUEST, null);
492
493 if (response.getEntity() != null && !canResponseHaveBody(request, response)) {
494 response.setEntity(null);
495 }
496
497 final HttpEntity entity = response.getEntity();
498 if (entity != null) {
499 if (entity instanceof ProducingNHttpEntity) {
500 connState.setProducingEntity((ProducingNHttpEntity) entity);
501 } else {
502 connState.setProducingEntity(new NHttpEntityWrapper(entity));
503 }
504 }
505
506 conn.submitResponse(response);
507
508 if (entity == null) {
509 if (!this.connStrategy.keepAlive(response, context)) {
510 conn.close();
511 } else {
512
513 connState.reset();
514 conn.requestInput();
515 }
516 responseComplete(response, context);
517 }
518 }
519
520
521
522
523
524
525
526 protected void responseComplete(final HttpResponse response, final HttpContext context) {
527 }
528
529 private NHttpRequestHandler getRequestHandler(final HttpRequest request) {
530 NHttpRequestHandler handler = null;
531 if (this.handlerResolver != null) {
532 final String requestURI = request.getRequestLine().getUri();
533 handler = this.handlerResolver.lookup(requestURI);
534 }
535
536 return handler;
537 }
538
539 protected static class ServerConnState {
540
541 private volatile NHttpRequestHandler requestHandler;
542 private volatile HttpRequest request;
543 private volatile ConsumingNHttpEntity consumingEntity;
544 private volatile HttpResponse response;
545 private volatile ProducingNHttpEntity producingEntity;
546 private volatile IOException ioex;
547 private volatile HttpException httpex;
548 private volatile boolean handled;
549
550 public void finishInput() throws IOException {
551 if (this.consumingEntity != null) {
552 this.consumingEntity.finish();
553 this.consumingEntity = null;
554 }
555 }
556
557 public void finishOutput() throws IOException {
558 if (this.producingEntity != null) {
559 this.producingEntity.finish();
560 this.producingEntity = null;
561 }
562 }
563
564 public void reset() throws IOException {
565 finishInput();
566 this.request = null;
567 finishOutput();
568 this.handled = false;
569 this.response = null;
570 this.ioex = null;
571 this.httpex = null;
572 this.requestHandler = null;
573 }
574
575 public NHttpRequestHandler getRequestHandler() {
576 return this.requestHandler;
577 }
578
579 public void setRequestHandler(final NHttpRequestHandler requestHandler) {
580 this.requestHandler = requestHandler;
581 }
582
583 public HttpRequest getRequest() {
584 return this.request;
585 }
586
587 public void setRequest(final HttpRequest request) {
588 this.request = request;
589 }
590
591 public ConsumingNHttpEntity getConsumingEntity() {
592 return this.consumingEntity;
593 }
594
595 public void setConsumingEntity(final ConsumingNHttpEntity consumingEntity) {
596 this.consumingEntity = consumingEntity;
597 }
598
599 public HttpResponse getResponse() {
600 return this.response;
601 }
602
603 public void setResponse(final HttpResponse response) {
604 this.response = response;
605 }
606
607 public ProducingNHttpEntity getProducingEntity() {
608 return this.producingEntity;
609 }
610
611 public void setProducingEntity(final ProducingNHttpEntity producingEntity) {
612 this.producingEntity = producingEntity;
613 }
614
615 public IOException getIOException() {
616 return this.ioex;
617 }
618
619 public IOException getIOExepction() {
620 return this.ioex;
621 }
622
623 public void setIOException(final IOException ex) {
624 this.ioex = ex;
625 }
626
627 public void setIOExepction(final IOException ex) {
628 this.ioex = ex;
629 }
630
631 public HttpException getHttpException() {
632 return this.httpex;
633 }
634
635 public HttpException getHttpExepction() {
636 return this.httpex;
637 }
638
639 public void setHttpException(final HttpException ex) {
640 this.httpex = ex;
641 }
642
643 public void setHttpExepction(final HttpException ex) {
644 this.httpex = ex;
645 }
646
647 public boolean isHandled() {
648 return this.handled;
649 }
650
651 public void setHandled(final boolean handled) {
652 this.handled = handled;
653 }
654
655 }
656
657 private static class ResponseTriggerImpl implements NHttpResponseTrigger {
658
659 private final ServerConnState connState;
660 private final IOControl iocontrol;
661
662 private volatile boolean triggered;
663
664 public ResponseTriggerImpl(final ServerConnState connState, final IOControl iocontrol) {
665 super();
666 this.connState = connState;
667 this.iocontrol = iocontrol;
668 }
669
670 @Override
671 public void submitResponse(final HttpResponse response) {
672 Args.notNull(response, "Response");
673 Asserts.check(!this.triggered, "Response already triggered");
674 this.triggered = true;
675 this.connState.setResponse(response);
676 this.iocontrol.requestOutput();
677 }
678
679 @Override
680 public void handleException(final HttpException ex) {
681 Asserts.check(!this.triggered, "Response already triggered");
682 this.triggered = true;
683 this.connState.setHttpException(ex);
684 this.iocontrol.requestOutput();
685 }
686
687 @Override
688 public void handleException(final IOException ex) {
689 Asserts.check(!this.triggered, "Response already triggered");
690 this.triggered = true;
691 this.connState.setIOException(ex);
692 this.iocontrol.requestOutput();
693 }
694
695 }
696
697 }