Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   //
   //  ========================================================================
   //  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
   //  ------------------------------------------------------------------------
   //  All rights reserved. This program and the accompanying materials
   //  are made available under the terms of the Eclipse Public License v1.0
   //  and Apache License v2.0 which accompanies this distribution.
   //
   //      The Eclipse Public License is available at
  //      http://www.eclipse.org/legal/epl-v10.html
  //
  //      The Apache License v2.0 is available at
  //      http://www.opensource.org/licenses/apache2.0.php
  //
  //  You may elect to redistribute this code under either of these licenses.
  //  ========================================================================
  //
  
  package org.eclipse.jetty.server;
  
  

A HttpConnection represents the connection of a HTTP client to the server and is created by an instance of a Connector. It's prime function is to associate Request and Response instances with a org.eclipse.jetty.io.EndPoint.

A connection is also the prime mechanism used by jetty to recycle objects without pooling. The Request, Response, org.eclipse.jetty.http.HttpParser, org.eclipse.jetty.http.HttpGenerator and org.eclipse.jetty.http.HttpFields instances are all recycled for the duraction of a connection. Where appropriate, allocated buffers are also kept associated with the connection via the parser and/or generator.

The connection state is held by 3 separate state machines: The request state, the response state and the continuation state. All three state machines must be driven to completion for every request, and all three can complete in any order.

The HttpConnection support protocol upgrade. If on completion of a request, the response code is 101 (switch protocols), then the org.eclipse.jetty.io.Connection request attribute is checked to see if there is a new Connection instance. If so, the new connection is returned from handle() and is used for future handling of the underlying connection. Note that for switching protocols that don't use 101 responses (eg CONNECT), the response should be sent and then the status code changed to 101 before returning from the handler. Implementors of new Connection types should be careful to extract any buffered data from (HttpParser)http.getParser()).getHeaderBuffer() and (HttpParser)http.getParser()).getBodyBuffer() to initialise their new connection.

  
  public abstract class AbstractHttpConnection  extends AbstractConnection
  {
      private static final Logger LOG = Log.getLogger(AbstractHttpConnection.class);
  
      private static final int UNKNOWN = -2;
 
     private int _requests;
 
     protected final Connector _connector;
     protected final Server _server;
     protected final HttpURI _uri;
 
     protected final Parser _parser;
     protected final HttpFields _requestFields;
     protected final Request _request;
     protected volatile ServletInputStream _in;
 
     protected final Generator _generator;
     protected final HttpFields _responseFields;
     protected final Response _response;
     protected volatile Output _out;
     protected volatile OutputWriter _writer;
     protected volatile PrintWriter _printWriter;
 
     int _include;
 
     private Object _associatedObject// associated object
 
     private int _version = ;
 
     private String _charset;
     private boolean _expect = false;
     private boolean _expect100Continue = false;
     private boolean _expect102Processing = false;
     private boolean _head = false;
     private boolean _host = false;
     private boolean _delayedHandling=false;
     private boolean _earlyEOF = false;
 
     /* ------------------------------------------------------------ */
     public static AbstractHttpConnection getCurrentConnection()
     {
         return .get();
     }
 
     /* ------------------------------------------------------------ */
     protected static void setCurrentConnection(AbstractHttpConnection connection)
     {
         .set(connection);
     }
 
     /* ------------------------------------------------------------ */
     public AbstractHttpConnection(Connector connectorEndPoint endpointServer server)
     {
         super(endpoint);
          = connector;
         HttpBuffers ab = (HttpBuffers);
          = newHttpParser(ab.getRequestBuffers(), endpointnew RequestHandler());
          = new HttpFields();
          = new HttpFields();
          = new Request(this);
          = new Response(this);
          = newHttpGenerator(ab.getResponseBuffers(), endpoint);
          = server;
     }
 
     /* ------------------------------------------------------------ */
     protected AbstractHttpConnection(Connector connectorEndPoint endpointServer server,
             Parser parserGenerator generatorRequest request)
     {
         super(endpoint);
 
          = connector;
          = parser;
          = new HttpFields();
          = new HttpFields();
          = request;
          = new Response(this);
          = generator;
          = server;
     }
 
     protected HttpParser newHttpParser(Buffers requestBuffersEndPoint endpointHttpParser.EventHandler requestHandler)
     {
         return new HttpParser(requestBuffersendpointrequestHandler);
     }
 
     protected HttpGenerator newHttpGenerator(Buffers responseBuffersEndPoint endPoint)
     {
         return new HttpGenerator(responseBuffersendPoint);
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
the parser used by this connection
 
     public Parser getParser()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
the number of requests handled by this connection
 
     public int getRequests()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
     public Server getServer()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
Returns the associatedObject.
 
     public Object getAssociatedObject()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
    

Parameters:
associatedObject The associatedObject to set.
 
     public void setAssociatedObject(Object associatedObject)
     {
          = associatedObject;
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
Returns the connector.
 
     public Connector getConnector()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
Returns the requestFields.
 
     public HttpFields getRequestFields()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
Returns the responseFields.
 
     public HttpFields getResponseFields()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
    
Find out if the request supports CONFIDENTIAL security.

Parameters:
request the incoming HTTP request
Returns:
the result of calling Connector.isConfidential(org.eclipse.jetty.server.Request), or false if there is no connector
 
     public boolean isConfidential(Request request)
     {
         return  != null && .isConfidential(request);
     }
 
     /* ------------------------------------------------------------ */
    
Find out if the request supports INTEGRAL security.

Parameters:
request the incoming HTTP request
Returns:
the result of calling Connector.isIntegral(org.eclipse.jetty.server.Request), or false if there is no connector
 
     public boolean isIntegral(Request request)
     {
         return  != null && .isIntegral(request);
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
false (this method is not yet implemented)
 
     public boolean getResolveNames()
     {
         return .getResolveNames();
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
Returns the request.
 
     public Request getRequest()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
Returns the response.
 
     public Response getResponse()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
    
Get the inputStream from the connection.

If the associated response has the Expect header set to 100 Continue, then accessing the input stream indicates that the handler/servlet is ready for the request body and thus a 100 Continue response is sent.

Returns:
The input stream for this connection. The stream will be created if it does not already exist.
Throws:
java.io.IOException if the input stream cannot be retrieved
 
     public ServletInputStream getInputStream() throws IOException
     {
         // If the client is expecting 100 CONTINUE, then send it now.
         if ()
         {
             // is content missing?
             if (((HttpParser)).getHeaderBuffer()==null || ((HttpParser)).getHeaderBuffer().length()<2)
             {
                 if (.isCommitted())
                     throw new IllegalStateException("Committed before 100 Continues");
 
                 ((HttpGenerator)).send1xx(.);
             }
             =false;
         }
 
         if ( == null)
              = new HttpInput(AbstractHttpConnection.this);
         return ;
     }
 
     /* ------------------------------------------------------------ */
    

Returns:
The output stream for this connection. The stream will be created if it does not already exist.
 
     {
         if ( == null)
              = new Output();
         return ;
     }
 
     /* ------------------------------------------------------------ */
    

Parameters:
encoding the PrintWriter encoding
Returns:
A java.io.PrintWriter wrapping the output stream. The writer is created if it does not already exist.
 
     public PrintWriter getPrintWriter(String encoding)
     {
         getOutputStream();
         if (==null)
         {
             =new OutputWriter();
             if (.isUncheckedPrintWriter())
                 =new UncheckedPrintWriter();
             else
                  = new PrintWriter()
                 {
                     public void close()
                     {
                         synchronized ()
                         {
                             try
                             {
                                 .close();
                             }
                             catch (IOException e)
                             {
                                 setError();
                             }
                         }
                     }
                 };
         }
         .setCharacterEncoding(encoding);
         return ;
     }
 
     /* ------------------------------------------------------------ */
     public boolean isResponseCommitted()
     {
         return .isCommitted();
     }
 
     /* ------------------------------------------------------------ */
     public boolean isEarlyEOF()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
     public void reset()
     {
         .reset();
         .returnBuffers(); // TODO maybe only on unhandle
         .clear();
         .recycle();
         .reset();
         .returnBuffers();// TODO maybe only on unhandle
         .clear();
         .recycle();
         .clear();
         =null;
          = false;
     }
 
     /* ------------------------------------------------------------ */
     protected void handleRequest() throws IOException
     {
         boolean error = false;
 
         String threadName=null;
         Throwable async_exception=null;
         try
         {
             if (.isDebugEnabled())
             {
                 threadName=Thread.currentThread().getName();
                 Thread.currentThread().setName(threadName+" - "+);
             }
 
 
             // Loop here to handle async request redispatches.
             // The loop is controlled by the call to async.unhandle in the
             // finally block below.  If call is from a non-blocking connector,
             // then the unhandle will return false only if an async dispatch has
             // already happened when unhandle is called.   For a blocking connector,
             // the wait for the asynchronous dispatch or timeout actually happens
             // within the call to unhandle().
 
             final Server server=;
             boolean handling=..handling() && server!=null && server.isRunning();
             while (handling)
             {
                 .setHandled(false);
 
                 String info=null;
                 try
                 {
                     .getPort();
                     String path = null;
 
                     try
                     {
                         path = .getDecodedPath();
                     }
                     catch (Exception e)
                     {
                         .warn("Failed UTF-8 decode for request path, trying ISO-8859-1");
                         .ignore(e);
                         path = .getDecodedPath(.);
                     }
 
                     info=URIUtil.canonicalPath(path);
                     if (info==null && !.getMethod().equals(.))
                     {
                         if (.getScheme()!=null && .getHost()!=null)
                             info="/";
                         else
                             throw new HttpException(400);
                     }
                     .setPathInfo(info);
 
                     if (!=null)
                         .reopen();
 
                     if (..isInitial())
                     {
                         .setDispatcherType(.);
                         .customize();
                         server.handle(this);
                     }
                     else
                     {
                         .setDispatcherType(.);
                         server.handleAsync(this);
                     }
                 }
                 catch (ContinuationThrowable e)
                 {
                     .ignore(e);
                 }
                 catch (EofException e)
                 {
                     async_exception=e;
                     .debug(e);
                     error=true;
                     .setHandled(true);
                     if (!.isCommitted())
                         .sendError(500, nullnulltrue);
                 }
                 catch (RuntimeIOException e)
                 {
                     async_exception=e;
                     .debug(e);
                     error=true;
                     .setHandled(true);
                 }
                 catch (HttpException e)
                 {
                     .debug(e);
                     error=true;
                     .setHandled(true);
                     .sendError(e.getStatus(), e.getReason());
                 }
                 catch (Throwable e)
                 {
                     async_exception=e;
                     .warn(String.valueOf(),e);
                     error=true;
                     .setHandled(true);
                     .sendError(info==null?400:500, nullnulltrue);
                 }
                 finally
                 {
                     handling = !..unhandle() && server.isRunning() && !=null;
                 }
             }
         }
         finally
         {
             if (threadName!=null)
                 Thread.currentThread().setName(threadName);
 
             if (..isUncompleted())
             {
                 
                 ..doComplete(async_exception);
 
                 if ()
                 {
                     .debug("100 continues not sent");
                     // We didn't send 100 continues, but the latest interpretation
                     // of the spec (see httpbis) is that the client will either
                     // send the body anyway, or close.  So we no longer need to
                     // do anything special here other than make the connection not persistent
                      = false;
                     if (!.isCommitted())
                         .setPersistent(false);
                 }
 
                 if(.isOpen())
                 {
                     if (error)
                     {
                         .shutdownOutput();
                         .setPersistent(false);
                         if (!.isComplete())
                             .complete();
                     }
                     else
                     {
                         if (!.isCommitted() && !.isHandled())
                             .sendError(.);
                         .complete();
                         if (.isPersistent())
                             .persist();
                     }
                 }
                 else
                 {
                     .complete();
                 }
 
                 .setHandled(true);
             }
         }
     }
 
     /* ------------------------------------------------------------ */
     public abstract Connection handle() throws IOException;
 
     /* ------------------------------------------------------------ */
     public void commitResponse(boolean lastthrows IOException
     {
         if (!.isCommitted())
         {
             try
             {
                 // If the client was expecting 100 continues, but we sent something
                 // else, then we need to close the connection
                 if ( && .getStatus()!=100)
                     .setPersistent(false);
                 .completeHeader(last);
             }
             catch(RuntimeException e)
             {
                 .warn("header full: " + e);
 
                 .reset();
                 .reset();
                 .setResponse(.,null);
                 .completeHeader(,.);
                 .complete();
                 throw new HttpException(.);
             }
 
         }
         if (last)
             .complete();
     }
 
     /* ------------------------------------------------------------ */
     public void completeResponse() throws IOException
     {
         if (!.isCommitted())
         {
             try
             {
                 .completeHeader(.);
             }
             catch(RuntimeException e)
             {
                 .warn("header full: "+e);
                 .debug(e);
 
                 .reset();
                 .reset();
                 .setResponse(.,null);
                 .completeHeader(,.);
                 .complete();
                 throw new HttpException(.);
             }
         }
 
         .complete();
     }
 
     /* ------------------------------------------------------------ */
     public void flushResponse() throws IOException
     {
         try
         {
             commitResponse(.);
             .flushBuffer();
         }
         catch(IOException e)
         {
             throw (e instanceof EofException) ? e:new EofException(e);
         }
     }
 
     /* ------------------------------------------------------------ */
     public Generator getGenerator()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
     public boolean isIncluding()
     {
         return >0;
     }
 
     /* ------------------------------------------------------------ */
     public void include()
     {
         ++;
     }
 
     /* ------------------------------------------------------------ */
     public void included()
     {
         --;
         if (!=null)
             .reopen();
     }
 
     /* ------------------------------------------------------------ */
     public boolean isIdle()
     {
         return .isIdle() && (.isIdle() || );
     }
 
     /* ------------------------------------------------------------ */
    
 
     public boolean isSuspended()
     {
         return .getAsyncContinuation().isSuspended();
     }
 
     /* ------------------------------------------------------------ */
     public void onClose()
     {
         .debug("closed {}",this);
     }
 
     /* ------------------------------------------------------------ */
     public boolean isExpecting100Continues()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
     public boolean isExpecting102Processing()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
     public int getMaxIdleTime()
     {
             return .getLowResourceMaxIdleTime();
         if (.getMaxIdleTime()>0)
             return .getMaxIdleTime();
         return .getMaxIdleTime();
     }
 
     /* ------------------------------------------------------------ */
     public String toString()
     {
         return String.format("%s,g=%s,p=%s,r=%d",
                 super.toString(),
                 ,
                 ,
                 );
     }
 
     /* ------------------------------------------------------------ */
     protected void startRequest(Buffer methodBuffer uriBuffer versionthrows IOException
     {
         uri=uri.asImmutableBuffer();
 
          = false;
          = false;
         =false;
         =false;
         =false;
         =null;
 
         if(.getTimeStamp()==0)
             .setTimeStamp(System.currentTimeMillis());
         .setMethod(method.toString());
 
         try
         {
             =false;
             switch (..getOrdinal(method))
             {
               case .:
                   .parseConnect(uri.array(), uri.getIndex(), uri.length());
                   break;
 
               case .:
                   =true;
                   .parse(uri.array(), uri.getIndex(), uri.length());
                   break;
 
               default:
                   .parse(uri.array(), uri.getIndex(), uri.length());
             }
 
             .setUri();
 
             if (version==null)
             {
                 .setProtocol(.);
                 =.;
             }
             else
             {
                 version..get(version);
                 if (version==null)
                     throw new HttpException(.,null);
                  = ..getOrdinal(version);
                 if ( <= 0)  = .;
                 .setProtocol(version.toString());
             }
         }
         catch (Exception e)
         {
             .debug(e);
             if (e instanceof HttpException)
                 throw (HttpException)e;
             throw new HttpException(.,null,e);
         }
     }
 
     /* ------------------------------------------------------------ */
     protected void parsedHeader(Buffer nameBuffer valuethrows IOException
     {
         int ho = ..getOrdinal(name);
         switch (ho)
         {
             case .:
                 // TODO check if host matched a host in the URI.
                  = true;
                 break;
 
             case .:
                 value = ..lookup(value);
                 switch(..getOrdinal(value))
                 {
                     case .:
                         = instanceof HttpGenerator;
                         break;
 
                     case .:
                         = instanceof HttpGenerator;
                         break;
 
                     default:
                         String[] values = value.toString().split(",");
                         for  (int i=0;values!=null && i<values.length;i++)
                         {
                             CachedBuffer cb=..get(values[i].trim());
                             if (cb==null)
                                 =true;
                             else
                             {
                                 switch(cb.getOrdinal())
                                 {
                                     case .:
                                         = instanceof HttpGenerator;
                                         break;
                                     case .:
                                         = instanceof HttpGenerator;
                                         break;
                                     default:
                                         =true;
                                 }
                             }
                         }
                 }
                 break;
 
             case .:
             case .:
                 value = ..lookup(value);
                 break;
 
             case .:
                 value = ..lookup(value);
                 =MimeTypes.getCharsetFromContentType(value);
                 break;
         }
 
         .add(namevalue);
     }
 
     /* ------------------------------------------------------------ */
     protected void headerComplete() throws IOException
     {
         ++;
         .setVersion();
         switch ()
         {
             case .:
                 break;
             case .:
                 .setHead();
                 if (.isPersistent())
                 {
                     .setPersistent(true);
                 }
                 else if (..equals(.getMethod()))
                 {
                     .setPersistent(true);
                     .setPersistent(true);
                 }
 
                 if (.getSendDateHeader())
                     .setDate(.getTimeStampBuffer());
                 break;
 
             case .:
                 .setHead();
 
                 if (!.isPersistent())
                 {
                     .setPersistent(false);
                 }
                 if (.getSendDateHeader())
                     .setDate(.getTimeStampBuffer());
 
                 if (!)
                 {
                     .debug("!host {}",this);
                     .setResponse(.null);
                     .completeHeader(true);
                     .complete();
                     return;
                 }
 
                 if ()
                 {
                     .debug("!expectation {}",this);
                     .setResponse(.null);
                     .completeHeader(true);
                     .complete();
                     return;
                 }
 
                 break;
             default:
         }
 
         if(!=null)
 
         // Either handle now or wait for first content
             handleRequest();
         else
             =true;
     }
 
     /* ------------------------------------------------------------ */
     protected void content(Buffer bufferthrows IOException
     {
         if ()
         {
             =false;
             handleRequest();
         }
     }
 
     /* ------------------------------------------------------------ */
     public void messageComplete(long contentLengththrows IOException
     {
         if ()
         {
             =false;
             handleRequest();
         }
     }
 
     /* ------------------------------------------------------------ */
     public void earlyEOF()
     {
          = true;
     }
 
     /* ------------------------------------------------------------ */
     /* ------------------------------------------------------------ */
     /* ------------------------------------------------------------ */
     private class RequestHandler extends HttpParser.EventHandler
     {
         /*
          *
          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#startRequest(org.eclipse.io.Buffer,
          *      org.eclipse.io.Buffer, org.eclipse.io.Buffer)
          */
         @Override
         public void startRequest(Buffer methodBuffer uriBuffer versionthrows IOException
         {
             AbstractHttpConnection.this.startRequest(methoduriversion);
         }
 
         /*
          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#parsedHeaderValue(org.eclipse.io.Buffer)
          */
         @Override
         public void parsedHeader(Buffer nameBuffer valuethrows IOException
         {
             AbstractHttpConnection.this.parsedHeader(namevalue);
         }
 
         /*
          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#headerComplete()
          */
         @Override
         public void headerComplete() throws IOException
         {
             AbstractHttpConnection.this.headerComplete();
         }
 
         /* ------------------------------------------------------------ */
         /*
          * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#content(int, org.eclipse.io.Buffer)
          */
         @Override
         public void content(Buffer refthrows IOException
         {
             AbstractHttpConnection.this.content(ref);
         }
        /* ------------------------------------------------------------ */
        /*
         * (non-Javadoc)
         *
         * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#messageComplete(int)
         */
        @Override
        public void messageComplete(long contentLengththrows IOException
        {
            AbstractHttpConnection.this.messageComplete(contentLength);
        }
        /* ------------------------------------------------------------ */
        /*
         * (non-Javadoc)
         *
         * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#startResponse(org.eclipse.io.Buffer, int,
         *      org.eclipse.io.Buffer)
         */
        @Override
        public void startResponse(Buffer versionint statusBuffer reason)
        {
            if (.isDebugEnabled())
                .debug("Bad request!: "+version+" "+status+" "+reason);
        }
        /* ------------------------------------------------------------ */
        /*
         * (non-Javadoc)
         *
         * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#earlyEOF()
         */
        @Override
        public void earlyEOF()
        {
            AbstractHttpConnection.this.earlyEOF();
        }
    }
    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    public class Output extends HttpOutput
    {
        Output()
        {
            super(AbstractHttpConnection.this);
        }
        /* ------------------------------------------------------------ */
        /*
         * @see java.io.OutputStream#close()
         */
        @Override
        public void close() throws IOException
        {
            if (isClosed())
                return;
            if (!isIncluding() && !super..isCommitted())
                commitResponse(.);
            else
                flushResponse();
            super.close();
        }
        /* ------------------------------------------------------------ */
        /*
         * @see java.io.OutputStream#flush()
         */
        @Override
        public void flush() throws IOException
        {
            if (!super..isCommitted())
                commitResponse(.);
            super.flush();
        }
        /* ------------------------------------------------------------ */
        /*
         * @see javax.servlet.ServletOutputStream#print(java.lang.String)
         */
        @Override
        public void print(String sthrows IOException
        {
            if (isClosed())
                throw new IOException("Closed");
            PrintWriter writer=getPrintWriter(null);
            writer.print(s);
        }
        /* ------------------------------------------------------------ */
        public void sendResponse(Buffer responsethrows IOException
        {
            ((HttpGenerator)super.).sendResponse(response);
        }
        /* ------------------------------------------------------------ */
        public void sendContent(Object contentthrows IOException
        {
            Resource resource=null;
            if (isClosed())
                throw new IOException("Closed");
            if (super..isWritten())
                throw new IllegalStateException("!empty");