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