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