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