jicarilla-sandbox/platform/components/http/impl/src/java/org/jicarilla/http HTTPMessageGenerator.java,1.7,1.8 HTTPParserImpl.java,1.9,1.10

Leo Simons <[email protected]>
Newsgroups gmane.comp.java.jicarilla.cvs
Message-ID <[email protected]>
Update of /cvsroot/jicarilla/jicarilla-sandbox/platform/components/http/impl/src/java/org/jicarilla/http
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1107/platform/components/http/impl/src/java/org/jicarilla/http

Modified Files:
	HTTPMessageGenerator.java HTTPParserImpl.java 
Log Message:
forgot to commit some of this. See weblog for TODO :D

Index: HTTPMessageGenerator.java
===================================================================
RCS file: /cvsroot/jicarilla/jicarilla-sandbox/platform/components/http/impl/src/java/org/jicarilla/http/HTTPMessageGenerator.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- HTTPMessageGenerator.java	31 Mar 2004 19:42:53 -0000	1.7
+++ HTTPMessageGenerator.java	3 Apr 2004 10:13:24 -0000	1.8
@@ -31,7 +31,9 @@
 import org.jicarilla.lang.ExceptionListener;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 
 /**
  * Will populateContainer a HTTPMessage instance based on the events
@@ -226,13 +228,59 @@
         getMessage().addBodyPart( buffer );
     }
 
-    public void foundFooterName( final ByteBuffer footer )
+    public boolean hasTrailers()
     {
-        foundHeaderName( footer );
+        checkState();
+        Iterator it = getMessage().getHeaders().iterator();
+        while( it.hasNext() )
+        {
+            HTTPField field = (HTTPField)it.next();
+            if( HTTPEncoding.HEADER_TRAILER.equalsIgnoreCase(
+                    field.getNameString() ) )
+            {
+                return true;
+            }
+        }
+        return false;
     }
 
-    public void foundFooterValue( final ByteBuffer value )
+    public String[] getTrailerNames()
+    {
+        checkState();
+        Iterator it = getMessage().getHeaders().iterator();
+        List nameList = new ArrayList();
+        while( it.hasNext() )
+        {
+            HTTPField field = (HTTPField)it.next();
+            if( HTTPEncoding.HEADER_TRAILER.equalsIgnoreCase(
+                    field.getNameString() ) )
+            {
+                String[] names = field.getValueString().split( "," );
+                for( int i = 0; i < names.length; i++ )
+                {
+                    nameList.add( names[i].trim() );
+                }
+            }
+        }
+        return (String[])nameList.toArray( new String[nameList.size()] ); 
+    }
+
+    public void foundTrailerName( final ByteBuffer trailer )
+    {
+        checkState();
+        final String trailerString = NioUtil.toString( trailer );
+        Assert.assertFalse(
+                "Illegal trailer",
+                HTTPEncoding.HEADER_TRANSFER_ENCODING.equalsIgnoreCase( trailerString ) ||
+                HTTPEncoding.HEADER_TRAILER.equalsIgnoreCase( trailerString ) ||
+                HTTPEncoding.HEADER_CONTENT_LENGTH.equalsIgnoreCase( trailerString )
+        );
+        foundHeaderName( trailer );
+    }
+
+    public void foundTrailerValue( final ByteBuffer value )
     {
+        checkState();
         foundHeaderValue( value );
     }
 
@@ -243,12 +291,6 @@
         getMessage().setComplete( true );
     }
 
-    public boolean hasTrailers()
-    {
-        // todo
-        return false;
-    }
-
     // ----------------------------------------------------------------------
     //  Work Interface: HTTPErrorHandler
     // ----------------------------------------------------------------------

Index: HTTPParserImpl.java
===================================================================
RCS file: /cvsroot/jicarilla/jicarilla-sandbox/platform/components/http/impl/src/java/org/jicarilla/http/HTTPParserImpl.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- HTTPParserImpl.java	31 Mar 2004 20:36:58 -0000	1.9
+++ HTTPParserImpl.java	3 Apr 2004 10:13:24 -0000	1.10
@@ -26,6 +26,7 @@
 package org.jicarilla.http;
 
 import org.jicarilla.http.util.Iso646;
+import org.jicarilla.http.util.NioUtil;
 import org.jicarilla.lang.Assert;
 
 import java.nio.ByteBuffer;
@@ -810,79 +811,157 @@
 
 // look for a body with chunked transfer coding
             case LOOKING_FOR_CHUNKED_BODY:
-                // todo: finish support for chunked transfer coding
-                throw new HTTPException(
-                        HTTPEncoding.STATUS_500_Internal_Server_Error,
-                        "Chunked transfer coding is not yet supported!" );
-                //getContext().newViewOffByOne();
-                //getContext().state = LOOKING_FOR_CHUNKED_BODY_CHUNK_SIZE;
+                // start reading the size into a new view
+                getContext().newViewOffByOne();
+                getContext().state = LOOKING_FOR_CHUNKED_BODY_CHUNK_SIZE;
                 // fall through
-                
-                //foundChunkedBody();
-                //break;
 
             case LOOKING_FOR_CHUNKED_BODY_CHUNK_SIZE:
+                // found the end of the size field
                 if( getContext().ch == HTTPEncoding.CR )
                 {
-                    // 1) set chunk size
-                    // 2) skip LF
-                    // 3) if size == 0
-                    //       3a) if look for trailers
-                    //          state = look for trailers
-                    //       3b) else
-                    //          state = done
-                    // 4) else -- state = look for chunk contents
+                    // CR followed by LF...make sure it is discarded on the
+                    // next round
                     getContext().skipLF();
-                    getContext().markFieldLimit();
-                    getContext().foundChunkSize( getContext().getAndResetView() );
+                    
+                    // mark the end in the view buffer and keep the size around
+                    // for the next state
+                    getContext().foundChunkSize();
 
-                    if( getContext().chunkSizeLeft == 0 )
+                    // found the end of the body?
+                    if( getContext().chunkSize == 0 )
                     {
-                        getContext().state = LOOKING_FOR_TRAILER;
+                        if( getHandler().hasTrailers() )
+                        {
+                            getContext().state = LOOKING_FOR_TRAILER;
+                        }
+                        else
+                        {
+                            // ...which is the end of the message in this case
+                            getContext().state = DONE;
+                            getHandler().endMessage();
+                        }
                     }
                     else
                     {
+                        // not the end, another chunk is coming
                         getContext().state =
                                 LOOKING_FOR_CHUNKED_BODY_CHUNK_CONTENTS;
                     }
                 }
                 break;
-                
-            case LOOKING_FOR_CHUNKED_BODY_CHUNK_CONTENTS:
-                // 1) determine what to read up to (remaining() or chunk size,
-                //    the smallest one)
-                // 2) read chunk
-                // 3) if read < chunk size: break
-                // 4) else: addBodyPart & state--
 
+            case LOOKING_FOR_CHUNKED_BODY_CHUNK_CONTENTS:
+                // start reading the chunk contents into a new view buffer
+                getContext().newViewOffByOne();
+        
                 // read up to chunkSize, or remaining(), whichever is _less_
                 int remaining = getContext().view.remaining();
-                if( remaining >= getContext().chunkSizeLeft )
-                {
-                    remaining = getContext().chunkSizeLeft;
-                    getContext().view.limit( remaining );
+                if( remaining > getContext().chunkSize )
+                    remaining = getContext().chunkSize;
+                getContext().view.limit( remaining );
+        
+                // send whatever part of the body we've found so far
+                if( remaining > 0 )
                     getHandler().foundBody( getContext().getAndUnsetView() );
+
+                // these already were equal, or we had more left than the
+                // message length and we just set it them to be equal...
+                // in either case, equality means we're done with this chunk!
+                if( remaining == getContext().chunkSize )
+                {
+                    // skip the rest of the chunk and the closing CRLF
+                    // in the source buffer
+                    getContext().source.position(
+                            getContext().source.position() + remaining +1 );
+
+                    // we'll always expect another chunk, though it could have
+                    // a size of zero
                     getContext().state = LOOKING_FOR_CHUNKED_BODY_CHUNK_SIZE;
+                    getContext().newView();
                 }
                 else
                 {
-                    getContext().chunkSizeLeft -= remaining;
+                    // this was an incomplete chunk, skip up to the end
+                    // and get the rest of the chunk from the next buffer
+                    getContext().source.position( getContext().source.limit() );
+                    getContext().chunkSize -= remaining;
+                    
+                    // that next run will create a new view anyway...no need
+                    // to create one here...
                 }
                 break;
             
+    // ----------------------------------------------------------------------
+    //  Trailers
+    // ----------------------------------------------------------------------
+// find a trailer name, including an ugly state to handle the whitespace
             case LOOKING_FOR_TRAILER:
-                if( getHandler().hasTrailers() )
+                getContext().expectedTrailers = m_handler.getTrailerNames();
+                getContext().newViewOffByOne();
+                getContext().state = LOOKING_FOR_TRAILER_NAME;
+                // fall through
+            
+            case LOOKING_FOR_TRAILER_NAME:
+                if( getContext().ch == Iso646.COLON )
+                    foundTrailerName();
+                else
+                    checkHeaderNameValidity();
+                break; // get rid of the colon
+            
+            case SKIPPING_WHITESPACE_AFTER_TRAILER_NAME:
+                if(     getContext().ch != HTTPEncoding.SP &&
+                        getContext().ch != HTTPEncoding.HT )
                 {
-                    // todo handle trailers
+                    if( getContext().ch == HTTPEncoding.CR )
+                    {
+                        // someone lame started the value with a CR. grmbl.
+                        getContext().next();
+                        Assert.assertTrue( getContext().ch == HTTPEncoding.LF );
+                        getContext().newView();
+                        getContext().state = LOOKING_FOR_TRAILER_VALUE_OR_NEXT_TRAILER;
+                        break;
+                    }
+                    else
+                    {
+                        getContext().newViewOffByOne();
+                        getContext().state = LOOKING_FOR_TRAILER_VALUE;
+        // fall through: we've already got the first character of trailer value
+                    }
                 }
                 else
+                    break;
+
+// find a trailer value, including two ugly states to handle the whitespace
+            case LOOKING_FOR_TRAILER_VALUE:
+                if( getContext().ch == HTTPEncoding.CR )
                 {
-                    getContext().state = DONE;
-                    getHandler().endMessage();
+                    getContext().skipLF();
+                    
+                    // todo check for CR
+                    if( getContext().view.remaining() <= 1 )
+                    {
+                        foundTrailerValue();
+                    }
+                    getContext().state =
+                            LOOKING_FOR_TRAILER_VALUE_OR_NEXT_TRAILER;
                 }
-                
-                
-                
+                else
+                    checkHeaderValueValidity();
+                break;
+
+            case LOOKING_FOR_TRAILER_VALUE_OR_NEXT_TRAILER:
+                if( getContext().ch == HTTPEncoding.SP )
+                    getContext().state = SKIPPING_TRAILER_VALUE_WHITESPACE;
+                else
+                    foundTrailerValue();
+                break;
+
+            case SKIPPING_TRAILER_VALUE_WHITESPACE:
+                if(     getContext().ch != HTTPEncoding.SP &&
+                        getContext().ch != HTTPEncoding.HT )
+                    lookForTrailerValue();
+                break;
 
 // this is a bug!
             //case INVALID:
@@ -890,6 +969,7 @@
             //    internalErrorOccurred();
         }
     }
+
 // ----------------------------------------------------------------------
 //  End of The Big Fat Ugly State Machine
 // ----------------------------------------------------------------------
@@ -1193,6 +1273,70 @@
         }
     }
 
+    protected void foundTrailerName() throws HTTPException
+    {
+        getContext().view.limit(
+                getContext().source.position() -
+                getContext().slice - 1 );
+        
+        ByteBuffer name = getContext().getAndUnsetView();
+        
+        String nameString = NioUtil.toString( name );
+        boolean valid = false;
+        for( int i = 0; i < getContext().expectedTrailers.length; i++ )
+        {
+            String trailer = getContext().expectedTrailers[i];
+            if(trailer == null ) continue;
+            if(trailer.equalsIgnoreCase( nameString ) )
+            {
+                getContext().expectedTrailers[i] = null;
+                valid = true;
+            }
+        }
+        if(!valid) m_errorHandler.exceptionOccurred(
+                new HTTPException( HTTPEncoding.STATUS_400_Bad_Request,
+                        "Unexpected trailer '" + nameString + "'!" )
+        );
+        
+        getHandler().foundTrailerName( name );
+
+        getContext().state = SKIPPING_WHITESPACE_AFTER_TRAILER_NAME;
+    }
+
+    protected void foundTrailerValue()
+    {
+        final int newLimit = getContext().source.position() -
+                getContext().slice - 3;
+        getContext().view.limit( newLimit );
+
+        getHandler().foundTrailerValue(
+                getContext().getAndUnsetView() );
+
+        boolean trailersFinished = true;
+        for( int i = 0; i < getContext().expectedTrailers.length; i++ )
+        {
+            String trailer = getContext().expectedTrailers[i];
+            if(trailer != null ) trailersFinished = false;
+        }
+        
+        if( trailersFinished )
+        {
+            getContext().state = DONE;
+            getHandler().endMessage();
+        }
+        else
+        {
+            getContext().newViewOffByOne();
+            getContext().state = LOOKING_FOR_TRAILER_NAME;
+        }
+        
+    }
+
+    private void lookForTrailerValue()
+    {
+        getContext().state = LOOKING_FOR_TRAILER_VALUE;
+    }
+
     // ----------------------------------------------------------------------
     //  Inner Class: Context
     // ----------------------------------------------------------------------
@@ -1260,7 +1404,12 @@
          * Contains the size of the next chunk expected for a body that has
          * a transfer-coding of chunked.
          */ 
-        public int chunkSizeLeft;
+        public int chunkSize;
+        
+        /**
+         * Contains the 
+         */ 
+        public String[] expectedTrailers;
 
         // ------------------------------------------------------------------
         //  Constructor
@@ -1424,7 +1573,7 @@
             ch = Iso646.NULL;
             slice = -1;
             bodySize = -1;
-            chunkSizeLeft = -1;
+            chunkSize = -1;
 
             limit = Integer.MAX_VALUE;
 
@@ -1434,6 +1583,8 @@
             source = null;
             view = null;
             leftovers = null;
+            
+            expectedTrailers = null;
         }
 
         /**
@@ -1463,17 +1614,16 @@
         }
 
         /**
-         * Sets {@link chunkSizeLeft}.
-         * 
-         * @param size how much chunk is left to parse.
+         * Sets {@link chunkSize}.
          */ 
-        public void foundChunkSize( ByteBuffer size )
+        public void foundChunkSize()
         {
-            // todo: support chunked transfer coding
+            getContext().markFieldLimit();
+            final ByteBuffer size = getContext().getAndUnsetView();
             
-            // 1) check buffer is not empty
-            // 2) parse buffer into integer
-            // 3) set chunkSizeLeft
+            Assert.assertTrue( "size may not be empty", size.hasRemaining() );
+            
+            chunkSize = Integer.parseInt( NioUtil.toString( size ), 16 );
         }
 
         /**



-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.