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