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