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.http;
  
  
  
  public class HttpParser implements Parser
  {
      private static final Logger LOG = Log.getLogger(HttpParser.class);
  
      // States
      public static final int STATE_START=-14;
      public static final int STATE_FIELD0=-13;
      public static final int STATE_SPACE1=-12;
      public static final int STATE_STATUS=-11;
      public static final int STATE_URI=-10;
      public static final int STATE_SPACE2=-9;
      public static final int STATE_END0=-8;
      public static final int STATE_END1=-7;
      public static final int STATE_FIELD2=-6;
      public static final int STATE_HEADER=-5;
      public static final int STATE_HEADER_NAME=-4;
      public static final int STATE_HEADER_IN_NAME=-3;
      public static final int STATE_HEADER_VALUE=-2;
      public static final int STATE_HEADER_IN_VALUE=-1;
      public static final int STATE_END=0;
      public static final int STATE_EOF_CONTENT=1;
      public static final int STATE_CONTENT=2;
      public static final int STATE_CHUNKED_CONTENT=3;
      public static final int STATE_CHUNK_SIZE=4;
      public static final int STATE_CHUNK_PARAMS=5;
      public static final int STATE_CHUNK=6;
      public static final int STATE_SEEKING_EOF=7;
  
      private final EventHandler _handler;
      private final Buffers _buffers// source of buffers
      private final EndPoint _endp;
      private Buffer _header// Buffer for header data (and small _content)
      private Buffer _body// Buffer for large content
      private Buffer _buffer// The current buffer in use (either _header or _content)
      private CachedBuffer _cached;
      private final View.CaseInsensitive _tok0// Saved token: header name, request method or response version
      private final View.CaseInsensitive _tok1// Saved token: header value, request URI or response code
      private String _multiLineValue;
      private int _responseStatus// If >0 then we are parsing a response
      private boolean _forceContentBuffer;
      private boolean _persistent;
  
      /* ------------------------------------------------------------------------------- */
      protected final View  _contentView=new View(); // View of the content in the buffer for {@link Input}
      protected int _state=;
      protected byte _eol;
      protected int _length;
      protected long _contentLength;
      protected long _contentPosition;
      protected int _chunkLength;
      protected int _chunkPosition;
      private boolean _headResponse;
  
      /* ------------------------------------------------------------------------------- */
    
Constructor.
  
      public HttpParser(Buffer bufferEventHandler handler)
      {
          =null;
          =null;
          =buffer;
          =buffer;
          =handler;
 
         =new View.CaseInsensitive();
         =new View.CaseInsensitive();
     }
 
     /* ------------------------------------------------------------------------------- */
    
Constructor.

Parameters:
buffers the buffers to use
endp the endpoint
handler the even handler
 
     public HttpParser(Buffers buffersEndPoint endpEventHandler handler)
     {
         =buffers;
         =endp;
         =handler;
         =new View.CaseInsensitive();
         =new View.CaseInsensitive();
     }
 
     /* ------------------------------------------------------------------------------- */
     public long getContentLength()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
     public long getContentRead()
     {
         return ;
     }
 
     /* ------------------------------------------------------------ */
    
Set if a HEAD response is expected

Parameters:
head
 
     public void setHeadResponse(boolean head)
     {
         =head;
     }
 
     /* ------------------------------------------------------------------------------- */
     public int getState()
     {
         return ;
     }
 
     /* ------------------------------------------------------------------------------- */
     public boolean inContentState()
     {
         return  > 0;
     }
 
     /* ------------------------------------------------------------------------------- */
     public boolean inHeaderState()
     {
         return  < 0;
     }
 
     /* ------------------------------------------------------------------------------- */
     public boolean isChunking()
     {
         return ==.;
     }
 
     /* ------------------------------------------------------------ */
     public boolean isIdle()
     {
         return isState();
     }
 
     /* ------------------------------------------------------------ */
     public boolean isComplete()
     {
         return isState();
     }
 
     /* ------------------------------------------------------------ */
     public boolean isMoreInBuffer()
     throws IOException
     {
         return ( !=null && .hasContent() ||
              !=null && .hasContent());
     }
 
     /* ------------------------------------------------------------------------------- */
     public boolean isState(int state)
     {
         return  == state;
     }
 
     /* ------------------------------------------------------------------------------- */
     public boolean isPersistent()
     {
         return ;
     }
 
     /* ------------------------------------------------------------------------------- */
     public void setPersistent(boolean persistent)
     {
          = persistent;
         if (! &&(== || ==))
             =;
     }
 
     /* ------------------------------------------------------------------------------- */
    
Parse until END state. If the parser is already in the END state, then it is reset and re-parsed.

Throws:
java.lang.IllegalStateException If the buffers have already been partially parsed.
 
     public void parse() throws IOException
     {
         if (==)
             reset();
         if (!=)
             throw new IllegalStateException("!START");
 
         // continue parsing
         while ( != )
             if (parseNext()<0)
                 return;
     }
 
     /* ------------------------------------------------------------------------------- */
    
Parse until END state. This method will parse any remaining content in the current buffer. It does not care about the current state of the parser.

 
     public boolean parseAvailable() throws IOException
     {
         boolean progress=parseNext()>0;
 
         // continue parsing
         while (!isComplete() && !=null && .length()>0)
         {
             progress |= parseNext()>0;
         }
         return progress;
     }
 
 
     /* ------------------------------------------------------------------------------- */
    
Parse until next Event.

Returns:
an indication of progress <0 EOF, 0 no progress, >0 progress.
 
     public int parseNext() throws IOException
     {
         try
         {
             int progress=0;
 
             if ( == )
                 return 0;
 
             if (==null)
                 =getHeaderBuffer();
 
 
             if ( ==  &&  == )
             {
                 =;
                 .messageComplete();
                 return 1;
             }
 
             int length=.length();
 
             // Fill buffer if we can
             if (length == 0)
             {
                 int filled=-1;
                 IOException ex=null;
                 try
                 {
                     filled=fill();
                     .debug("filled {}/{}",filled,.length());
                 }
                 catch(IOException e)
                 {
                     .debug(this.toString(),e);
                     ex=e;
                 }
 
                 if (filled > 0 )
                     progress++;
                 else if (filled < 0 )
                 {
                     =false;
 
                     // do we have content to deliver?
                     if (>)
                     {
                         if (.length()>0 && !)
                         {
                             Buffer chunk=.get(.length());
                              += chunk.length();
                             .update(chunk);
                             .content(chunk); // May recurse here
                         }
                     }
 
                     // was this unexpected?
                     switch()
                     {
                         case :
                         case :
                             =;
                             break;
 
                         case :
                             =;
                             .messageComplete();
                             break;
 
                         default:
                             =;
                             if (!)
                                 .earlyEOF();
                             .messageComplete();
                     }
 
                     if (ex!=null)
                         throw ex;
 
                     if (!isComplete() && !isIdle())
                         throw new EofException();
 
                     return -1;
                 }
                 length=.length();
             }
 
 
             // Handle header states
             byte ch;
             byte[] array=.array();
             int last=;
             while (< && length-->0)
             {
                 if (last!=)
                 {
                     progress++;
                     last=;
                 }
 
                 ch=.get();
 
                 if ( == . && ch == .)
                 {
                     =.;
                     continue;
                 }
                 =0;
 
                 switch ()
                 {
                     case :
                         =.;
                         =null;
                         if (ch > . || ch<0)
                         {
                             .mark();
                             =;
                         }
                         break;
 
                     case :
                         if (ch == .)
                         {
                             .update(.markIndex(), .getIndex() - 1);
                             =..get()==null?-1:0;
                             =;
                             continue;
                         }
                         else if (ch < . && ch>=0)
                         {
                             throw new HttpException(.);
                         }
                         break;
 
                     case :
                         if (ch > . || ch<0)
                         {
                             .mark();
                             if (>=0)
                             {
                                 =;
                                 =ch-'0';
                             }
                             else
                                 =;
                         }
                         else if (ch < .)
                         {
                             throw new HttpException(.);
                         }
                         break;
 
                     case :
                         if (ch == .)
                         {
                             .update(.markIndex(), .getIndex() - 1);
                             =;
                             continue;
                         }
                         else if (ch>='0' && ch<='9')
                         {
                             =*10+(ch-'0');
                             continue;
                         }
                         else if (ch < . && ch>=0)
                         {
                             .startResponse(..lookup(), null);
                             =ch;
                             =;
                             .setPutIndex(.getIndex());
                             .setPutIndex(.getIndex());
                             =null;
                             continue;
                         }
                         // not a digit, so must be a URI
                         =;
                         =-1;
                         break;
 
                     case :
                         if (ch == .)
                         {
                             .update(.markIndex(), .getIndex() - 1);
                             =;
                             continue;
                         }
                         else if (ch < . && ch>=0)
                         {
                             // HTTP/0.9
                             .startRequest(..lookup(), .sliceFromMark(), null);
                             =false;
                             =;
                             .headerComplete();
                             .messageComplete();
                             return 1;
                         }
                         break;
 
                     case :
                         if (ch > . || ch<0)
                         {
                             .mark();
                             =;
                         }
                         else if (ch < .)
                         {
                             if (>0)
                             {
                                 .startResponse(..lookup(), null);
                                 =ch;
                                 =;
                                 .setPutIndex(.getIndex());
                                 .setPutIndex(.getIndex());
                                 =null;
                             }
                             else
                             {
                                 // HTTP/0.9
                                 .startRequest(..lookup(), null);
                                 =false;
                                 =;
                                 .headerComplete();
                                 .messageComplete();
                                 return 1;
                             }
                         }
                         break;
 
                     case :
                         if (ch == . || ch == .)
                         {
                             Buffer version;
                             if (>0)
                                 .startResponse(version=..lookup(), ,.sliceFromMark());
                             else
                                 .startRequest(..lookup(), version=..lookup(.sliceFromMark()));
                             =ch;
                             =..getOrdinal(version)>=.;
                             =;
                             .setPutIndex(.getIndex());
                             .setPutIndex(.getIndex());
                             =null;
                             continue;
                         }
                         break;
 
                     case :
                         switch(ch)
                         {
                             case .:
                             case .:
                             case .:
                             {
                                 // header value without name - continuation?
                                 =-1;
                                 =;
                                 break;
                             }
 
                             default:
                             {
                                 // handler last header if any
                                 if (!=null || .length() > 0 || .length() > 0 ||  != null)
                                 {
                                     Buffer header=!=null?:..lookup();
                                     =null;
                                     Buffer value= == null ?  : new ByteArrayBuffer();
 
                                     int ho=..getOrdinal(header);
                                     if (ho >= 0)
                                     {
                                         int vo;
 
                                         switch (ho)
                                         {
                                             case .:
                                                 if ( != . && !=304 && !=204 && (<100 || >=200))
                                                 {
                                                     try
                                                     {
                                                         =BufferUtil.toLong(value);
                                                     }
                                                     catch(NumberFormatException e)
                                                     {
                                                         .ignore(e);
                                                         throw new HttpException(.);
                                                     }
                                                     if ( <= 0)
                                                         =.;
                                                 }
                                                 break;
 
                                             case .:
                                                 value=..lookup(value);
                                                 vo=..getOrdinal(value);
                                                 if (. == vo)
                                                     =.;
                                                 else
                                                 {
                                                     String c=value.toString(.);
                                                     if (c.endsWith(.))
                                                         =.;
 
                                                     else if (c.indexOf(.) >= 0)
                                                         throw new HttpException(400,null);
                                                 }
                                                 break;
 
                                             case .:
                                                 switch(..getOrdinal(value))
                                                 {
                                                     case .:
                                                         =false;
                                                         break;
 
                                                     case .:
                                                         =true;
                                                         break;
 
                                                     case -1: // No match, may be multi valued
                                                     {
                                                         for (String v : value.toString().split(","))
                                                         {
                                                             switch(..getOrdinal(v.trim()))
                                                             {
                                                                 case .:
                                                                     =false;
                                                                     break;
 
                                                                 case .:
                                                                     =true;
                                                                     break;
                                                             }
                                                         }
                                                         break;
                                                     }
                                                 }
                                         }
                                     }
 
                                     .parsedHeader(headervalue);
                                     .setPutIndex(.getIndex());
                                     .setPutIndex(.getIndex());
                                     =null;
                                 }
                                 .setMarkIndex(-1);
 
 
                                 // now handle ch
                                 if (ch == . || ch == .)
                                 {
                                     // work out the _content demarcation
                                     if ( == .)
                                     {
                                         if ( == 0  // request
                                                 ||  == 304 // not-modified response
                                                 ||  == 204 // no-content response
                                                 ||  < 200) // 1xx response
                                             =.;
                                         else
                                             =.;
                                     }
 
                                     =0;
                                     =ch;
                                     if (==. && .hasContent() && .peek()==.)
                                         =.get();
 
                                     // We convert _contentLength to an int for this switch statement because
                                     // we don't care about the amount of data available just whether there is some.
                                     switch ( > . ? . : (int)
                                     {
                                         case .:
                                             =;
                                             .headerComplete(); // May recurse here !
                                             break;
 
                                         case .:
                                             =;
                                             .headerComplete(); // May recurse here !
                                             break;
 
                                         case .:
                                             .headerComplete();
                                             =||(>=100&&<200)?:;
                                             .messageComplete();
                                             return 1;
 
                                         default:
                                             =;
                                             .headerComplete(); // May recurse here !
                                             break;
                                     }
                                     return 1;
                                 }
                                 else
                                 {
                                     // New header
                                     =1;
                                     .mark();
                                     =;
 
                                     // try cached name!
                                     if (array!=null)
                                     {
                                         =..getBest(array.markIndex(), length+1);
 
                                         if (!=null)
                                         {
                                             =.length();
                                             .setGetIndex(.markIndex()+);
                                             length=.length();
                                         }
                                     }
                                 }
                             }
                         }
 
                         break;
 
                     case :
                         switch(ch)
                         {
                             case .:
                             case .:
                                 if ( > 0)
                                     .update(.markIndex(), .markIndex() + );
                                 =ch;
                                 =;
                                 break;
                             case .:
                                 if ( > 0 && ==null)
                                     .update(.markIndex(), .markIndex() + );
                                 =-1;
                                 =;
                                 break;
                             case .:
                             case .:
                                 break;
                             default:
                             {
                                 =null;
                                 if ( == -1)
                                     .mark();
                                 =.getIndex() - .markIndex();
                                 =;
                             }
                         }
 
                         break;
 
                     case :
                         switch(ch)
                         {
                             case .:
                             case .:
                                 if ( > 0)
                                     .update(.markIndex(), .markIndex() + );
                                 =ch;
                                 =;
                                 break;
                             case .:
                                 if ( > 0 && ==null)
                                     .update(.markIndex(), .markIndex() + );
                                 =-1;
                                 =;
                                 break;
                             case .:
                             case .:
                                 =;
                                 break;
                             default:
                             {
                                 =null;
                                 ++;
                             }
                         }
                         break;
 
                     case :
                         switch(ch)
                         {
                             case .:
                             case .:
                                 if ( > 0)
                                 {
                                     if (.length() == 0)
                                         .update(.markIndex(), .markIndex() + );
                                     else
                                     {
                                         // Continuation line!
                                         if ( == null=.toString(.);
                                         .update(.markIndex(), .markIndex() + );
                                          += " " + .toString(.);
                                     }
                                 }
                                 =ch;
                                 =;
                                 break;
                             case .:
                             case .:
                                 break;
                             default:
                             {
                                 if ( == -1)
                                     .mark();
                                 =.getIndex() - .markIndex();
                                 =;
                             }
                         }
                         break;
 
                     case :
                         switch(ch)
                         {
                             case .:
                             case .:
                                 if ( > 0)
                                 {
                                     if (.length() == 0)
                                         .update(.markIndex(), .markIndex() + );
                                     else
                                     {
                                         // Continuation line!
                                         if ( == null=.toString(.);
                                         .update(.markIndex(), .markIndex() + );
                                          += " " + .toString(.);
                                     }
                                 }
                                 =ch;
                                 =;
                                 break;
                             case .:
                             case .:
                                 =;
                                 break;
                             default:
                                 ++;
                         }
                         break;
                 }
             } // end of HEADER states loop
 
             // ==========================
 
             // Handle HEAD response
             if (>0 && )
             {
                 =||(>=100&&<200)?:;
                 .messageComplete();
             }
 
 
             // ==========================
 
             // Handle _content
             length=.length();
             Buffer chunk;
             last=;
             while ( >  && length > 0)
             {
                 if (last!=)
                 {
                     progress++;
                     last=;
                 }
 
                 if ( == . && .peek() == .)
                 {
                     =.get();
                     length=.length();
                     continue;
                 }
                 =0;
                 switch ()
                 {
                     case :
                         chunk=.get(.length());
                          += chunk.length();
                         .update(chunk);
                         .content(chunk); // May recurse here
                         // TODO adjust the _buffer to keep unconsumed content
                         return 1;
 
                     case :
                     {
                         long remaining= - ;
                         if (remaining == 0)
                         {
                             =?:;
                             .messageComplete();
                             return 1;
                         }
 
                         if (length > remaining)
                         {
                             // We can cast reamining to an int as we know that it is smaller than
                             // or equal to length which is already an int.
                             length=(int)remaining;
                         }
 
                         chunk=.get(length);
                          += chunk.length();
                         .update(chunk);
                         .content(chunk); // May recurse here
 
                         if( == )
                         {
                             =?:;
                             .messageComplete();
                         }
                         // TODO adjust the _buffer to keep unconsumed content
                         return 1;
                     }
 
                     case :
                     {
                         ch=.peek();
                         if (ch == . || ch == .)
                             =.get();
                         else if (ch <= .)
                             .get();
                         else
                         {
                             =0;
                             =0;
                             =;
                         }
                         break;
                     }
 
                     case :
                     {
                         ch=.get();
                         if (ch == . || ch == .)
                         {
                             =ch;
 
                             if ( == 0)
                             {
                                 if (==. && .hasContent() && .peek()==.)
                                     =.get();
                                 =?:;
                                 .messageComplete();
                                 return 1;
                             }
                             else
                                 =;
                         }
                         else if (ch <= . || ch == .)
                             =;
                         else if (ch >= '0' && ch <= '9')
                             = * 16 + (ch - '0');
                         else if (ch >= 'a' && ch <= 'f')
                             = * 16 + (10 + ch - 'a');
                         else if (ch >= 'A' && ch <= 'F')
                             = * 16 + (10 + ch - 'A');
                         else
                             throw new IOException("bad chunk char: " + ch);
                         break;
                     }
 
                     case :
                     {
                         ch=.get();
                         if (ch == . || ch == .)
                         {
                             =ch;
                             if ( == 0)
                             {
                                 if (==. && .hasContent() && .peek()==.)
                                     =.get();
                                 =?:;
                                 .messageComplete();
                                 return 1;
                             }
                             else
                                 =;
                         }
                         break;
                     }
 
                     case :
                     {
                         int remaining= - ;
                         if (remaining == 0)
                         {
                             =;
                             break;
                         }
                         else if (length > remaining)
                             length=remaining;
                         chunk=.get(length);
                          += chunk.length();
                          += chunk.length();
                         .update(chunk);
                         .content(chunk); // May recurse here
                         // TODO adjust the _buffer to keep unconsumed content
                         return 1;
                     }
 
                     case :
                     {                        
                         // Close if there is more data than CRLF
                         if (.length()>2)
                         {
                             =;
                             .close();
                         }
                         else  
                         {
                             // or if the data is not white space
                             while (.