View Javadoc

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