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 ServletInputStream _in;
107 
108     protected final Generator _generator;
109     protected final HttpFields _responseFields;
110     protected final Response _response;
111     protected Output _out;
112     protected OutputWriter _writer;
113     protected 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             _printWriter=new UncheckedPrintWriter(_writer);
360         }
361         _writer.setCharacterEncoding(encoding);
362         return _printWriter;
363     }
364 
365     /* ------------------------------------------------------------ */
366     public boolean isResponseCommitted()
367     {
368         return _generator.isCommitted();
369     }
370 
371     /* ------------------------------------------------------------ */
372     public void reset()
373     {
374         _parser.reset();
375         _parser.returnBuffers(); // TODO maybe only on unhandle
376         _requestFields.clear();
377         _request.recycle();
378         _generator.reset();
379         _generator.returnBuffers();// TODO maybe only on unhandle
380         _responseFields.clear();
381         _response.recycle();
382         _uri.clear();
383     }
384 
385     /* ------------------------------------------------------------ */
386     protected void handleRequest() throws IOException
387     {
388         boolean error = false;
389 
390         String threadName=null;
391         Throwable async_exception=null;
392         try
393         {
394             if (LOG.isDebugEnabled())
395             {
396                 threadName=Thread.currentThread().getName();
397                 Thread.currentThread().setName(threadName+" - "+_uri);
398             }
399 
400 
401             // Loop here to handle async request redispatches.
402             // The loop is controlled by the call to async.unhandle in the
403             // finally block below.  If call is from a non-blocking connector,
404             // then the unhandle will return false only if an async dispatch has
405             // already happened when unhandle is called.   For a blocking connector,
406             // the wait for the asynchronous dispatch or timeout actually happens
407             // within the call to unhandle().
408 
409             final Server server=_server;
410             boolean handling=_request._async.handling() && server!=null && server.isRunning();
411             while (handling)
412             {
413                 _request.setHandled(false);
414 
415                 String info=null;
416                 try
417                 {
418                     _uri.getPort();
419                     info=URIUtil.canonicalPath(_uri.getDecodedPath());
420                     if (info==null && !_request.getMethod().equals(HttpMethods.CONNECT))
421                         throw new HttpException(400);
422                     _request.setPathInfo(info);
423 
424                     if (_out!=null)
425                         _out.reopen();
426 
427                     if (_request._async.isInitial())
428                     {
429                         _request.setDispatcherType(DispatcherType.REQUEST);
430                         _connector.customize(_endp, _request);
431                         server.handle(this);
432                     }
433                     else
434                     {
435                         _request.setDispatcherType(DispatcherType.ASYNC);
436                         server.handleAsync(this);
437                     }
438                 }
439                 catch (ContinuationThrowable e)
440                 {
441                     LOG.ignore(e);
442                 }
443                 catch (EofException e)
444                 {
445                     async_exception=e;
446                     LOG.debug(e);
447                     error=true;
448                     _request.setHandled(true);
449                 }
450                 catch (RuntimeIOException e)
451                 {
452                     async_exception=e;
453                     LOG.debug(e);
454                     error=true;
455                     _request.setHandled(true);
456                 }
457                 catch (HttpException e)
458                 {
459                     LOG.debug(e);
460                     error=true;
461                     _request.setHandled(true);
462                     _response.sendError(e.getStatus(), e.getReason());
463                 }
464                 catch (Throwable e)
465                 {
466                     async_exception=e;
467                     LOG.warn(String.valueOf(_uri),e);
468                     error=true;
469                     _request.setHandled(true);
470                     _generator.sendError(info==null?400:500, null, null, true);
471                 }
472                 finally
473                 {
474                     handling = !_request._async.unhandle() && server.isRunning() && _server!=null;
475                 }
476             }
477         }
478         finally
479         {
480             if (threadName!=null)
481                 Thread.currentThread().setName(threadName);
482 
483             if (_request._async.isUncompleted())
484             {
485                 
486                 _request._async.doComplete(async_exception);
487 
488                 if (_expect100Continue)
489                 {
490                     LOG.debug("100 continues not sent");
491                     // We didn't send 100 continues, but the latest interpretation
492                     // of the spec (see httpbis) is that the client will either
493                     // send the body anyway, or close.  So we no longer need to
494                     // do anything special here other than make the connection not persistent
495                     _expect100Continue = false;
496                     if (!_response.isCommitted())
497                         _generator.setPersistent(false);
498                 }
499 
500                 if(_endp.isOpen())
501                 {
502                     if (error)
503                     {
504                         _endp.shutdownOutput();
505                         _generator.setPersistent(false);
506                         if (!_generator.isComplete())
507                             _response.complete();
508                     }
509                     else
510                     {
511                         if (!_response.isCommitted() && !_request.isHandled())
512                             _response.sendError(HttpServletResponse.SC_NOT_FOUND);
513                         _response.complete();
514                         if (_generator.isPersistent())
515                             _connector.persist(_endp);
516                     }
517                 }
518                 else
519                 {
520                     _response.complete();
521                 }
522 
523                 _request.setHandled(true);
524             }
525         }
526     }
527 
528     /* ------------------------------------------------------------ */
529     public abstract Connection handle() throws IOException;
530 
531     /* ------------------------------------------------------------ */
532     public void commitResponse(boolean last) throws IOException
533     {
534         if (!_generator.isCommitted())
535         {
536             _generator.setResponse(_response.getStatus(), _response.getReason());
537             try
538             {
539                 // If the client was expecting 100 continues, but we sent something
540                 // else, then we need to close the connection
541                 if (_expect100Continue && _response.getStatus()!=100)
542                     _generator.setPersistent(false);
543                 _generator.completeHeader(_responseFields, last);
544             }
545             catch(IOException io)
546             {
547                 throw io;
548             }
549             catch(RuntimeException e)
550             {
551                 LOG.warn("header full: " + e);
552 
553                 _response.reset();
554                 _generator.reset();
555                 _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500,null);
556                 _generator.completeHeader(_responseFields,Generator.LAST);
557                 _generator.complete();
558                 throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500);
559             }
560 
561         }
562         if (last)
563             _generator.complete();
564     }
565 
566     /* ------------------------------------------------------------ */
567     public void completeResponse() throws IOException
568     {
569         if (!_generator.isCommitted())
570         {
571             _generator.setResponse(_response.getStatus(), _response.getReason());
572             try
573             {
574                 _generator.completeHeader(_responseFields, Generator.LAST);
575             }
576             catch(IOException io)
577             {
578                 throw io;
579             }
580             catch(RuntimeException e)
581             {
582                 LOG.warn("header full: "+e);
583                 LOG.debug(e);
584 
585                 _response.reset();
586                 _generator.reset();
587                 _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500,null);
588                 _generator.completeHeader(_responseFields,Generator.LAST);
589                 _generator.complete();
590                 throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500);
591             }
592         }
593 
594         _generator.complete();
595     }
596 
597     /* ------------------------------------------------------------ */
598     public void flushResponse() throws IOException
599     {
600         try
601         {
602             commitResponse(Generator.MORE);
603             _generator.flushBuffer();
604         }
605         catch(IOException e)
606         {
607             throw (e instanceof EofException) ? e:new EofException(e);
608         }
609     }
610 
611     /* ------------------------------------------------------------ */
612     public Generator getGenerator()
613     {
614         return _generator;
615     }
616 
617     /* ------------------------------------------------------------ */
618     public boolean isIncluding()
619     {
620         return _include>0;
621     }
622 
623     /* ------------------------------------------------------------ */
624     public void include()
625     {
626         _include++;
627     }
628 
629     /* ------------------------------------------------------------ */
630     public void included()
631     {
632         _include--;
633         if (_out!=null)
634             _out.reopen();
635     }
636 
637     /* ------------------------------------------------------------ */
638     public boolean isIdle()
639     {
640         return _generator.isIdle() && (_parser.isIdle() || _delayedHandling);
641     }
642 
643     /* ------------------------------------------------------------ */
644     /**
645      * @see org.eclipse.jetty.io.Connection#isSuspended()
646      */
647     public boolean isSuspended()
648     {
649         return _request.getAsyncContinuation().isSuspended();
650     }
651 
652     /* ------------------------------------------------------------ */
653     public void onClose()
654     {
655         LOG.debug("closed {}",this);
656     }
657 
658     /* ------------------------------------------------------------ */
659     public boolean isExpecting100Continues()
660     {
661         return _expect100Continue;
662     }
663 
664     /* ------------------------------------------------------------ */
665     public boolean isExpecting102Processing()
666     {
667         return _expect102Processing;
668     }
669 
670     /* ------------------------------------------------------------ */
671     public int getMaxIdleTime()
672     {
673         if (_connector.isLowResources() && _endp.getMaxIdleTime()==_connector.getMaxIdleTime())
674             return _connector.getLowResourceMaxIdleTime();
675         if (_endp.getMaxIdleTime()>0)
676             return _endp.getMaxIdleTime();
677         return _connector.getMaxIdleTime();
678     }
679 
680     /* ------------------------------------------------------------ */
681     public String toString()
682     {
683         return String.format("%s,g=%s,p=%s,r=%d",
684                 super.toString(),
685                 _generator,
686                 _parser,
687                 _requests);
688     }
689 
690     /* ------------------------------------------------------------ */
691     /* ------------------------------------------------------------ */
692     /* ------------------------------------------------------------ */
693     private class RequestHandler extends HttpParser.EventHandler
694     {
695         private String _charset;
696 
697         /*
698          *
699          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#startRequest(org.eclipse.io.Buffer,
700          *      org.eclipse.io.Buffer, org.eclipse.io.Buffer)
701          */
702         @Override
703         public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
704         {
705             uri=uri.asImmutableBuffer();
706 
707             _host = false;
708             _expect = false;
709             _expect100Continue=false;
710             _expect102Processing=false;
711             _delayedHandling=false;
712             _charset=null;
713 
714             if(_request.getTimeStamp()==0)
715                 _request.setTimeStamp(System.currentTimeMillis());
716             _request.setMethod(method.toString());
717 
718             try
719             {
720                 _head=false;
721                 switch (HttpMethods.CACHE.getOrdinal(method))
722                 {
723                   case HttpMethods.CONNECT_ORDINAL:
724                       _uri.parseConnect(uri.array(), uri.getIndex(), uri.length());
725                       break;
726 
727                   case HttpMethods.HEAD_ORDINAL:
728                       _head=true;
729                       _uri.parse(uri.array(), uri.getIndex(), uri.length());
730                       break;
731 
732                   default:
733                       _uri.parse(uri.array(), uri.getIndex(), uri.length());
734                 }
735 
736                 _request.setUri(_uri);
737 
738                 if (version==null)
739                 {
740                     _request.setProtocol(HttpVersions.HTTP_0_9);
741                     _version=HttpVersions.HTTP_0_9_ORDINAL;
742                 }
743                 else
744                 {
745                     version= HttpVersions.CACHE.get(version);
746                     if (version==null)
747                         throw new HttpException(HttpStatus.BAD_REQUEST_400,null);
748                     _version = HttpVersions.CACHE.getOrdinal(version);
749                     if (_version <= 0) _version = HttpVersions.HTTP_1_0_ORDINAL;
750                     _request.setProtocol(version.toString());
751                 }
752             }
753             catch (Exception e)
754             {
755                 LOG.debug(e);
756                 if (e instanceof HttpException)
757                     throw (HttpException)e;
758                 throw new HttpException(HttpStatus.BAD_REQUEST_400,null,e);
759             }
760         }
761 
762         /*
763          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#parsedHeaderValue(org.eclipse.io.Buffer)
764          */
765         @Override
766         public void parsedHeader(Buffer name, Buffer value)
767         {
768             int ho = HttpHeaders.CACHE.getOrdinal(name);
769             switch (ho)
770             {
771                 case HttpHeaders.HOST_ORDINAL:
772                     // TODO check if host matched a host in the URI.
773                     _host = true;
774                     break;
775 
776                 case HttpHeaders.EXPECT_ORDINAL:
777                     value = HttpHeaderValues.CACHE.lookup(value);
778                     switch(HttpHeaderValues.CACHE.getOrdinal(value))
779                     {
780                         case HttpHeaderValues.CONTINUE_ORDINAL:
781                             _expect100Continue=_generator instanceof HttpGenerator;
782                             break;
783 
784                         case HttpHeaderValues.PROCESSING_ORDINAL:
785                             _expect102Processing=_generator instanceof HttpGenerator;
786                             break;
787 
788                         default:
789                             String[] values = value.toString().split(",");
790                             for  (int i=0;values!=null && i<values.length;i++)
791                             {
792                                 CachedBuffer cb=HttpHeaderValues.CACHE.get(values[i].trim());
793                                 if (cb==null)
794                                     _expect=true;
795                                 else
796                                 {
797                                     switch(cb.getOrdinal())
798                                     {
799                                         case HttpHeaderValues.CONTINUE_ORDINAL:
800                                             _expect100Continue=_generator instanceof HttpGenerator;
801                                             break;
802                                         case HttpHeaderValues.PROCESSING_ORDINAL:
803                                             _expect102Processing=_generator instanceof HttpGenerator;
804                                             break;
805                                         default:
806                                             _expect=true;
807                                     }
808                                 }
809                             }
810                     }
811                     break;
812 
813                 case HttpHeaders.ACCEPT_ENCODING_ORDINAL:
814                 case HttpHeaders.USER_AGENT_ORDINAL:
815                     value = HttpHeaderValues.CACHE.lookup(value);
816                     break;
817 
818                 case HttpHeaders.CONTENT_TYPE_ORDINAL:
819                     value = MimeTypes.CACHE.lookup(value);
820                     _charset=MimeTypes.getCharsetFromContentType(value);
821                     break;
822             }
823 
824             _requestFields.add(name, value);
825         }
826 
827         /*
828          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#headerComplete()
829          */
830         @Override
831         public void headerComplete() throws IOException
832         {
833             _requests++;
834             _generator.setVersion(_version);
835             switch (_version)
836             {
837                 case HttpVersions.HTTP_0_9_ORDINAL:
838                     break;
839                 case HttpVersions.HTTP_1_0_ORDINAL:
840                     _generator.setHead(_head);
841                     if (_parser.isPersistent())
842                     {
843                         _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
844                         _generator.setPersistent(true);
845                     }
846                     else if (HttpMethods.CONNECT.equals(_request.getMethod()))
847                     {
848                         _generator.setPersistent(true);
849                         _parser.setPersistent(true);
850                     }
851 
852                     if (_server.getSendDateHeader())
853                         _generator.setDate(_request.getTimeStampBuffer());
854                     break;
855 
856                 case HttpVersions.HTTP_1_1_ORDINAL:
857                     _generator.setHead(_head);
858 
859                     if (!_parser.isPersistent())
860                     {
861                         _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
862                         _generator.setPersistent(false);
863                     }
864                     if (_server.getSendDateHeader())
865                         _generator.setDate(_request.getTimeStampBuffer());
866 
867                     if (!_host)
868                     {
869                         LOG.debug("!host {}",this);
870                         _generator.setResponse(HttpStatus.BAD_REQUEST_400, null);
871                         _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
872                         _generator.completeHeader(_responseFields, true);
873                         _generator.complete();
874                         return;
875                     }
876 
877                     if (_expect)
878                     {
879                         LOG.debug("!expectation {}",this);
880                         _generator.setResponse(HttpStatus.EXPECTATION_FAILED_417, null);
881                         _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
882                         _generator.completeHeader(_responseFields, true);
883                         _generator.complete();
884                         return;
885                     }
886 
887                     break;
888                 default:
889             }
890 
891             if(_charset!=null)
892                 _request.setCharacterEncodingUnchecked(_charset);
893 
894             // Either handle now or wait for first content
895             if ((((HttpParser)_parser).getContentLength()<=0 && !((HttpParser)_parser).isChunking())||_expect100Continue)
896                 handleRequest();
897             else
898                 _delayedHandling=true;
899         }
900 
901         /* ------------------------------------------------------------ */
902         /*
903          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#content(int, org.eclipse.io.Buffer)
904          */
905         @Override
906         public void content(Buffer ref) throws IOException
907         {
908             if (_delayedHandling)
909             {
910                 _delayedHandling=false;
911                 handleRequest();
912             }
913         }
914 
915         /* ------------------------------------------------------------ */
916         /*
917          * (non-Javadoc)
918          *
919          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#messageComplete(int)
920          */
921         @Override
922         public void messageComplete(long contentLength) throws IOException
923         {
924             if (_delayedHandling)
925             {
926                 _delayedHandling=false;
927                 handleRequest();
928             }
929         }
930 
931         /* ------------------------------------------------------------ */
932         /*
933          * (non-Javadoc)
934          *
935          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#startResponse(org.eclipse.io.Buffer, int,
936          *      org.eclipse.io.Buffer)
937          */
938         @Override
939         public void startResponse(Buffer version, int status, Buffer reason)
940         {
941             if (LOG.isDebugEnabled())
942                 LOG.debug("Bad request!: "+version+" "+status+" "+reason);
943         }
944 
945     }
946 
947 
948     /* ------------------------------------------------------------ */
949     /* ------------------------------------------------------------ */
950     /* ------------------------------------------------------------ */
951     public class Output extends HttpOutput
952     {
953         Output()
954         {
955             super(AbstractHttpConnection.this);
956         }
957 
958         /* ------------------------------------------------------------ */
959         /*
960          * @see java.io.OutputStream#close()
961          */
962         @Override
963         public void close() throws IOException
964         {
965             if (isClosed())
966                 return;
967 
968             if (!isIncluding() && !super._generator.isCommitted())
969                 commitResponse(Generator.LAST);
970             else
971                 flushResponse();
972 
973             super.close();
974         }
975 
976 
977         /* ------------------------------------------------------------ */
978         /*
979          * @see java.io.OutputStream#flush()
980          */
981         @Override
982         public void flush() throws IOException
983         {
984             if (!super._generator.isCommitted())
985                 commitResponse(Generator.MORE);
986             super.flush();
987         }
988 
989         /* ------------------------------------------------------------ */
990         /*
991          * @see javax.servlet.ServletOutputStream#print(java.lang.String)
992          */
993         @Override
994         public void print(String s) throws IOException
995         {
996             if (isClosed())
997                 throw new IOException("Closed");
998             PrintWriter writer=getPrintWriter(null);
999             writer.print(s);
1000         }
1001 
1002         /* ------------------------------------------------------------ */
1003         public void sendResponse(Buffer response) throws IOException
1004         {
1005             ((HttpGenerator)super._generator).sendResponse(response);
1006         }
1007 
1008         /* ------------------------------------------------------------ */
1009         public void sendContent(Object content) throws IOException
1010         {
1011             Resource resource=null;
1012 
1013             if (isClosed())
1014                 throw new IOException("Closed");
1015 
1016             if (super._generator.isWritten())
1017                 throw new IllegalStateException("!empty");
1018 
1019             // Convert HTTP content to contentl
1020             if (content instanceof HttpContent)
1021             {
1022                 HttpContent httpContent = (HttpContent) content;
1023                 Buffer contentType = httpContent.getContentType();
1024                 if (contentType != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER))
1025                 {
1026                     String enc = _response.getSetCharacterEncoding();
1027                     if(enc==null)
1028                         _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, contentType);
1029                     else
1030                     {
1031                         if(contentType instanceof CachedBuffer)
1032                         {
1033                             CachedBuffer content_type = ((CachedBuffer)contentType).getAssociate(enc);
1034                             if(content_type!=null)
1035                                 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, content_type);
1036                             else
1037                             {
1038                                 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1039                                         contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1040                             }
1041                         }
1042                         else
1043                         {
1044                             _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1045                                     contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1046                         }
1047                     }
1048                 }
1049                 if (httpContent.getContentLength() > 0)
1050                     _responseFields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER, httpContent.getContentLength());
1051                 Buffer lm = httpContent.getLastModified();
1052                 long lml=httpContent.getResource().lastModified();
1053                 if (lm != null)
1054                     _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm);
1055                 else if (httpContent.getResource()!=null)
1056                 {
1057                     if (lml!=-1)
1058                         _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml);
1059                 }
1060 
1061                 boolean direct=_connector instanceof NIOConnector && ((NIOConnector)_connector).getUseDirectBuffers() && !(_connector instanceof SslConnector);
1062                 content = direct?httpContent.getDirectBuffer():httpContent.getIndirectBuffer();
1063                 if (content==null)
1064                     content=httpContent.getInputStream();
1065             }
1066             else if (content instanceof Resource)
1067             {
1068                 resource=(Resource)content;
1069                 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, resource.lastModified());
1070                 content=resource.getInputStream();
1071             }
1072 
1073             // Process content.
1074             if (content instanceof Buffer)
1075             {
1076                 super._generator.addContent((Buffer) content, Generator.LAST);
1077                 commitResponse(Generator.LAST);
1078             }
1079             else if (content instanceof InputStream)
1080             {
1081                 InputStream in = (InputStream)content;
1082 
1083                 try
1084                 {
1085                     int max = super._generator.prepareUncheckedAddContent();
1086                     Buffer buffer = super._generator.getUncheckedBuffer();
1087 
1088                     int len=buffer.readFrom(in,max);
1089 
1090                     while (len>=0)
1091                     {
1092                         super._generator.completeUncheckedAddContent();
1093                         _out.flush();
1094 
1095                         max = super._generator.prepareUncheckedAddContent();
1096                         buffer = super._generator.getUncheckedBuffer();
1097                         len=buffer.readFrom(in,max);
1098                     }
1099                     super._generator.completeUncheckedAddContent();
1100                     _out.flush();
1101                 }
1102                 finally
1103                 {
1104                     if (resource!=null)
1105                         resource.release();
1106                     else
1107                         in.close();
1108 
1109                 }
1110             }
1111             else
1112                 throw new IllegalArgumentException("unknown content type?");
1113 
1114 
1115         }
1116     }
1117 
1118     /* ------------------------------------------------------------ */
1119     /* ------------------------------------------------------------ */
1120     /* ------------------------------------------------------------ */
1121     public class OutputWriter extends HttpWriter
1122     {
1123         OutputWriter()
1124         {
1125             super(AbstractHttpConnection.this._out);
1126         }
1127     }
1128 
1129 
1130 }