~ubuntu-branches/ubuntu/trusty/httpcomponents-core/trusty

« back to all changes in this revision

Viewing changes to httpcore-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpServiceHandler.java

  • Committer: Bazaar Package Importer
  • Author(s): David Paleino
  • Date: 2010-06-12 08:37:34 UTC
  • Revision ID: james.westby@ubuntu.com-20100612083734-1y8kp6qm4sjk60az
Tags: upstream-4.0.1
ImportĀ upstreamĀ versionĀ 4.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0.1/httpcore-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpServiceHandler.java $
 
3
 * $Revision: 747992 $
 
4
 * $Date: 2009-02-26 04:03:22 +0100 (Thu, 26 Feb 2009) $
 
5
 *
 
6
 * ====================================================================
 
7
 * Licensed to the Apache Software Foundation (ASF) under one
 
8
 * or more contributor license agreements.  See the NOTICE file
 
9
 * distributed with this work for additional information
 
10
 * regarding copyright ownership.  The ASF licenses this file
 
11
 * to you under the Apache License, Version 2.0 (the
 
12
 * "License"); you may not use this file except in compliance
 
13
 * with the License.  You may obtain a copy of the License at
 
14
 *
 
15
 *   http://www.apache.org/licenses/LICENSE-2.0
 
16
 *
 
17
 * Unless required by applicable law or agreed to in writing,
 
18
 * software distributed under the License is distributed on an
 
19
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
20
 * KIND, either express or implied.  See the License for the
 
21
 * specific language governing permissions and limitations
 
22
 * under the License.
 
23
 * ====================================================================
 
24
 *
 
25
 * This software consists of voluntary contributions made by many
 
26
 * individuals on behalf of the Apache Software Foundation.  For more
 
27
 * information on the Apache Software Foundation, please see
 
28
 * <http://www.apache.org/>.
 
29
 *
 
30
 */
 
31
 
 
32
package org.apache.http.nio.protocol;
 
33
 
 
34
import java.io.IOException;
 
35
 
 
36
import org.apache.http.ConnectionReuseStrategy;
 
37
import org.apache.http.HttpEntity;
 
38
import org.apache.http.HttpEntityEnclosingRequest;
 
39
import org.apache.http.HttpException;
 
40
import org.apache.http.HttpRequest;
 
41
import org.apache.http.HttpResponse;
 
42
import org.apache.http.HttpResponseFactory;
 
43
import org.apache.http.HttpStatus;
 
44
import org.apache.http.HttpVersion;
 
45
import org.apache.http.MethodNotSupportedException;
 
46
import org.apache.http.ProtocolException;
 
47
import org.apache.http.ProtocolVersion;
 
48
import org.apache.http.UnsupportedHttpVersionException;
 
49
import org.apache.http.nio.ContentDecoder;
 
50
import org.apache.http.nio.ContentEncoder;
 
51
import org.apache.http.nio.IOControl;
 
52
import org.apache.http.nio.NHttpServerConnection;
 
53
import org.apache.http.nio.NHttpServiceHandler;
 
54
import org.apache.http.nio.entity.ConsumingNHttpEntity;
 
55
import org.apache.http.nio.entity.ConsumingNHttpEntityTemplate;
 
56
import org.apache.http.nio.entity.NByteArrayEntity;
 
57
import org.apache.http.nio.entity.NHttpEntityWrapper;
 
58
import org.apache.http.nio.entity.ProducingNHttpEntity;
 
59
import org.apache.http.nio.entity.SkipContentListener;
 
60
import org.apache.http.nio.util.ByteBufferAllocator;
 
61
import org.apache.http.nio.util.HeapByteBufferAllocator;
 
62
import org.apache.http.params.DefaultedHttpParams;
 
63
import org.apache.http.params.HttpParams;
 
64
import org.apache.http.protocol.ExecutionContext;
 
65
import org.apache.http.protocol.HttpContext;
 
66
import org.apache.http.protocol.HttpExpectationVerifier;
 
67
import org.apache.http.protocol.HttpProcessor;
 
68
import org.apache.http.util.EncodingUtils;
 
69
 
 
70
/**
 
71
 * Fully asynchronous HTTP server side protocol handler implementation that 
 
72
 * implements the essential requirements of the HTTP protocol for the server 
 
73
 * side message processing as described by RFC 2616. It is capable of processing 
 
74
 * HTTP requests with nearly constant memory footprint. Only HTTP message heads 
 
75
 * are stored in memory, while content of message bodies is streamed directly 
 
76
 * from the entity to the underlying channel (and vice versa) 
 
77
 * {@link ConsumingNHttpEntity} and {@link ProducingNHttpEntity} interfaces.
 
78
 * <p/>
 
79
 * When using this class, it is important to ensure that entities supplied for 
 
80
 * writing implement {@link ProducingNHttpEntity}. Doing so will allow the 
 
81
 * entity to be written out asynchronously. If entities supplied for writing do 
 
82
 * not implement {@link ProducingNHttpEntity}, a delegate is added that buffers 
 
83
 * the entire contents in memory. Additionally, the buffering might take place 
 
84
 * in the I/O thread, which could cause I/O to block temporarily. For best 
 
85
 * results, ensure that all entities set on {@link HttpResponse}s from  
 
86
 * {@link NHttpRequestHandler}s implement {@link ProducingNHttpEntity}.
 
87
 * <p/>
 
88
 * If incoming requests enclose a content entity, {@link NHttpRequestHandler}s 
 
89
 * are expected to return a {@link ConsumingNHttpEntity} for reading the 
 
90
 * content. After the entity is finished reading the data,
 
91
 * {@link NHttpRequestHandler#handle(HttpRequest, HttpResponse, NHttpResponseTrigger, HttpContext)}
 
92
 * is called to generate a response.
 
93
 * <p/>
 
94
 * Individual {@link NHttpRequestHandler}s do not have to submit a response 
 
95
 * immediately. They can defer transmission of the HTTP response back to the 
 
96
 * client without blocking the I/O thread and to delegate the processing the 
 
97
 * HTTP request to a worker thread. The worker thread in its turn can use an 
 
98
 * instance of {@link NHttpResponseTrigger} passed as a parameter to submit 
 
99
 * a response as at a later point of time once the response becomes available.
 
100
 *
 
101
 * @see ConsumingNHttpEntity
 
102
 * @see ProducingNHttpEntity
 
103
 *
 
104
 * @since 4.0
 
105
 */
 
106
public class AsyncNHttpServiceHandler extends NHttpHandlerBase
 
107
                                      implements NHttpServiceHandler {
 
108
 
 
109
    protected final HttpResponseFactory responseFactory;
 
110
 
 
111
    protected NHttpRequestHandlerResolver handlerResolver;
 
112
    protected HttpExpectationVerifier expectationVerifier;
 
113
 
 
114
    public AsyncNHttpServiceHandler(
 
115
            final HttpProcessor httpProcessor,
 
116
            final HttpResponseFactory responseFactory,
 
117
            final ConnectionReuseStrategy connStrategy,
 
118
            final ByteBufferAllocator allocator,
 
119
            final HttpParams params) {
 
120
        super(httpProcessor, connStrategy, allocator, params);
 
121
        if (responseFactory == null) {
 
122
            throw new IllegalArgumentException("Response factory may not be null");
 
123
        }
 
124
        this.responseFactory = responseFactory;
 
125
    }
 
126
 
 
127
    public AsyncNHttpServiceHandler(
 
128
            final HttpProcessor httpProcessor,
 
129
            final HttpResponseFactory responseFactory,
 
130
            final ConnectionReuseStrategy connStrategy,
 
131
            final HttpParams params) {
 
132
        this(httpProcessor, responseFactory, connStrategy,
 
133
                new HeapByteBufferAllocator(), params);
 
134
    }
 
135
 
 
136
    public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
 
137
        this.expectationVerifier = expectationVerifier;
 
138
    }
 
139
 
 
140
    public void setHandlerResolver(final NHttpRequestHandlerResolver handlerResolver) {
 
141
        this.handlerResolver = handlerResolver;
 
142
    }
 
143
 
 
144
    public void connected(final NHttpServerConnection conn) {
 
145
        HttpContext context = conn.getContext();
 
146
 
 
147
        ServerConnState connState = new ServerConnState();
 
148
        context.setAttribute(CONN_STATE, connState);
 
149
        context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
 
150
 
 
151
        if (this.eventListener != null) {
 
152
            this.eventListener.connectionOpen(conn);
 
153
        }
 
154
    }
 
155
 
 
156
    public void requestReceived(final NHttpServerConnection conn) {
 
157
        HttpContext context = conn.getContext();
 
158
 
 
159
        ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
 
160
 
 
161
        HttpRequest request = conn.getHttpRequest();
 
162
        request.setParams(new DefaultedHttpParams(request.getParams(), this.params));
 
163
 
 
164
        connState.setRequest(request);
 
165
 
 
166
        NHttpRequestHandler requestHandler = getRequestHandler(request);
 
167
        connState.setRequestHandler(requestHandler);
 
168
 
 
169
        ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
 
170
        if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
 
171
            // Downgrade protocol version if greater than HTTP/1.1
 
172
            ver = HttpVersion.HTTP_1_1;
 
173
        }
 
174
 
 
175
        HttpResponse response;
 
176
 
 
177
        try {
 
178
 
 
179
            if (request instanceof HttpEntityEnclosingRequest) {
 
180
                if (((HttpEntityEnclosingRequest) request).expectContinue()) {
 
181
                    response = this.responseFactory.newHttpResponse(
 
182
                            ver, HttpStatus.SC_CONTINUE, context);
 
183
                    response.setParams(
 
184
                            new DefaultedHttpParams(response.getParams(), this.params));
 
185
 
 
186
                    if (this.expectationVerifier != null) {
 
187
                        try {
 
188
                            this.expectationVerifier.verify(request, response, context);
 
189
                        } catch (HttpException ex) {
 
190
                            response = this.responseFactory.newHttpResponse(
 
191
                                    HttpVersion.HTTP_1_0,
 
192
                                    HttpStatus.SC_INTERNAL_SERVER_ERROR,
 
193
                                    context);
 
194
                            response.setParams(
 
195
                                    new DefaultedHttpParams(response.getParams(), this.params));
 
196
                            handleException(ex, response);
 
197
                        }
 
198
                    }
 
199
 
 
200
                    if (response.getStatusLine().getStatusCode() < 200) {
 
201
                        // Send 1xx response indicating the server expections
 
202
                        // have been met
 
203
                        conn.submitResponse(response);
 
204
                    } else {
 
205
                        conn.resetInput();
 
206
                        sendResponse(conn, request, response);
 
207
                    }
 
208
                }
 
209
                // Request content is expected.
 
210
                HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
 
211
 
 
212
                // Lookup request handler for this request
 
213
                if (requestHandler != null) {
 
214
                    ConsumingNHttpEntity consumingEntity = requestHandler.entityRequest(
 
215
                            (HttpEntityEnclosingRequest) request, context);
 
216
                    if (consumingEntity == null) {
 
217
                        consumingEntity = new ConsumingNHttpEntityTemplate(
 
218
                                entity,
 
219
                                new SkipContentListener(this.allocator));
 
220
                    }
 
221
                    ((HttpEntityEnclosingRequest) request).setEntity(consumingEntity);
 
222
                    connState.setConsumingEntity(consumingEntity);
 
223
                }
 
224
 
 
225
            } else {
 
226
                // No request content is expected.
 
227
                // Process request right away
 
228
                conn.suspendInput();
 
229
                processRequest(conn, request);
 
230
            }
 
231
 
 
232
        } catch (IOException ex) {
 
233
            shutdownConnection(conn, ex);
 
234
            if (this.eventListener != null) {
 
235
                this.eventListener.fatalIOException(ex, conn);
 
236
            }
 
237
        } catch (HttpException ex) {
 
238
            closeConnection(conn, ex);
 
239
            if (this.eventListener != null) {
 
240
                this.eventListener.fatalProtocolException(ex, conn);
 
241
            }
 
242
        }
 
243
 
 
244
    }
 
245
 
 
246
    public void closed(final NHttpServerConnection conn) {
 
247
        HttpContext context = conn.getContext();
 
248
 
 
249
        ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
 
250
        try {
 
251
            connState.reset();
 
252
        } catch (IOException ex) {
 
253
            if (this.eventListener != null) {
 
254
                this.eventListener.fatalIOException(ex, conn);
 
255
            }
 
256
        }
 
257
        if (this.eventListener != null) {
 
258
            this.eventListener.connectionClosed(conn);
 
259
        }
 
260
    }
 
261
 
 
262
    public void exception(final NHttpServerConnection conn, final HttpException httpex) {
 
263
        if (conn.isResponseSubmitted()) {
 
264
            // There is not much that we can do if a response head
 
265
            // has already been submitted
 
266
            closeConnection(conn, httpex);
 
267
            if (eventListener != null) {
 
268
                eventListener.fatalProtocolException(httpex, conn);
 
269
            }
 
270
            return;
 
271
        }
 
272
 
 
273
        HttpContext context = conn.getContext();
 
274
        try {
 
275
            HttpResponse response = this.responseFactory.newHttpResponse(
 
276
                    HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR, context);
 
277
            response.setParams(
 
278
                    new DefaultedHttpParams(response.getParams(), this.params));
 
279
            handleException(httpex, response);
 
280
            response.setEntity(null);
 
281
            sendResponse(conn, null, response);
 
282
 
 
283
        } catch (IOException ex) {
 
284
            shutdownConnection(conn, ex);
 
285
            if (this.eventListener != null) {
 
286
                this.eventListener.fatalIOException(ex, conn);
 
287
            }
 
288
        } catch (HttpException ex) {
 
289
            closeConnection(conn, ex);
 
290
            if (this.eventListener != null) {
 
291
                this.eventListener.fatalProtocolException(ex, conn);
 
292
            }
 
293
        }
 
294
    }
 
295
 
 
296
    public void exception(final NHttpServerConnection conn, final IOException ex) {
 
297
        shutdownConnection(conn, ex);
 
298
 
 
299
        if (this.eventListener != null) {
 
300
            this.eventListener.fatalIOException(ex, conn);
 
301
        }
 
302
    }
 
303
 
 
304
    public void timeout(final NHttpServerConnection conn) {
 
305
        handleTimeout(conn);
 
306
    }
 
307
 
 
308
    public void inputReady(final NHttpServerConnection conn, final ContentDecoder decoder) {
 
309
        HttpContext context = conn.getContext();
 
310
        ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
 
311
 
 
312
        HttpRequest request = connState.getRequest();
 
313
        ConsumingNHttpEntity consumingEntity = connState.getConsumingEntity();
 
314
 
 
315
        try {
 
316
 
 
317
            consumingEntity.consumeContent(decoder, conn);
 
318
            if (decoder.isCompleted()) {
 
319
                conn.suspendInput();
 
320
                processRequest(conn, request);
 
321
            }
 
322
 
 
323
        } catch (IOException ex) {
 
324
            shutdownConnection(conn, ex);
 
325
            if (this.eventListener != null) {
 
326
                this.eventListener.fatalIOException(ex, conn);
 
327
            }
 
328
        } catch (HttpException ex) {
 
329
            closeConnection(conn, ex);
 
330
            if (this.eventListener != null) {
 
331
                this.eventListener.fatalProtocolException(ex, conn);
 
332
            }
 
333
        }
 
334
    }
 
335
 
 
336
    public void responseReady(final NHttpServerConnection conn) {
 
337
        HttpContext context = conn.getContext();
 
338
        ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
 
339
 
 
340
        if (connState.isHandled()) {
 
341
            return;
 
342
        }
 
343
 
 
344
        HttpRequest request = connState.getRequest();
 
345
 
 
346
        try {
 
347
 
 
348
            IOException ioex = connState.getIOExepction();
 
349
            if (ioex != null) {
 
350
                throw ioex;
 
351
            }
 
352
 
 
353
            HttpException httpex = connState.getHttpExepction();
 
354
            if (httpex != null) {
 
355
                HttpResponse response = this.responseFactory.newHttpResponse(HttpVersion.HTTP_1_0,
 
356
                        HttpStatus.SC_INTERNAL_SERVER_ERROR, context);
 
357
                response.setParams(
 
358
                        new DefaultedHttpParams(response.getParams(), this.params));
 
359
                handleException(httpex, response);
 
360
                connState.setResponse(response);
 
361
            }
 
362
 
 
363
            HttpResponse response = connState.getResponse();
 
364
            if (response != null) {
 
365
                connState.setHandled(true);
 
366
                sendResponse(conn, request, response);
 
367
            }
 
368
 
 
369
        } catch (IOException ex) {
 
370
            shutdownConnection(conn, ex);
 
371
            if (this.eventListener != null) {
 
372
                this.eventListener.fatalIOException(ex, conn);
 
373
            }
 
374
        } catch (HttpException ex) {
 
375
            closeConnection(conn, ex);
 
376
            if (this.eventListener != null) {
 
377
                this.eventListener.fatalProtocolException(ex, conn);
 
378
            }
 
379
        }
 
380
    }
 
381
 
 
382
    public void outputReady(final NHttpServerConnection conn, final ContentEncoder encoder) {
 
383
        HttpContext context = conn.getContext();
 
384
        ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
 
385
 
 
386
        HttpResponse response = conn.getHttpResponse();
 
387
 
 
388
        try {
 
389
            ProducingNHttpEntity entity = connState.getProducingEntity();
 
390
            entity.produceContent(encoder, conn);
 
391
 
 
392
            if (encoder.isCompleted()) {
 
393
                connState.finishOutput();
 
394
                if (!this.connStrategy.keepAlive(response, context)) {
 
395
                    conn.close();
 
396
                } else {
 
397
                    // Ready to process new request
 
398
                    connState.reset();
 
399
                    conn.requestInput();
 
400
                }
 
401
                responseComplete(response, context);
 
402
            }
 
403
 
 
404
        } catch (IOException ex) {
 
405
            shutdownConnection(conn, ex);
 
406
            if (this.eventListener != null) {
 
407
                this.eventListener.fatalIOException(ex, conn);
 
408
            }
 
409
        }
 
410
    }
 
411
 
 
412
    private void handleException(final HttpException ex, final HttpResponse response) {
 
413
        int code = HttpStatus.SC_INTERNAL_SERVER_ERROR;
 
414
        if (ex instanceof MethodNotSupportedException) {
 
415
            code = HttpStatus.SC_NOT_IMPLEMENTED;
 
416
        } else if (ex instanceof UnsupportedHttpVersionException) {
 
417
            code = HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED;
 
418
        } else if (ex instanceof ProtocolException) {
 
419
            code = HttpStatus.SC_BAD_REQUEST;
 
420
        }
 
421
        response.setStatusCode(code);
 
422
 
 
423
        byte[] msg = EncodingUtils.getAsciiBytes(ex.getMessage());
 
424
        NByteArrayEntity entity = new NByteArrayEntity(msg);
 
425
        entity.setContentType("text/plain; charset=US-ASCII");
 
426
        response.setEntity(entity);
 
427
    }
 
428
 
 
429
    /**
 
430
     * @throws HttpException - not thrown currently 
 
431
     */
 
432
    private void processRequest(
 
433
            final NHttpServerConnection conn,
 
434
            final HttpRequest request) throws IOException, HttpException {
 
435
 
 
436
        HttpContext context = conn.getContext();
 
437
        ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
 
438
 
 
439
        ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
 
440
 
 
441
        if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
 
442
            // Downgrade protocol version if greater than HTTP/1.1
 
443
            ver = HttpVersion.HTTP_1_1;
 
444
        }
 
445
 
 
446
        NHttpResponseTrigger trigger = new ResponseTriggerImpl(connState, conn);
 
447
        try {
 
448
            this.httpProcessor.process(request, context);
 
449
 
 
450
            NHttpRequestHandler handler = connState.getRequestHandler();
 
451
            if (handler != null) {
 
452
                HttpResponse response = this.responseFactory.newHttpResponse(
 
453
                        ver, HttpStatus.SC_OK, context);
 
454
                response.setParams(
 
455
                        new DefaultedHttpParams(response.getParams(), this.params));
 
456
 
 
457
                handler.handle(
 
458
                        request,
 
459
                        response,
 
460
                        trigger,
 
461
                        context);
 
462
            } else {
 
463
                HttpResponse response = this.responseFactory.newHttpResponse(ver,
 
464
                        HttpStatus.SC_NOT_IMPLEMENTED, context);
 
465
                response.setParams(
 
466
                        new DefaultedHttpParams(response.getParams(), this.params));
 
467
                trigger.submitResponse(response);
 
468
            }
 
469
 
 
470
        } catch (HttpException ex) {
 
471
            trigger.handleException(ex);
 
472
        }
 
473
    }
 
474
 
 
475
    private void sendResponse(
 
476
            final NHttpServerConnection conn,
 
477
            final HttpRequest request,
 
478
            final HttpResponse response) throws IOException, HttpException {
 
479
        HttpContext context = conn.getContext();
 
480
        ServerConnState connState = (ServerConnState) context.getAttribute(CONN_STATE);
 
481
 
 
482
        // Now that a response is ready, we can cleanup the listener for the request.
 
483
        connState.finishInput();
 
484
 
 
485
        // Some processers need the request that generated this response.
 
486
        context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
 
487
        this.httpProcessor.process(response, context);
 
488
        context.setAttribute(ExecutionContext.HTTP_REQUEST, null);
 
489
 
 
490
        if (response.getEntity() != null && !canResponseHaveBody(request, response)) {
 
491
            response.setEntity(null);
 
492
        }
 
493
 
 
494
        HttpEntity entity = response.getEntity();
 
495
        if (entity != null) {
 
496
            if (entity instanceof ProducingNHttpEntity) {
 
497
                connState.setProducingEntity((ProducingNHttpEntity) entity);
 
498
            } else {
 
499
                connState.setProducingEntity(new NHttpEntityWrapper(entity));
 
500
            }
 
501
        }
 
502
 
 
503
        conn.submitResponse(response);
 
504
 
 
505
        if (entity == null) {
 
506
            if (!this.connStrategy.keepAlive(response, context)) {
 
507
                conn.close();
 
508
            } else {
 
509
                // Ready to process new request
 
510
                connState.reset();
 
511
                conn.requestInput();
 
512
            }
 
513
            responseComplete(response, context);
 
514
        }
 
515
    }
 
516
 
 
517
    /**
 
518
     * Signals that this response has been fully sent. This will be called after
 
519
     * submitting the response to a connection, if there is no entity in the
 
520
     * response. If there is an entity, it will be called after the entity has
 
521
     * completed.
 
522
     */
 
523
    protected void responseComplete(HttpResponse response, HttpContext context) {
 
524
    }
 
525
 
 
526
    private NHttpRequestHandler getRequestHandler(HttpRequest request) {
 
527
        NHttpRequestHandler handler = null;
 
528
         if (this.handlerResolver != null) {
 
529
             String requestURI = request.getRequestLine().getUri();
 
530
             handler = this.handlerResolver.lookup(requestURI);
 
531
         }
 
532
 
 
533
         return handler;
 
534
    }
 
535
 
 
536
    protected static class ServerConnState {
 
537
 
 
538
        private volatile NHttpRequestHandler requestHandler;
 
539
        private volatile HttpRequest request;
 
540
        private volatile ConsumingNHttpEntity consumingEntity;
 
541
        private volatile HttpResponse response;
 
542
        private volatile ProducingNHttpEntity producingEntity;
 
543
        private volatile IOException ioex;
 
544
        private volatile HttpException httpex;
 
545
        private volatile boolean handled;
 
546
 
 
547
        public void finishInput() throws IOException {
 
548
            if (this.consumingEntity != null) {
 
549
                this.consumingEntity.finish();
 
550
                this.consumingEntity = null;
 
551
            }
 
552
        }
 
553
 
 
554
        public void finishOutput() throws IOException {
 
555
            if (this.producingEntity != null) {
 
556
                this.producingEntity.finish();
 
557
                this.producingEntity = null;
 
558
            }
 
559
        }
 
560
 
 
561
        public void reset() throws IOException {
 
562
            finishInput();
 
563
            this.request = null;
 
564
            finishOutput();
 
565
            this.handled = false;
 
566
            this.response = null;
 
567
            this.ioex = null;
 
568
            this.httpex = null;
 
569
            this.requestHandler = null;
 
570
        }
 
571
 
 
572
        public NHttpRequestHandler getRequestHandler() {
 
573
            return this.requestHandler;
 
574
        }
 
575
 
 
576
        public void setRequestHandler(final NHttpRequestHandler requestHandler) {
 
577
            this.requestHandler = requestHandler;
 
578
        }
 
579
 
 
580
        public HttpRequest getRequest() {
 
581
            return this.request;
 
582
        }
 
583
 
 
584
        public void setRequest(final HttpRequest request) {
 
585
            this.request = request;
 
586
        }
 
587
 
 
588
        public ConsumingNHttpEntity getConsumingEntity() {
 
589
            return this.consumingEntity;
 
590
        }
 
591
 
 
592
        public void setConsumingEntity(final ConsumingNHttpEntity consumingEntity) {
 
593
            this.consumingEntity = consumingEntity;
 
594
        }
 
595
 
 
596
        public HttpResponse getResponse() {
 
597
            return this.response;
 
598
        }
 
599
 
 
600
        public void setResponse(final HttpResponse response) {
 
601
            this.response = response;
 
602
        }
 
603
 
 
604
        public ProducingNHttpEntity getProducingEntity() {
 
605
            return this.producingEntity;
 
606
        }
 
607
 
 
608
        public void setProducingEntity(final ProducingNHttpEntity producingEntity) {
 
609
            this.producingEntity = producingEntity;
 
610
        }
 
611
 
 
612
        public IOException getIOExepction() {
 
613
            return this.ioex;
 
614
        }
 
615
 
 
616
        public void setIOExepction(final IOException ex) {
 
617
            this.ioex = ex;
 
618
        }
 
619
 
 
620
        public HttpException getHttpExepction() {
 
621
            return this.httpex;
 
622
        }
 
623
 
 
624
        public void setHttpExepction(final HttpException ex) {
 
625
            this.httpex = ex;
 
626
        }
 
627
 
 
628
        public boolean isHandled() {
 
629
            return this.handled;
 
630
        }
 
631
 
 
632
        public void setHandled(boolean handled) {
 
633
            this.handled = handled;
 
634
        }
 
635
 
 
636
    }
 
637
 
 
638
    private static class ResponseTriggerImpl implements NHttpResponseTrigger {
 
639
 
 
640
        private final ServerConnState connState;
 
641
        private final IOControl iocontrol;
 
642
 
 
643
        private volatile boolean triggered;
 
644
 
 
645
        public ResponseTriggerImpl(final ServerConnState connState, final IOControl iocontrol) {
 
646
            super();
 
647
            this.connState = connState;
 
648
            this.iocontrol = iocontrol;
 
649
        }
 
650
 
 
651
        public void submitResponse(final HttpResponse response) {
 
652
            if (response == null) {
 
653
                throw new IllegalArgumentException("Response may not be null");
 
654
            }
 
655
            if (this.triggered) {
 
656
                throw new IllegalStateException("Response already triggered");
 
657
            }
 
658
            this.triggered = true;
 
659
            this.connState.setResponse(response);
 
660
            this.iocontrol.requestOutput();
 
661
        }
 
662
 
 
663
        public void handleException(final HttpException ex) {
 
664
            if (this.triggered) {
 
665
                throw new IllegalStateException("Response already triggered");
 
666
            }
 
667
            this.triggered = true;
 
668
            this.connState.setHttpExepction(ex);
 
669
            this.iocontrol.requestOutput();
 
670
        }
 
671
 
 
672
        public void handleException(final IOException ex) {
 
673
            if (this.triggered) {
 
674
                throw new IllegalStateException("Response already triggered");
 
675
            }
 
676
            this.triggered = true;
 
677
            this.connState.setIOExepction(ex);
 
678
            this.iocontrol.requestOutput();
 
679
        }
 
680
 
 
681
    }
 
682
 
 
683
}