jetty-9 work in progress on new HttpGenerator

This commit is contained in:
Greg Wilkins 2012-03-02 11:39:42 +11:00
parent 1fa6c998db
commit a4bee5b12d
7 changed files with 936 additions and 786 deletions

View File

@ -24,6 +24,7 @@ import java.util.Date;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -49,7 +50,7 @@ import org.eclipse.jetty.util.log.Logger;
* *
* *
*/ */
public class HttpFields public class HttpFields implements Iterable<HttpFields.Field>
{ {
private static final Logger LOG = Log.getLogger(HttpFields.class); private static final Logger LOG = Log.getLogger(HttpFields.class);
@ -363,6 +364,12 @@ public class HttpFields
return _fields.get(i); return _fields.get(i);
} }
/* ------------------------------------------------------------ */
public Iterator<Field> iterator()
{
return _fields.iterator();
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public Field getField(HttpHeader header) public Field getField(HttpHeader header)
{ {

View File

@ -43,40 +43,82 @@ public class HttpGeneratorTest
{ {
ByteBuffer header=BufferUtil.allocate(8096); ByteBuffer header=BufferUtil.allocate(8096);
HttpFields fields = new HttpFields(); HttpFields fields = new HttpFields();
HttpGenerator hg = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
fields.add("Host","something"); fields.add("Host","something");
fields.add("User-Agent","test"); fields.add("User-Agent","test");
hg.setRequest(HttpMethod.GET,"/index.html",HttpVersion.HTTP_1_1); gen.setRequest(HttpMethod.GET,"/index.html",HttpVersion.HTTP_1_1);
hg.completeHeader(header,fields,true);
hg.complete();
HttpGenerator.Result
result=gen.complete(null,null);
assertEquals(HttpGenerator.Result.NEED_COMMIT,result);
result=gen.commit(fields,header,null,null,true);
String out = BufferUtil.toString(header); String out = BufferUtil.toString(header);
BufferUtil.clear(header);
assertEquals(HttpGenerator.Result.NEED_COMPLETE,result);
result=gen.complete(null,null);
assertEquals(HttpGenerator.Result.OK,result);
assertTrue(out.indexOf("GET /index.html HTTP/1.1")==0); assertTrue(out.indexOf("GET /index.html HTTP/1.1")==0);
assertTrue(out.indexOf("Content-Length")==-1); assertTrue(out.indexOf("Content-Length")==-1);
}
assertEquals(HttpGenerator.State.END,gen.getState());
assertEquals(0,gen.getContentWritten()); }
@Test @Test
public void testRequestWithContent() throws Exception public void testRequestWithSmallContent() throws Exception
{ {
ByteBuffer header=BufferUtil.allocate(8096); ByteBuffer header=BufferUtil.allocate(8096);
ByteBuffer buffer=BufferUtil.allocate(8096);
ByteBuffer content=BufferUtil.toBuffer("Hello World");
HttpFields fields = new HttpFields(); HttpFields fields = new HttpFields();
HttpGenerator hg = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
hg.setRequest("GET","/index.html"); gen.setVersion(HttpVersion.HTTP_1_1);
gen.setRequest("POST","/index.html");
fields.add("Host","something"); fields.add("Host","something");
fields.add("User-Agent","test"); fields.add("User-Agent","test");
hg.setVersion(HttpVersion.HTTP_1_1); HttpGenerator.Result
hg.completeHeader(header,fields,true);
hg.complete();
result=gen.prepareContent(null,null,content);
assertEquals(HttpGenerator.Result.NEED_BUFFER,result);
result=gen.prepareContent(null,buffer,content);
assertEquals(HttpGenerator.Result.OK,result);
assertEquals("Hello World",BufferUtil.toString(buffer));
assertTrue(BufferUtil.isEmpty(content));
result=gen.complete(null,buffer);
assertEquals(HttpGenerator.Result.NEED_COMMIT,result);
result=gen.commit(fields,header,buffer,content,true);
assertEquals(HttpGenerator.Result.FLUSH,result);
String out = BufferUtil.toString(header); String out = BufferUtil.toString(header);
BufferUtil.clear(header);
BufferUtil.clear(buffer);
result=gen.complete(null,buffer);
assertEquals(HttpGenerator.Result.OK,result);
result=gen.commit(fields,header,null,null,true);
assertEquals(HttpGenerator.Result.NEED_COMPLETE,result);
result=gen.complete(null,null);
assertEquals(HttpGenerator.Result.OK,result);
assertTrue(out.indexOf("GET /index.html HTTP/1.1")==0); assertTrue(out.indexOf("GET /index.html HTTP/1.1")==0);
assertTrue(out.indexOf("Content-Length")==-1); assertTrue(out.indexOf("Content-Length")==-1);
assertEquals(HttpGenerator.State.END,gen.getState());
assertEquals(0,gen.getContentWritten());
} }
@Test @Test
public void testHTTP() throws Exception public void testHTTP() throws Exception
{ {

View File

@ -291,7 +291,7 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
boolean progress=process(null,toFlush); boolean progress=process(null,toFlush);
// if we received any data, // if we received any data,
if (!BufferUtil.isEmpty(_unwrapBuf)) if (BufferUtil.hasContent(_unwrapBuf))
{ {
// transfer from temp buffer to fill buffer // transfer from temp buffer to fill buffer
BufferUtil.put(_unwrapBuf,toFill); BufferUtil.put(_unwrapBuf,toFill);
@ -302,7 +302,7 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
return progress; return progress;
} }
// Else if there is some temporary data // Else if there is some temporary data
else if (!BufferUtil.isEmpty(_unwrapBuf)) else if (BufferUtil.hasContent(_unwrapBuf))
{ {
// transfer from temp buffer to fill buffer // transfer from temp buffer to fill buffer
BufferUtil.put(_unwrapBuf,toFill); BufferUtil.put(_unwrapBuf,toFill);
@ -332,7 +332,7 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
_inbound.compact().flip(); _inbound.compact().flip();
// flush any output data // flush any output data
if (!BufferUtil.isEmpty(_outbound) && (flushed=_endp.flush(_outbound))>0) if (BufferUtil.hasContent(_outbound) && (flushed=_endp.flush(_outbound))>0)
{ {
progress = true; progress = true;
_outbound.compact().flip(); _outbound.compact().flip();
@ -358,11 +358,11 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
case NOT_HANDSHAKING: case NOT_HANDSHAKING:
{ {
// Try unwrapping some application data // Try unwrapping some application data
if (!BufferUtil.isAtCapacity(toFill) && !BufferUtil.isEmpty(_inbound) && unwrap(toFill)) if (!BufferUtil.isAtCapacity(toFill) && BufferUtil.hasContent(_inbound) && unwrap(toFill))
progress=true; progress=true;
// Try wrapping some application data // Try wrapping some application data
if (!BufferUtil.isEmpty(toFlush) && !BufferUtil.isAtCapacity(_outbound) && wrap(toFlush)) if (BufferUtil.hasContent(toFlush) && !BufferUtil.isAtCapacity(_outbound) && wrap(toFlush))
progress=true; progress=true;
} }
break; break;
@ -418,7 +418,7 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
} }
// If we are reading into the temp buffer and it has some content, then we should be dispatched. // If we are reading into the temp buffer and it has some content, then we should be dispatched.
if (toFill==_unwrapBuf && !BufferUtil.isEmpty(_unwrapBuf)) if (toFill==_unwrapBuf && BufferUtil.hasContent(_unwrapBuf))
_aEndp.asyncDispatch(); _aEndp.asyncDispatch();
} }
finally finally
@ -592,8 +592,8 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
synchronized (SslConnection.this) synchronized (SslConnection.this)
{ {
return _endp.isInputShutdown() && return _endp.isInputShutdown() &&
!(_unwrapBuf!=null&&!BufferUtil.isEmpty(_unwrapBuf)) && !(_unwrapBuf!=null&&BufferUtil.hasContent(_unwrapBuf)) &&
!(_inbound!=null&&!BufferUtil.isEmpty(_inbound)); !(_inbound!=null&&BufferUtil.hasContent(_inbound));
} }
} }
@ -624,9 +624,9 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
public int flush(ByteBuffer header, ByteBuffer buffer) throws IOException public int flush(ByteBuffer header, ByteBuffer buffer) throws IOException
{ {
if (!BufferUtil.isEmpty(header)) if (BufferUtil.hasContent(header))
return flush(header); return flush(header);
if (!BufferUtil.isEmpty(buffer)) if (BufferUtil.hasContent(buffer))
return flush(buffer); return flush(buffer);
return 0; return 0;
} }

View File

@ -0,0 +1,169 @@
package org.eclipse.jetty.io.nio;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.BufferUtil;
import org.junit.Test;
public class BufferUtilTest
{
@Test
public void testPut() throws Exception
{
ByteBuffer to = BufferUtil.allocate(10);
ByteBuffer from=BufferUtil.toBuffer("12345");
BufferUtil.clear(to);
assertEquals(5,BufferUtil.put(from,to));
assertTrue(BufferUtil.isEmpty(from));
assertEquals("12345",BufferUtil.toString(to));
from=BufferUtil.toBuffer("XX67890ZZ");
from.position(2);
assertEquals(5,BufferUtil.put(from,to));
assertEquals(2,from.remaining());
assertEquals("1234567890",BufferUtil.toString(to));
}
@Test
public void testPutUnderMax() throws Exception
{
ByteBuffer to = BufferUtil.allocate(10);
ByteBuffer from=BufferUtil.toBuffer("12345");
BufferUtil.clear(to);
assertEquals(5,BufferUtil.put(from,to,10));
assertTrue(BufferUtil.isEmpty(from));
assertEquals("12345",BufferUtil.toString(to));
from=BufferUtil.toBuffer("XX67890ZZ");
from.position(2);
assertEquals(5,BufferUtil.put(from,to,10));
assertEquals(2,from.remaining());
assertEquals("1234567890",BufferUtil.toString(to));
}
@Test
public void testPutAtMax() throws Exception
{
ByteBuffer to = BufferUtil.allocate(10);
ByteBuffer from=BufferUtil.toBuffer("12345");
BufferUtil.clear(to);
assertEquals(5,BufferUtil.put(from,to,5));
assertTrue(BufferUtil.isEmpty(from));
assertEquals("12345",BufferUtil.toString(to));
from=BufferUtil.toBuffer("XX67890ZZ");
from.position(2);
assertEquals(5,BufferUtil.put(from,to,5));
assertEquals(2,from.remaining());
assertEquals("1234567890",BufferUtil.toString(to));
}
@Test
public void testPutOverMax() throws Exception
{
ByteBuffer to = BufferUtil.allocate(10);
ByteBuffer from=BufferUtil.toBuffer("12345");
BufferUtil.clear(to);
assertEquals(4,BufferUtil.put(from,to,4));
assertEquals(1,from.remaining());
assertEquals("1234",BufferUtil.toString(to));
from=BufferUtil.toBuffer("XX567890ZZ");
from.position(2);
assertEquals(4,BufferUtil.put(from,to,4));
assertEquals(4,from.remaining());
assertEquals("12345678",BufferUtil.toString(to));
}
@Test
public void testPutDirect() throws Exception
{
ByteBuffer to = BufferUtil.allocateDirect(10);
ByteBuffer from=BufferUtil.toBuffer("12345");
BufferUtil.clear(to);
assertEquals(5,BufferUtil.put(from,to));
assertTrue(BufferUtil.isEmpty(from));
assertEquals("12345",BufferUtil.toString(to));
from=BufferUtil.toBuffer("XX67890ZZ");
from.position(2);
assertEquals(5,BufferUtil.put(from,to));
assertEquals(2,from.remaining());
assertEquals("1234567890",BufferUtil.toString(to));
}
@Test
public void testPutUnderMaxDirect() throws Exception
{
ByteBuffer to = BufferUtil.allocateDirect(10);
ByteBuffer from=BufferUtil.toBuffer("12345");
BufferUtil.clear(to);
assertEquals(5,BufferUtil.put(from,to,10));
assertTrue(BufferUtil.isEmpty(from));
assertEquals("12345",BufferUtil.toString(to));
from=BufferUtil.toBuffer("XX67890ZZ");
from.position(2);
assertEquals(5,BufferUtil.put(from,to,10));
assertEquals(2,from.remaining());
assertEquals("1234567890",BufferUtil.toString(to));
}
@Test
public void testPutAtMaxDirect() throws Exception
{
ByteBuffer to = BufferUtil.allocateDirect(10);
ByteBuffer from=BufferUtil.toBuffer("12345");
BufferUtil.clear(to);
assertEquals(5,BufferUtil.put(from,to,5));
assertTrue(BufferUtil.isEmpty(from));
assertEquals("12345",BufferUtil.toString(to));
from=BufferUtil.toBuffer("XX67890ZZ");
from.position(2);
assertEquals(5,BufferUtil.put(from,to,5));
assertEquals(2,from.remaining());
assertEquals("1234567890",BufferUtil.toString(to));
}
@Test
public void testPutOverMaxDirect() throws Exception
{
ByteBuffer to = BufferUtil.allocateDirect(10);
ByteBuffer from=BufferUtil.toBuffer("12345");
BufferUtil.clear(to);
assertEquals(4,BufferUtil.put(from,to,4));
assertEquals(1,from.remaining());
assertEquals("1234",BufferUtil.toString(to));
from=BufferUtil.toBuffer("XX567890ZZ");
from.position(2);
assertEquals(4,BufferUtil.put(from,to,4));
assertEquals(4,from.remaining());
assertEquals("12345678",BufferUtil.toString(to));
}
}

View File

@ -138,15 +138,15 @@ public class SelectChannelEndPointTest
progress=true; progress=true;
} }
if (!BufferUtil.isEmpty(_in) && BufferUtil.put(_in,_out)>0) if (BufferUtil.hasContent(_in) && BufferUtil.put(_in,_out)>0)
progress=true; progress=true;
if (!BufferUtil.isEmpty(_out) && _endp.flush(_out)>0) if (BufferUtil.hasContent(_out) && _endp.flush(_out)>0)
progress=true; progress=true;
_out.compact().flip(); _out.compact().flip();
if (!!BufferUtil.isEmpty(_out) && _endp.isInputShutdown()) if (BufferUtil.isEmpty(_out) && _endp.isInputShutdown())
_endp.shutdownOutput(); _endp.shutdownOutput();
} }
return this; return this;

View File

@ -69,6 +69,23 @@ public class BufferUtil
return buf; return buf;
} }
/* ------------------------------------------------------------ */
public static void flipToFill(ByteBuffer buffer)
{
buffer.position(buffer.limit());
buffer.limit(buffer.capacity());
}
/* ------------------------------------------------------------ */
public static void flipToFlush(ByteBuffer buffer,int position)
{
buffer.limit(buffer.position());
buffer.position(position);
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public static byte[] toArray(ByteBuffer buffer) public static byte[] toArray(ByteBuffer buffer)
{ {
@ -89,17 +106,93 @@ public class BufferUtil
return buf==null || buf.remaining()==0; return buf==null || buf.remaining()==0;
} }
/* ------------------------------------------------------------ */
public static boolean hasContent(ByteBuffer buf)
{
return buf!=null && buf.remaining()>0;
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public static boolean isAtCapacity(ByteBuffer buf) public static boolean isAtCapacity(ByteBuffer buf)
{ {
return buf!=null && buf.limit()==buf.capacity(); return buf!=null && buf.limit()==buf.capacity();
} }
/* ------------------------------------------------------------ */
public static long remaining(ByteBuffer buffer)
{
return buffer==null?0:buffer.remaining();
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Put data from one buffer into another, avoiding over/under flows * Put data from one buffer into another, avoiding over/under flows
* @param from * @param from Buffer to take bytes from
* @param to * @param to Buffer to put bytes to
* @return number of bytes moved
*/
public static int put(ByteBuffer from, ByteBuffer to, long maxBytes)
{
return put(from,to,maxBytes>=Integer.MAX_VALUE?Integer.MAX_VALUE:(int)maxBytes);
}
/* ------------------------------------------------------------ */
/**
* Put data from one buffer into another, avoiding over/under flows
* @param from Buffer to take bytes from
* @param to Buffer to put bytes to
* @return number of bytes moved
*/
public static int put(ByteBuffer from, ByteBuffer to, int maxBytes)
{
int put;
int pos=to.position();
try
{
flipToFill(to);
maxBytes=Math.min(maxBytes,to.remaining());
int remaining=from.remaining();
if (remaining>0)
{
if (remaining<=maxBytes)
{
to.put(from);
put=remaining;
}
else if (from.hasArray())
{
put=maxBytes;
to.put(from.array(),from.arrayOffset()+from.position(),put);
from.position(from.position()+put);
}
else
{
put=maxBytes;
ByteBuffer slice=from.slice();
slice.limit(put);
to.put(slice);
from.position(from.position()+put);
}
}
else
put=0;
}
finally
{
flipToFlush(to,pos);
}
return put;
}
/* ------------------------------------------------------------ */
/**
* Put data from one buffer into another, avoiding over/under flows
* @param from Buffer to take bytes from
* @param to Buffer to put bytes to
* @return number of bytes moved
*/ */
public static int put(ByteBuffer from, ByteBuffer to) public static int put(ByteBuffer from, ByteBuffer to)
{ {
@ -107,8 +200,7 @@ public class BufferUtil
int pos=to.position(); int pos=to.position();
try try
{ {
to.position(to.limit()); flipToFill(to);
to.limit(to.capacity());
int remaining=from.remaining(); int remaining=from.remaining();
if (remaining>0) if (remaining>0)
@ -139,8 +231,7 @@ public class BufferUtil
} }
finally finally
{ {
to.limit(to.position()); flipToFlush(to,pos);
to.position(pos);
} }
return put; return put;
@ -558,4 +649,6 @@ public class BufferUtil
} }
} }