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