View Javadoc

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