View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.PrintWriter;
24  import javax.servlet.ServletInputStream;
25  import javax.servlet.ServletOutputStream;
26  import javax.servlet.http.HttpServletResponse;
27  
28  import org.eclipse.jetty.continuation.ContinuationThrowable;
29  import org.eclipse.jetty.http.EncodedHttpURI;
30  import org.eclipse.jetty.http.Generator;
31  import org.eclipse.jetty.http.HttpBuffers;
32  import org.eclipse.jetty.http.HttpContent;
33  import org.eclipse.jetty.http.HttpException;
34  import org.eclipse.jetty.http.HttpFields;
35  import org.eclipse.jetty.http.HttpGenerator;
36  import org.eclipse.jetty.http.HttpHeaderValues;
37  import org.eclipse.jetty.http.HttpHeaders;
38  import org.eclipse.jetty.http.HttpMethods;
39  import org.eclipse.jetty.http.HttpParser;
40  import org.eclipse.jetty.http.HttpStatus;
41  import org.eclipse.jetty.http.HttpURI;
42  import org.eclipse.jetty.http.HttpVersions;
43  import org.eclipse.jetty.http.MimeTypes;
44  import org.eclipse.jetty.http.Parser;
45  import org.eclipse.jetty.io.AbstractConnection;
46  import org.eclipse.jetty.io.Buffer;
47  import org.eclipse.jetty.io.BufferCache.CachedBuffer;
48  import org.eclipse.jetty.io.Buffers;
49  import org.eclipse.jetty.io.Connection;
50  import org.eclipse.jetty.io.EndPoint;
51  import org.eclipse.jetty.io.EofException;
52  import org.eclipse.jetty.io.RuntimeIOException;
53  import org.eclipse.jetty.io.UncheckedPrintWriter;
54  import org.eclipse.jetty.server.nio.NIOConnector;
55  import org.eclipse.jetty.server.ssl.SslConnector;
56  import org.eclipse.jetty.util.QuotedStringTokenizer;
57  import org.eclipse.jetty.util.StringUtil;
58  import org.eclipse.jetty.util.URIUtil;
59  import org.eclipse.jetty.util.log.Log;
60  import org.eclipse.jetty.util.log.Logger;
61  import org.eclipse.jetty.util.resource.Resource;
62  
63  /**
64   * <p>A HttpConnection represents the connection of a HTTP client to the server
65   * and is created by an instance of a {@link Connector}. It's prime function is
66   * to associate {@link Request} and {@link Response} instances with a {@link EndPoint}.
67   * </p>
68   * <p>
69   * A connection is also the prime mechanism used by jetty to recycle objects without
70   * pooling.  The {@link Request},  {@link Response}, {@link HttpParser}, {@link HttpGenerator}
71   * and {@link HttpFields} instances are all recycled for the duraction of
72   * a connection. Where appropriate, allocated buffers are also kept associated
73   * with the connection via the parser and/or generator.
74   * </p>
75   * <p>
76   * The connection state is held by 3 separate state machines: The request state, the
77   * response state and the continuation state.  All three state machines must be driven
78   * to completion for every request, and all three can complete in any order.
79   * </p>
80   * <p>
81   * The HttpConnection support protocol upgrade.  If on completion of a request, the
82   * response code is 101 (switch protocols), then the org.eclipse.jetty.io.Connection
83   * request attribute is checked to see if there is a new Connection instance. If so,
84   * the new connection is returned from {@link #handle()} and is used for future
85   * handling of the underlying connection.   Note that for switching protocols that
86   * don't use 101 responses (eg CONNECT), the response should be sent and then the
87   * status code changed to 101 before returning from the handler.  Implementors
88   * of new Connection types should be careful to extract any buffered data from
89   * (HttpParser)http.getParser()).getHeaderBuffer() and
90   * (HttpParser)http.getParser()).getBodyBuffer() to initialise their new connection.
91   * </p>
92   *
93   */
94  public abstract class AbstractHttpConnection  extends AbstractConnection
95  {
96      private static final Logger LOG = Log.getLogger(AbstractHttpConnection.class);
97  
98      private static final int UNKNOWN = -2;
99      private static final ThreadLocal<AbstractHttpConnection> __currentConnection = new ThreadLocal<AbstractHttpConnection>();
100 
101     private int _requests;
102 
103     protected final Connector _connector;
104     protected final Server _server;
105     protected final HttpURI _uri;
106 
107     protected final Parser _parser;
108     protected final HttpFields _requestFields;
109     protected final Request _request;
110     protected volatile ServletInputStream _in;
111 
112     protected final Generator _generator;
113     protected final HttpFields _responseFields;
114     protected final Response _response;
115     protected volatile Output _out;
116     protected volatile OutputWriter _writer;
117     protected volatile PrintWriter _printWriter;
118 
119     int _include;
120 
121     private Object _associatedObject; // associated object
122 
123     private int _version = UNKNOWN;
124 
125     private String _charset;
126     private boolean _expect = false;
127     private boolean _expect100Continue = false;
128     private boolean _expect102Processing = false;
129     private boolean _head = false;
130     private boolean _host = false;
131     private boolean _delayedHandling=false;
132     private boolean _earlyEOF = false;
133 
134     /* ------------------------------------------------------------ */
135     public static AbstractHttpConnection getCurrentConnection()
136     {
137         return __currentConnection.get();
138     }
139 
140     /* ------------------------------------------------------------ */
141     protected static void setCurrentConnection(AbstractHttpConnection connection)
142     {
143         __currentConnection.set(connection);
144     }
145 
146     /* ------------------------------------------------------------ */
147     public AbstractHttpConnection(Connector connector, EndPoint endpoint, Server server)
148     {
149         super(endpoint);
150         _uri = StringUtil.__UTF8.equals(URIUtil.__CHARSET)?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
151         _connector = connector;
152         HttpBuffers ab = (HttpBuffers)_connector;
153         _parser = newHttpParser(ab.getRequestBuffers(), endpoint, new RequestHandler());
154         _requestFields = new HttpFields();
155         _responseFields = new HttpFields();
156         _request = new Request(this);
157         _response = new Response(this);
158         _generator = newHttpGenerator(ab.getResponseBuffers(), endpoint);
159         _generator.setSendServerVersion(server.getSendServerVersion());
160         _server = server;
161     }
162 
163     /* ------------------------------------------------------------ */
164     protected AbstractHttpConnection(Connector connector, EndPoint endpoint, Server server,
165             Parser parser, Generator generator, Request request)
166     {
167         super(endpoint);
168 
169         _uri = URIUtil.__CHARSET.equals(StringUtil.__UTF8)?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
170         _connector = connector;
171         _parser = parser;
172         _requestFields = new HttpFields();
173         _responseFields = new HttpFields();
174         _request = request;
175         _response = new Response(this);
176         _generator = generator;
177         _generator.setSendServerVersion(server.getSendServerVersion());
178         _server = server;
179     }
180 
181     protected HttpParser newHttpParser(Buffers requestBuffers, EndPoint endpoint, HttpParser.EventHandler requestHandler)
182     {
183         return new HttpParser(requestBuffers, endpoint, requestHandler);
184     }
185 
186     protected HttpGenerator newHttpGenerator(Buffers responseBuffers, EndPoint endPoint)
187     {
188         return new HttpGenerator(responseBuffers, endPoint);
189     }
190 
191     /* ------------------------------------------------------------ */
192     /**
193      * @return the parser used by this connection
194      */
195     public Parser getParser()
196     {
197         return _parser;
198     }
199 
200     /* ------------------------------------------------------------ */
201     /**
202      * @return the number of requests handled by this connection
203      */
204     public int getRequests()
205     {
206         return _requests;
207     }
208 
209     /* ------------------------------------------------------------ */
210     public Server getServer()
211     {
212         return _server;
213     }
214 
215     /* ------------------------------------------------------------ */
216     /**
217      * @return Returns the associatedObject.
218      */
219     public Object getAssociatedObject()
220     {
221         return _associatedObject;
222     }
223 
224     /* ------------------------------------------------------------ */
225     /**
226      * @param associatedObject The associatedObject to set.
227      */
228     public void setAssociatedObject(Object associatedObject)
229     {
230         _associatedObject = associatedObject;
231     }
232 
233     /* ------------------------------------------------------------ */
234     /**
235      * @return Returns the connector.
236      */
237     public Connector getConnector()
238     {
239         return _connector;
240     }
241 
242     /* ------------------------------------------------------------ */
243     /**
244      * @return Returns the requestFields.
245      */
246     public HttpFields getRequestFields()
247     {
248         return _requestFields;
249     }
250 
251     /* ------------------------------------------------------------ */
252     /**
253      * @return Returns the responseFields.
254      */
255     public HttpFields getResponseFields()
256     {
257         return _responseFields;
258     }
259 
260     /* ------------------------------------------------------------ */
261     /**
262      * Find out if the request supports CONFIDENTIAL security.
263      * @param request the incoming HTTP request
264      * @return the result of calling {@link Connector#isConfidential(Request)}, or false
265      * if there is no connector
266      */
267     public boolean isConfidential(Request request)
268     {
269         return _connector != null && _connector.isConfidential(request);
270     }
271 
272     /* ------------------------------------------------------------ */
273     /**
274      * Find out if the request supports INTEGRAL security.
275      * @param request the incoming HTTP request
276      * @return the result of calling {@link Connector#isIntegral(Request)}, or false
277      * if there is no connector
278      */
279     public boolean isIntegral(Request request)
280     {
281         return _connector != null && _connector.isIntegral(request);
282     }
283 
284     /* ------------------------------------------------------------ */
285     /**
286      * @return <code>false</code> (this method is not yet implemented)
287      */
288     public boolean getResolveNames()
289     {
290         return _connector.getResolveNames();
291     }
292 
293     /* ------------------------------------------------------------ */
294     /**
295      * @return Returns the request.
296      */
297     public Request getRequest()
298     {
299         return _request;
300     }
301 
302     /* ------------------------------------------------------------ */
303     /**
304      * @return Returns the response.
305      */
306     public Response getResponse()
307     {
308         return _response;
309     }
310 
311     /* ------------------------------------------------------------ */
312     /**
313      * Get the inputStream from the connection.
314      * <p>
315      * If the associated response has the Expect header set to 100 Continue,
316      * then accessing the input stream indicates that the handler/servlet
317      * is ready for the request body and thus a 100 Continue response is sent.
318      *
319      * @return The input stream for this connection.
320      * The stream will be created if it does not already exist.
321      * @throws IOException if the input stream cannot be retrieved
322      */
323     public ServletInputStream getInputStream() throws IOException
324     {
325         // If the client is expecting 100 CONTINUE, then send it now.
326         if (_expect100Continue)
327         {
328             // is content missing?
329             if (((HttpParser)_parser).getHeaderBuffer()==null || ((HttpParser)_parser).getHeaderBuffer().length()<2)
330             {
331                 if (_generator.isCommitted())
332                     throw new IllegalStateException("Committed before 100 Continues");
333 
334                 ((HttpGenerator)_generator).send1xx(HttpStatus.CONTINUE_100);
335             }
336             _expect100Continue=false;
337         }
338 
339         if (_in == null)
340             _in = new HttpInput(AbstractHttpConnection.this);
341         return _in;
342     }
343 
344     /* ------------------------------------------------------------ */
345     /**
346      * @return The output stream for this connection. The stream will be created if it does not already exist.
347      */
348     public ServletOutputStream getOutputStream()
349     {
350         if (_out == null)
351             _out = new Output();
352         return _out;
353     }
354 
355     /* ------------------------------------------------------------ */
356     /**
357      * @param encoding the PrintWriter encoding
358      * @return A {@link PrintWriter} wrapping the {@link #getOutputStream output stream}. The writer is created if it
359      *    does not already exist.
360      */
361     public PrintWriter getPrintWriter(String encoding)
362     {
363         getOutputStream();
364         if (_writer==null)
365         {
366             _writer=new OutputWriter();
367             if (_server.isUncheckedPrintWriter())
368                 _printWriter=new UncheckedPrintWriter(_writer);
369             else
370                 _printWriter = new PrintWriter(_writer)
371                 {
372                     public void close()
373                     {
374                         synchronized (lock)
375                         {
376                             try
377                             {
378                                 out.close();
379                             }
380                             catch (IOException e)
381                             {
382                                 setError();
383                             }
384                         }
385                     }
386                 };
387         }
388         _writer.setCharacterEncoding(encoding);
389         return _printWriter;
390     }
391 
392     /* ------------------------------------------------------------ */
393     public boolean isResponseCommitted()
394     {
395         return _generator.isCommitted();
396     }
397 
398     /* ------------------------------------------------------------ */
399     public boolean isEarlyEOF()
400     {
401         return _earlyEOF;
402     }
403 
404     /* ------------------------------------------------------------ */
405     public void reset()
406     {
407         _parser.reset();
408         _parser.returnBuffers(); // TODO maybe only on unhandle
409         _requestFields.clear();
410         _request.recycle();
411         _generator.reset();
412         _generator.returnBuffers();// TODO maybe only on unhandle
413         _responseFields.clear();
414         _response.recycle();
415         _uri.clear();
416         _writer=null;
417         _earlyEOF = false;
418     }
419 
420     /* ------------------------------------------------------------ */
421     protected void handleRequest() throws IOException
422     {
423         boolean error = false;
424 
425         String threadName=null;
426         try
427         {
428             if (LOG.isDebugEnabled())
429             {
430                 threadName=Thread.currentThread().getName();
431                 Thread.currentThread().setName(threadName+" - "+_uri);
432             }
433 
434 
435             // Loop here to handle async request redispatches.
436             // The loop is controlled by the call to async.unhandle in the
437             // finally block below.  If call is from a non-blocking connector,
438             // then the unhandle will return false only if an async dispatch has
439             // already happened when unhandle is called.   For a blocking connector,
440             // the wait for the asynchronous dispatch or timeout actually happens
441             // within the call to unhandle().
442 
443             final Server server=_server;
444             boolean handling=_request._async.handling() && server!=null && server.isRunning();
445             while (handling)
446             {
447                 _request.setHandled(false);
448 
449                 String info=null;
450                 try
451                 {
452                     _uri.getPort();
453                     String path = null;
454 
455                     try
456                     {
457                         path = _uri.getDecodedPath();
458                     }
459                     catch (Exception e)
460                     {
461                         LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1");
462                         LOG.ignore(e);
463                         path = _uri.getDecodedPath(StringUtil.__ISO_8859_1);
464                     }
465 
466                     info=URIUtil.canonicalPath(path);
467                     if (info==null && !_request.getMethod().equals(HttpMethods.CONNECT))
468                     {
469                         if (_uri.getScheme()!=null && _uri.getHost()!=null)
470                         {
471                             info="/";
472                             _request.setRequestURI("");
473                         }
474                         else
475                             throw new HttpException(400);
476                     }
477                     _request.setPathInfo(info);
478 
479                     if (_out!=null)
480                         _out.reopen();
481 
482                     if (_request._async.isInitial())
483                     {
484                         _request.setDispatcherType(DispatcherType.REQUEST);
485                         _connector.customize(_endp, _request);
486                         server.handle(this);
487                     }
488                     else
489                     {
490                         _request.setDispatcherType(DispatcherType.ASYNC);
491                         server.handleAsync(this);
492                     }
493                 }
494                 catch (ContinuationThrowable e)
495                 {
496                     LOG.ignore(e);
497                 }
498                 catch (EofException e)
499                 {
500                     LOG.debug(e);
501                     error=true;
502                     _request.setHandled(true);
503                     if (!_response.isCommitted())
504                         _generator.sendError(500, null, null, true);
505                 }
506                 catch (RuntimeIOException e)
507                 {
508                     LOG.debug(e);
509                     error=true;
510                     _request.setHandled(true);
511                 }
512                 catch (HttpException e)
513                 {
514                     LOG.debug(e);
515                     error=true;
516                     _request.setHandled(true);
517                     _response.sendError(e.getStatus(), e.getReason());
518                 }
519                 catch (Throwable e)
520                 {
521                     LOG.warn(String.valueOf(_uri),e);
522                     error=true;
523                     _request.setHandled(true);
524                     _generator.sendError(info==null?400:500, null, null, true);
525                 }
526                 finally
527                 {
528                     handling = !_request._async.unhandle() && server.isRunning() && _server!=null;
529                 }
530             }
531         }
532         finally
533         {
534             if (threadName!=null)
535                 Thread.currentThread().setName(threadName);
536 
537             if (_request._async.isUncompleted())
538             {
539                 _request._async.doComplete();
540 
541                 if (_expect100Continue)
542                 {
543                     LOG.debug("100 continues not sent");
544                     // We didn't send 100 continues, but the latest interpretation
545                     // of the spec (see httpbis) is that the client will either
546                     // send the body anyway, or close.  So we no longer need to
547                     // do anything special here other than make the connection not persistent
548                     _expect100Continue = false;
549                     if (!_response.isCommitted())
550                         _generator.setPersistent(false);
551                 }
552 
553                 if(_endp.isOpen())
554                 {
555                     if (error)
556                     {
557                         _endp.shutdownOutput();
558                         _generator.setPersistent(false);
559                         if (!_generator.isComplete())
560                             _response.complete();
561                     }
562                     else
563                     {
564                         if (!_response.isCommitted() && !_request.isHandled())
565                             _response.sendError(HttpServletResponse.SC_NOT_FOUND);
566                         _response.complete();
567                         if (_generator.isPersistent())
568                             _connector.persist(_endp);
569                     }
570                 }
571                 else
572                 {
573                     _response.complete();
574                 }
575 
576                 _request.setHandled(true);
577             }
578         }
579     }
580 
581     /* ------------------------------------------------------------ */
582     public abstract Connection handle() throws IOException;
583 
584     /* ------------------------------------------------------------ */
585     public void commitResponse(boolean last) throws IOException
586     {
587         if (!_generator.isCommitted())
588         {
589             _generator.setResponse(_response.getStatus(), _response.getReason());
590             try
591             {
592                 // If the client was expecting 100 continues, but we sent something
593                 // else, then we need to close the connection
594                 if (_expect100Continue && _response.getStatus()!=100)
595                     _generator.setPersistent(false);
596                 _generator.completeHeader(_responseFields, last);
597             }
598             catch(RuntimeException e)
599             {
600                 LOG.warn("header full: " + e);
601 
602                 _response.reset();
603                 _generator.reset();
604                 _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500,null);
605                 _generator.completeHeader(_responseFields,Generator.LAST);
606                 _generator.complete();
607                 throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500);
608             }
609 
610         }
611         if (last)
612             _generator.complete();
613     }
614 
615     /* ------------------------------------------------------------ */
616     public void completeResponse() throws IOException
617     {
618         if (!_generator.isCommitted())
619         {
620             _generator.setResponse(_response.getStatus(), _response.getReason());
621             try
622             {
623                 _generator.completeHeader(_responseFields, Generator.LAST);
624             }
625             catch(RuntimeException e)
626             {
627                 LOG.warn("header full: "+e);
628                 LOG.debug(e);
629 
630                 _response.reset();
631                 _generator.reset();
632                 _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500,null);
633                 _generator.completeHeader(_responseFields,Generator.LAST);
634                 _generator.complete();
635                 throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500);
636             }
637         }
638 
639         _generator.complete();
640     }
641 
642     /* ------------------------------------------------------------ */
643     public void flushResponse() throws IOException
644     {
645         try
646         {
647             commitResponse(Generator.MORE);
648             _generator.flushBuffer();
649         }
650         catch(IOException e)
651         {
652             throw (e instanceof EofException) ? e:new EofException(e);
653         }
654     }
655 
656     /* ------------------------------------------------------------ */
657     public Generator getGenerator()
658     {
659         return _generator;
660     }
661 
662     /* ------------------------------------------------------------ */
663     public boolean isIncluding()
664     {
665         return _include>0;
666     }
667 
668     /* ------------------------------------------------------------ */
669     public void include()
670     {
671         _include++;
672     }
673 
674     /* ------------------------------------------------------------ */
675     public void included()
676     {
677         _include--;
678         if (_out!=null)
679             _out.reopen();
680     }
681 
682     /* ------------------------------------------------------------ */
683     public boolean isIdle()
684     {
685         return _generator.isIdle() && (_parser.isIdle() || _delayedHandling);
686     }
687 
688     /* ------------------------------------------------------------ */
689     /**
690      * @see org.eclipse.jetty.io.Connection#isSuspended()
691      */
692     public boolean isSuspended()
693     {
694         return _request.getAsyncContinuation().isSuspended();
695     }
696 
697     /* ------------------------------------------------------------ */
698     public void onClose()
699     {
700         LOG.debug("closed {}",this);
701     }
702 
703     /* ------------------------------------------------------------ */
704     public boolean isExpecting100Continues()
705     {
706         return _expect100Continue;
707     }
708 
709     /* ------------------------------------------------------------ */
710     public boolean isExpecting102Processing()
711     {
712         return _expect102Processing;
713     }
714 
715     /* ------------------------------------------------------------ */
716     public int getMaxIdleTime()
717     {
718         if (_connector.isLowResources() && _endp.getMaxIdleTime()==_connector.getMaxIdleTime())
719             return _connector.getLowResourceMaxIdleTime();
720         if (_endp.getMaxIdleTime()>0)
721             return _endp.getMaxIdleTime();
722         return _connector.getMaxIdleTime();
723     }
724 
725     /* ------------------------------------------------------------ */
726     public String toString()
727     {
728         return String.format("%s,g=%s,p=%s,r=%d",
729                 super.toString(),
730                 _generator,
731                 _parser,
732                 _requests);
733     }
734 
735     /* ------------------------------------------------------------ */
736     protected void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
737     {
738         uri=uri.asImmutableBuffer();
739 
740         _host = false;
741         _expect = false;
742         _expect100Continue=false;
743         _expect102Processing=false;
744         _delayedHandling=false;
745         _charset=null;
746 
747         if(_request.getTimeStamp()==0)
748             _request.setTimeStamp(System.currentTimeMillis());
749         _request.setMethod(method.toString());
750 
751         try
752         {
753             _head=false;
754             switch (HttpMethods.CACHE.getOrdinal(method))
755             {
756               case HttpMethods.CONNECT_ORDINAL:
757                   _uri.parseConnect(uri.array(), uri.getIndex(), uri.length());
758                   break;
759 
760               case HttpMethods.HEAD_ORDINAL:
761                   _head=true;
762                   _uri.parse(uri.array(), uri.getIndex(), uri.length());
763                   break;
764 
765               default:
766                   _uri.parse(uri.array(), uri.getIndex(), uri.length());
767             }
768 
769             _request.setUri(_uri);
770 
771             if (version==null)
772             {
773                 _request.setProtocol(HttpVersions.HTTP_0_9);
774                 _version=HttpVersions.HTTP_0_9_ORDINAL;
775             }
776             else
777             {
778                 version= HttpVersions.CACHE.get(version);
779                 if (version==null)
780                     throw new HttpException(HttpStatus.BAD_REQUEST_400,null);
781                 _version = HttpVersions.CACHE.getOrdinal(version);
782                 if (_version <= 0) _version = HttpVersions.HTTP_1_0_ORDINAL;
783                 _request.setProtocol(version.toString());
784             }
785         }
786         catch (Exception e)
787         {
788             LOG.debug(e);
789             if (e instanceof HttpException)
790                 throw (HttpException)e;
791             throw new HttpException(HttpStatus.BAD_REQUEST_400,null,e);
792         }
793     }
794 
795     /* ------------------------------------------------------------ */
796     protected void parsedHeader(Buffer name, Buffer value) throws IOException
797     {
798         int ho = HttpHeaders.CACHE.getOrdinal(name);
799         switch (ho)
800         {
801             case HttpHeaders.HOST_ORDINAL:
802                 // TODO check if host matched a host in the URI.
803                 _host = true;
804                 break;
805 
806             case HttpHeaders.EXPECT_ORDINAL:
807                 if (_version>=HttpVersions.HTTP_1_1_ORDINAL)
808                 {
809                     value = HttpHeaderValues.CACHE.lookup(value);
810                     switch(HttpHeaderValues.CACHE.getOrdinal(value))
811                     {
812                         case HttpHeaderValues.CONTINUE_ORDINAL:
813                             _expect100Continue=_generator instanceof HttpGenerator;
814                             break;
815 
816                         case HttpHeaderValues.PROCESSING_ORDINAL:
817                             _expect102Processing=_generator instanceof HttpGenerator;
818                             break;
819 
820                         default:
821                             String[] values = value.toString().split(",");
822                             for  (int i=0;values!=null && i<values.length;i++)
823                             {
824                                 CachedBuffer cb=HttpHeaderValues.CACHE.get(values[i].trim());
825                                 if (cb==null)
826                                     _expect=true;
827                                 else
828                                 {
829                                     switch(cb.getOrdinal())
830                                     {
831                                         case HttpHeaderValues.CONTINUE_ORDINAL:
832                                             _expect100Continue=_generator instanceof HttpGenerator;
833                                             break;
834                                         case HttpHeaderValues.PROCESSING_ORDINAL:
835                                             _expect102Processing=_generator instanceof HttpGenerator;
836                                             break;
837                                         default:
838                                             _expect=true;
839                                     }
840                                 }
841                             }
842                     }
843                 }
844                 break;
845 
846             case HttpHeaders.ACCEPT_ENCODING_ORDINAL:
847             case HttpHeaders.USER_AGENT_ORDINAL:
848                 value = HttpHeaderValues.CACHE.lookup(value);
849                 break;
850 
851             case HttpHeaders.CONTENT_TYPE_ORDINAL:
852                 value = MimeTypes.CACHE.lookup(value);
853                 _charset=MimeTypes.getCharsetFromContentType(value);
854                 break;
855         }
856 
857         _requestFields.add(name, value);
858     }
859 
860     /* ------------------------------------------------------------ */
861     protected void headerComplete() throws IOException
862     {
863         // Handle idle race
864         if (_endp.isOutputShutdown())
865         {
866             _endp.close();
867             return;
868         }
869         
870         _requests++;
871         _generator.setVersion(_version);
872         switch (_version)
873         {
874             case HttpVersions.HTTP_0_9_ORDINAL:
875                 break;
876             case HttpVersions.HTTP_1_0_ORDINAL:
877                 _generator.setHead(_head);
878                 if (_parser.isPersistent())
879                 {
880                     _responseFields.add(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.KEEP_ALIVE_BUFFER);
881                     _generator.setPersistent(true);
882                 }
883                 else if (HttpMethods.CONNECT.equals(_request.getMethod()))
884                 {
885                     _generator.setPersistent(true);
886                     _parser.setPersistent(true);
887                 }
888 
889                 if (_server.getSendDateHeader())
890                     _generator.setDate(_request.getTimeStampBuffer());
891                 break;
892 
893             case HttpVersions.HTTP_1_1_ORDINAL:
894                 _generator.setHead(_head);
895 
896                 if (!_parser.isPersistent())
897                 {
898                     _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
899                     _generator.setPersistent(false);
900                 }
901                 if (_server.getSendDateHeader())
902                     _generator.setDate(_request.getTimeStampBuffer());
903 
904                 if (!_host)
905                 {
906                     LOG.debug("!host {}",this);
907                     _generator.setResponse(HttpStatus.BAD_REQUEST_400, null);
908                     _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
909                     _generator.completeHeader(_responseFields, true);
910                     _generator.complete();
911                     return;
912                 }
913 
914                 if (_expect)
915                 {
916                     LOG.debug("!expectation {}",this);
917                     _generator.setResponse(HttpStatus.EXPECTATION_FAILED_417, null);
918                     _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
919                     _generator.completeHeader(_responseFields, true);
920                     _generator.complete();
921                     return;
922                 }
923 
924                 break;
925             default:
926         }
927 
928         if(_charset!=null)
929             _request.setCharacterEncodingUnchecked(_charset);
930 
931         // Either handle now or wait for first content
932         if ((((HttpParser)_parser).getContentLength()<=0 && !((HttpParser)_parser).isChunking())||_expect100Continue)
933             handleRequest();
934         else
935             _delayedHandling=true;
936     }
937 
938     /* ------------------------------------------------------------ */
939     protected void content(Buffer buffer) throws IOException
940     {
941         if (_delayedHandling)
942         {
943             _delayedHandling=false;
944             handleRequest();
945         }
946     }
947 
948     /* ------------------------------------------------------------ */
949     public void messageComplete(long contentLength) throws IOException
950     {
951         if (_delayedHandling)
952         {
953             _delayedHandling=false;
954             handleRequest();
955         }
956     }
957 
958     /* ------------------------------------------------------------ */
959     public void earlyEOF()
960     {
961         _earlyEOF = true;
962     }
963 
964     /* ------------------------------------------------------------ */
965     /* ------------------------------------------------------------ */
966     /* ------------------------------------------------------------ */
967     private class RequestHandler extends HttpParser.EventHandler
968     {
969         /*
970          *
971          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#startRequest(org.eclipse.io.Buffer,
972          *      org.eclipse.io.Buffer, org.eclipse.io.Buffer)
973          */
974         @Override
975         public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
976         {
977             AbstractHttpConnection.this.startRequest(method, uri, version);
978         }
979 
980         /*
981          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#parsedHeaderValue(org.eclipse.io.Buffer)
982          */
983         @Override
984         public void parsedHeader(Buffer name, Buffer value) throws IOException
985         {
986             AbstractHttpConnection.this.parsedHeader(name, value);
987         }
988 
989         /*
990          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#headerComplete()
991          */
992         @Override
993         public void headerComplete() throws IOException
994         {
995             AbstractHttpConnection.this.headerComplete();
996         }
997 
998         /* ------------------------------------------------------------ */
999         /*
1000          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#content(int, org.eclipse.io.Buffer)
1001          */
1002         @Override
1003         public void content(Buffer ref) throws IOException
1004         {
1005             AbstractHttpConnection.this.content(ref);
1006         }
1007 
1008         /* ------------------------------------------------------------ */
1009         /*
1010          * (non-Javadoc)
1011          *
1012          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#messageComplete(int)
1013          */
1014         @Override
1015         public void messageComplete(long contentLength) throws IOException
1016         {
1017             AbstractHttpConnection.this.messageComplete(contentLength);
1018         }
1019 
1020         /* ------------------------------------------------------------ */
1021         /*
1022          * (non-Javadoc)
1023          *
1024          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#startResponse(org.eclipse.io.Buffer, int,
1025          *      org.eclipse.io.Buffer)
1026          */
1027         @Override
1028         public void startResponse(Buffer version, int status, Buffer reason)
1029         {
1030             if (LOG.isDebugEnabled())
1031                 LOG.debug("Bad request!: "+version+" "+status+" "+reason);
1032         }
1033 
1034         /* ------------------------------------------------------------ */
1035         /*
1036          * (non-Javadoc)
1037          *
1038          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#earlyEOF()
1039          */
1040         @Override
1041         public void earlyEOF()
1042         {
1043             AbstractHttpConnection.this.earlyEOF();
1044         }
1045     }
1046 
1047     /* ------------------------------------------------------------ */
1048     /* ------------------------------------------------------------ */
1049     /* ------------------------------------------------------------ */
1050     public class Output extends HttpOutput
1051     {
1052         Output()
1053         {
1054             super(AbstractHttpConnection.this);
1055         }
1056 
1057         /* ------------------------------------------------------------ */
1058         /*
1059          * @see java.io.OutputStream#close()
1060          */
1061         @Override
1062         public void close() throws IOException
1063         {
1064             if (isClosed())
1065                 return;
1066 
1067             if (!isIncluding() && !super._generator.isCommitted())
1068                 commitResponse(Generator.LAST);
1069             else
1070                 flushResponse();
1071 
1072             super.close();
1073         }
1074 
1075 
1076         /* ------------------------------------------------------------ */
1077         /*
1078          * @see java.io.OutputStream#flush()
1079          */
1080         @Override
1081         public void flush() throws IOException
1082         {
1083             if (!super._generator.isCommitted())
1084                 commitResponse(Generator.MORE);
1085             super.flush();
1086         }
1087 
1088         /* ------------------------------------------------------------ */
1089         /*
1090          * @see javax.servlet.ServletOutputStream#print(java.lang.String)
1091          */
1092         @Override
1093         public void print(String s) throws IOException
1094         {
1095             if (isClosed())
1096                 throw new IOException("Closed");
1097             PrintWriter writer=getPrintWriter(null);
1098             writer.print(s);
1099         }
1100 
1101         /* ------------------------------------------------------------ */
1102         public void sendResponse(Buffer response) throws IOException
1103         {
1104             ((HttpGenerator)super._generator).sendResponse(response);
1105         }
1106 
1107         /* ------------------------------------------------------------ */
1108         public void sendContent(Object content) throws IOException
1109         {
1110             Resource resource=null;
1111 
1112             if (isClosed())
1113                 throw new IOException("Closed");
1114 
1115             if (super._generator.isWritten())
1116                 throw new IllegalStateException("!empty");
1117 
1118             // Convert HTTP content to content
1119             if (content instanceof HttpContent)
1120             {
1121                 HttpContent httpContent = (HttpContent) content;
1122                 Buffer contentType = httpContent.getContentType();
1123                 if (contentType != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER))
1124                 {
1125                     String enc = _response.getSetCharacterEncoding();
1126                     if(enc==null)
1127                         _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, contentType);
1128                     else
1129                     {
1130                         if(contentType instanceof CachedBuffer)
1131                         {
1132                             CachedBuffer content_type = ((CachedBuffer)contentType).getAssociate(enc);
1133                             if(content_type!=null)
1134                                 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, content_type);
1135                             else
1136                             {
1137                                 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1138                                         contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1139                             }
1140                         }
1141                         else
1142                         {
1143                             _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1144                                     contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1145                         }
1146                     }
1147                 }
1148                 if (httpContent.getContentLength() > 0)
1149                     _responseFields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER, httpContent.getContentLength());
1150                 Buffer lm = httpContent.getLastModified();
1151                 long lml=httpContent.getResource().lastModified();
1152                 if (lm != null)
1153                 {
1154                     _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm);
1155                 }
1156                 else if (httpContent.getResource()!=null)
1157                 {
1158                     if (lml!=-1)
1159                         _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml);
1160                 }
1161                 
1162                 Buffer etag=httpContent.getETag();
1163                 if (etag!=null)
1164                     _responseFields.put(HttpHeaders.ETAG_BUFFER,etag);
1165 
1166                 
1167                 boolean direct=_connector instanceof NIOConnector && ((NIOConnector)_connector).getUseDirectBuffers() && !(_connector instanceof SslConnector);
1168                 content = direct?httpContent.getDirectBuffer():httpContent.getIndirectBuffer();
1169                 if (content==null)
1170                     content=httpContent.getInputStream();
1171             }
1172             else if (content instanceof Resource)
1173             {
1174                 resource=(Resource)content;
1175                 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, resource.lastModified());
1176                 content=resource.getInputStream();
1177             }
1178 
1179             // Process content.
1180             if (content instanceof Buffer)
1181             {
1182                 super._generator.addContent((Buffer) content, Generator.LAST);
1183                 commitResponse(Generator.LAST);
1184             }
1185             else if (content instanceof InputStream)
1186             {
1187                 InputStream in = (InputStream)content;
1188 
1189                 try
1190                 {
1191                     int max = super._generator.prepareUncheckedAddContent();
1192                     Buffer buffer = super._generator.getUncheckedBuffer();
1193 
1194                     int len=buffer.readFrom(in,max);
1195 
1196                     while (len>=0)
1197                     {
1198                         super._generator.completeUncheckedAddContent();
1199                         _out.flush();
1200 
1201                         max = super._generator.prepareUncheckedAddContent();
1202                         buffer = super._generator.getUncheckedBuffer();
1203                         len=buffer.readFrom(in,max);
1204                     }
1205                     super._generator.completeUncheckedAddContent();
1206                     _out.flush();
1207                 }
1208                 finally
1209                 {
1210                     if (resource!=null)
1211                         resource.release();
1212                     else
1213                         in.close();
1214                 }
1215             }
1216             else
1217                 throw new IllegalArgumentException("unknown content type?");
1218 
1219 
1220         }
1221     }
1222 
1223     /* ------------------------------------------------------------ */
1224     /* ------------------------------------------------------------ */
1225     /* ------------------------------------------------------------ */
1226     public class OutputWriter extends HttpWriter
1227     {
1228         OutputWriter()
1229         {
1230             super(AbstractHttpConnection.this._out);
1231         }
1232     }
1233 
1234 
1235 }