View Javadoc

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