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