From 8c25941e04c04877ec95a2fa9a30583ce3d5e24f Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 8 Mar 2012 14:13:40 +1100 Subject: [PATCH] jetty-9 jetty-http passing unit tests --- .../org/eclipse/jetty/http/HttpGenerator.java | 484 ++++++++-------- .../org/eclipse/jetty/http/HttpParser.java | 4 +- .../jetty/http/HttpGeneratorClientTest.java | 150 +++-- .../eclipse/jetty/http/HttpGeneratorTest.java | 530 +++++++----------- .../org/eclipse/jetty/util/BufferUtil.java | 47 +- 5 files changed, 567 insertions(+), 648 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index 64c1b77c08b..158707359f2 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -20,6 +20,7 @@ import java.nio.ByteBuffer; import javax.swing.text.View; +import org.eclipse.jetty.http.HttpGenerator.Action; import org.eclipse.jetty.io.Buffers; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; @@ -81,9 +82,10 @@ public class HttpGenerator private static final Logger LOG = Log.getLogger(HttpGenerator.class); // states - - enum State { START, COMPLETING_UNCOMMITTED, COMMITTING, COMMITTING_COMPLETING, COMMITTED, COMPLETING, END }; - enum Result { NEED_COMMIT,NEED_CHUNK,NEED_BUFFER,FLUSH,FLUSH_CONTENT,NEED_COMPLETE,OK,SHUTDOWN_OUT}; + + enum Action { FLUSH, COMPLETE, PREPARE }; + enum State { START, COMMITTING, COMMITTING_COMPLETING, COMMITTED, COMPLETING, END }; + enum Result { NEED_CHUNK,NEED_HEADER,NEED_BUFFER,FLUSH,FLUSH_CONTENT,OK,SHUTDOWN_OUT}; public static final byte[] NO_BYTES = {}; @@ -92,6 +94,8 @@ public class HttpGenerator private State _state = State.START; private int _status = 0; + + private final HttpFields _fields; private HttpVersion _version = HttpVersion.HTTP_1_1; private byte[] _reason; private byte[] _method; @@ -132,7 +136,13 @@ public class HttpGenerator // data private boolean _needCRLF = false; - + + /* ------------------------------------------------------------------------------- */ + public HttpGenerator(HttpFields fields) + { + _fields=fields; + } + /* ------------------------------------------------------------------------------- */ public void reset() { @@ -152,6 +162,7 @@ public class HttpGenerator _needCRLF = false; _uri=null; _noContent=false; + _fields.clear(); } /* ------------------------------------------------------------ */ @@ -193,7 +204,7 @@ public class HttpGenerator /* ------------------------------------------------------------ */ public boolean isCommitted() { - return _state != State.START; + return _state.ordinal() >= State.COMMITTED.ordinal(); } /* ------------------------------------------------------------ */ @@ -367,25 +378,115 @@ public class HttpGenerator return _method==null; } + /* ------------------------------------------------------------ */ - public Result commit(HttpFields fields,ByteBuffer header,ByteBuffer buffer, ByteBuffer content, boolean last) throws IOException + public Result generate(ByteBuffer header, ByteBuffer chunk, ByteBuffer buffer, ByteBuffer content, Action action) { + Result result = Result.OK; + if (_state==State.END) + return result; + if (action==null) + action=Action.PREPARE; + + // Do we have content to handle + if (BufferUtil.hasContent(content)) + { + // Do we have too much content? + if (_contentLength>0 && content.remaining()>(_contentLength-_contentPrepared)) + { + LOG.warn("Content truncated at {}",new Throwable()); + content.limit(content.position()+(int)(_contentLength-_contentPrepared)); + } - if (isResponse() && _status==0) - throw new EofException(); // TODO ??? + // Can we do a direct flush + if (BufferUtil.isEmpty(buffer) && content.remaining()>_largeContent) + { + if (isCommitted()) + { + if (isChunking()) + { + if (chunk==null) + return Result.NEED_CHUNK; + BufferUtil.clearToFill(chunk); + prepareChunk(chunk,content.remaining()); + BufferUtil.flipToFlush(chunk,0); + } + _contentPrepared+=content.remaining(); + return Result.FLUSH_CONTENT; + } - int pos=header.position(); + _state=action==Action.COMPLETE?State.COMMITTING_COMPLETING:State.COMMITTING; + result=Result.FLUSH_CONTENT; + } + else + { + // we copy content to buffer + // if we don't have one, we need one + if (buffer==null) + return Result.NEED_BUFFER; + + // Copy the content + _contentPrepared+=BufferUtil.put(content,buffer); + + // are we full? + if (BufferUtil.isAtCapacity(buffer)) + { + if (isCommitted()) + { + if (isChunking()) + { + if (chunk==null) + return Result.NEED_CHUNK; + BufferUtil.clearToFill(chunk); + prepareChunk(chunk,buffer.remaining()); + BufferUtil.flipToFlush(chunk,0); + } + return Result.FLUSH; + } + _state=action==Action.COMPLETE?State.COMMITTING_COMPLETING:State.COMMITTING; + result=Result.FLUSH; + } + } + } + + // Handle the actions + if (result==Result.OK) + { + switch(action) + { + case COMPLETE: + if (!isCommitted()) + _state=State.COMMITTING_COMPLETING; + else if (_state==State.COMMITTED) + _state=State.COMPLETING; + result=BufferUtil.hasContent(buffer)?Result.FLUSH:Result.OK; + break; + case FLUSH: + if (!isCommitted()) + _state=State.COMMITTING; + result=BufferUtil.hasContent(buffer)?Result.FLUSH:Result.OK; + break; + } + } + + // flip header if we have one + final int pos=header==null?-1:BufferUtil.flipToFill(header); try { - BufferUtil.flipToFill(header); - - switch(_state) + // handle by state + switch (_state) { case START: - case COMPLETING_UNCOMMITTED: - + return Result.OK; + + case COMMITTING: + case COMMITTING_COMPLETING: + { if (isRequest()) { + if (header==null || header.capacity()<=CHUNK_SIZE) + return Result.NEED_HEADER; + if(_version==HttpVersion.HTTP_0_9) { _noContent=true; @@ -399,14 +500,22 @@ public class HttpGenerator else { // Responses + + // Do we need a response header? if (_version == HttpVersion.HTTP_0_9) { _persistent = false; _contentLength = HttpTokens.EOF_CONTENT; _state = State.COMMITTED; - return prepareContent(null,buffer,content); + if (result==Result.FLUSH_CONTENT) + _contentPrepared+=content.remaining(); + return result; } + // yes we need a response header + if (header==null || header.capacity()<=CHUNK_SIZE) + return Result.NEED_HEADER; + // Are we persistent by default? if (_persistent==null) _persistent=(_version.ordinal() > HttpVersion.HTTP_1_0.ordinal()); @@ -430,69 +539,115 @@ public class HttpGenerator _noContent=true; } } - - generateHeaders(fields,header,content,last); - _state = _state==State.COMPLETING_UNCOMMITTED?State.COMMITTING_COMPLETING:State.COMMITTING; - - // fall through to COMMITTING states - - case COMMITTING: - case COMMITTING_COMPLETING: + boolean completing=action==Action.COMPLETE||_state==State.COMMITTING_COMPLETING; + generateHeaders(header,content,completing); + _state = completing?State.COMPLETING:State.COMMITTED; - // Handle any content - if (BufferUtil.hasContent(content)) + // handle result + switch(result) { - // Do we have too much content? - if (_contentLength>0 && content.remaining()>(_contentLength-_contentPrepared)) - { - LOG.warn("Content truncated at {}",new Throwable()); - content.limit(content.position()+(int)(_contentLength-_contentPrepared)); - } - - // Can we do a direct flush - if (BufferUtil.isEmpty(buffer) && content.remaining()>_largeContent) - { - _contentPrepared+=content.remaining(); + case FLUSH: + if (isChunking()) + prepareChunk(header,buffer.remaining()); + break; + case FLUSH_CONTENT: if (isChunking()) prepareChunk(header,content.remaining()); - return Result.FLUSH_CONTENT; - } - - // we copy content to buffer - // if we don't have one, we need one - if (buffer==null) - return Result.NEED_BUFFER; - - _contentPrepared+=BufferUtil.put(content,buffer); - - if (isChunking()) - prepareChunk(header,buffer.remaining()); - - return Result.FLUSH; + _contentPrepared+=content.remaining(); + break; + case OK: + if (BufferUtil.hasContent(buffer)) + { + if (isChunking()) + prepareChunk(header,buffer.remaining()); + } + result=Result.FLUSH; } - _state = _state==State.COMMITTING?State.COMMITTED:State.COMPLETING; - - break; - - default: - throw new IllegalStateException(this.toString()); - - } - } - catch(BufferOverflowException e) - { - throw new RuntimeException("Header>"+header.capacity(),e); + return result; + } + + + case COMMITTED: + return Result.OK; + + + case COMPLETING: + // handle content with commit + + if (isChunking()) + { + if (chunk==null) + return Result.NEED_CHUNK; + BufferUtil.clearToFill(chunk); + + switch(result) + { + case FLUSH: + prepareChunk(chunk,buffer.remaining()); + break; + case FLUSH_CONTENT: + prepareChunk(chunk,content.remaining()); + case OK: + if (BufferUtil.hasContent(buffer)) + { + result=Result.FLUSH; + prepareChunk(chunk,buffer.remaining()); + } + else + { + result=Result.FLUSH; + _state=State.END; + prepareChunk(chunk,0); + } + } + BufferUtil.flipToFlush(chunk,0); + } + else if (result==Result.OK) + { + if (BufferUtil.hasContent(buffer)) + result=Result.FLUSH; + else + _state=State.END; + } + + return result; + + + default: + throw new IllegalStateException(); + } } finally { - BufferUtil.flipToFlush(header,pos); + if (pos>=0) + BufferUtil.flipToFlush(header,pos); } - - return _state==State.COMPLETING?Result.NEED_COMPLETE:Result.OK; } + /* ------------------------------------------------------------ */ + private void prepareChunk(ByteBuffer chunk, int remaining) + { + // if we need CRLF add this to header + if (_needCRLF) + BufferUtil.putCRLF(chunk); + + // Add the chunk size to the header + if (remaining>0) + { + BufferUtil.putHexInt(chunk, remaining); + BufferUtil.putCRLF(chunk); + _needCRLF=true; + } + else + { + chunk.put(LAST_CHUNK); + _needCRLF=false; + } + } + + /* ------------------------------------------------------------ */ private void generateRequestLine(ByteBuffer header) { @@ -545,7 +700,7 @@ public class HttpGenerator } /* ------------------------------------------------------------ */ - private void generateHeaders(HttpFields fields,ByteBuffer header,ByteBuffer content,boolean last) + private void generateHeaders(ByteBuffer header,ByteBuffer content,boolean last) { // Add Date header @@ -566,9 +721,9 @@ public class HttpGenerator StringBuilder connection = null; // Generate fields - if (fields != null) + if (_fields != null) { - for (HttpFields.Field field : fields) + for (HttpFields.Field field : _fields) { HttpHeader name = HttpHeader.CACHE.get(field.getName()); @@ -579,8 +734,14 @@ public class HttpGenerator long length = field.getLongValue(); if (length>=0) { - if (length < _contentPrepared || last && length != _contentPrepared) - LOG.warn("Incorrect ContentLength ignored ",new Throwable()); + long prepared=_contentPrepared+BufferUtil.remaining(content); + if (length < prepared || last && length != prepared) + { + LOG.warn("Incorrect ContentLength: "+length+"!="+prepared); + if (LOG.isDebugEnabled()) + LOG.debug(new Throwable()); + _contentLength=HttpTokens.UNKNOWN_CONTENT; + } else { // write the field to the header @@ -694,9 +855,14 @@ public class HttpGenerator } default: - header.put(name.toBytesColonSpace()); - field.putValueTo(header); - header.put(CRLF); + if (name==null) + field.putTo(header); + else + { + header.put(name.toBytesColonSpace()); + field.putValueTo(header); + header.put(CRLF); + } } } @@ -828,178 +994,6 @@ public class HttpGenerator } - /* ------------------------------------------------------------ */ - public Result prepareContent(ByteBuffer chunk, ByteBuffer buffer, ByteBuffer content) - { - // Do we have too much content? - if (_contentLength>0 && content.remaining()>(_contentLength-_contentPrepared)) - { - LOG.warn("Content truncated at {}",new Throwable()); - content.limit(content.position()+(int)(_contentLength-_contentPrepared)); - } - - switch (_state) - { - case START: - // Can we do a direct flush - if (BufferUtil.isEmpty(buffer) && content.remaining()>_largeContent) - return Result.NEED_COMMIT; - - // we copy content to buffer - // if we don't have one, we need one - if (buffer==null) - return Result.NEED_BUFFER; - - // copy content to buffer - _contentPrepared+=BufferUtil.put(content,buffer); - - // are we full? - if (BufferUtil.isAtCapacity(buffer)) - return Result.NEED_COMMIT; - - return Result.OK; - - case COMPLETING: - return Result.NEED_COMPLETE; - - case COMMITTED: - - // Can we do a direct flush - if (BufferUtil.isEmpty(buffer) && content.remaining()>_largeContent) - { - if (isChunking()) - { - if (chunk==null) - return Result.NEED_CHUNK; - BufferUtil.clearToFill(chunk); - prepareChunk(chunk,content.remaining()); - BufferUtil.flipToFlush(chunk,0); - } - _contentPrepared+=content.remaining(); - return Result.FLUSH_CONTENT; - } - - // we copy content to buffer - // if we don't have one, we need one - if (buffer==null) - return Result.NEED_BUFFER; - - // Copy the content - _contentPrepared+=BufferUtil.put(content,buffer); - - // are we full? - if (BufferUtil.isAtCapacity(buffer)) - { - if (isChunking()) - { - if (chunk==null) - return Result.NEED_CHUNK; - BufferUtil.clearToFill(chunk); - prepareChunk(chunk,buffer.remaining()); - BufferUtil.flipToFlush(chunk,0); - } - return Result.FLUSH; - } - return Result.OK; - - default: - throw new IllegalStateException(); - } - } - - /* ------------------------------------------------------------ */ - private void prepareChunk(ByteBuffer chunk, int remaining) - { - // if we need CRLF add this to header - if (_needCRLF) - BufferUtil.putCRLF(chunk); - - // Add the chunk size to the header - if (remaining>0) - { - BufferUtil.putHexInt(chunk, remaining); - BufferUtil.putCRLF(chunk); - _needCRLF=true; - } - else - { - chunk.put(LAST_CHUNK); - _needCRLF=false; - } - } - - /* ------------------------------------------------------------ */ - /** - * @throws IOException - */ - public Result flush(ByteBuffer chunk, ByteBuffer buffer) throws IOException - { - switch(_state) - { - case START: - return Result.NEED_COMMIT; - case COMMITTED: - if (isChunking()) - { - if (chunk==null) - return Result.NEED_CHUNK; - - if (BufferUtil.hasContent(buffer)) - { - BufferUtil.clearToFill(chunk); - prepareChunk(chunk,buffer.remaining()); - BufferUtil.flipToFlush(chunk,0); - } - } - } - return Result.FLUSH; - } - - /* ------------------------------------------------------------ */ - /** - * Complete the message. - * - * @throws IOException - */ - public Result complete(ByteBuffer chunk, ByteBuffer buffer) throws IOException - { - if (_state == State.END) - return Result.OK; - - switch(_state) - { - case START: - case COMPLETING_UNCOMMITTED: - _state=State.COMPLETING_UNCOMMITTED; - return Result.NEED_COMMIT; - - case COMPLETING: - case COMMITTED: - _state=State.COMPLETING; - if (isChunking()) - { - if (BufferUtil.hasContent(buffer)) - { - if (chunk==null) - return Result.NEED_CHUNK; - BufferUtil.clearToFill(chunk); - prepareChunk(chunk,buffer.remaining()); - BufferUtil.flipToFlush(chunk,0); - return Result.FLUSH; - } - _state=State.END; - BufferUtil.clearToFill(chunk); - prepareChunk(chunk,0); - BufferUtil.flipToFlush(chunk,0); - return Result.FLUSH; - } - else if (BufferUtil.hasContent(buffer)) - return Result.FLUSH; - - } - _state=State.END; - return Result.OK; - } /* ------------------------------------------------------------------------------- */ public static byte[] getReasonBuffer(int code) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 0aba5d34042..75ac4a981f2 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -449,7 +449,7 @@ public class HttpParser break; case CONNECTION: - switch(_value) + switch(_value==null?HttpHeaderValue.UNKNOWN:_value) { case CLOSE: _persistent=false; @@ -662,7 +662,7 @@ public class HttpParser else if (HttpHeaderValue.hasKnownValues(_header)) { _value=HttpHeaderValue.CACHE.get(buffer,start,length); - _field1=_value.toString(); + _field1=_value!=null?_value.toString():BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET); } else { diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java index 9e90573f3e1..50ed1a24cf4 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java @@ -24,6 +24,7 @@ import java.nio.ByteBuffer; import javax.swing.text.View; +import org.eclipse.jetty.http.HttpGenerator.Action; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.io.SimpleBuffers; import org.eclipse.jetty.util.BufferUtil; @@ -41,9 +42,9 @@ public class HttpGeneratorClientTest @Test public void testRequestNoContent() throws Exception { - ByteBuffer header=BufferUtil.allocate(8096); + ByteBuffer header=BufferUtil.allocate(2048); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); fields.add("Host","something"); fields.add("User-Agent","test"); @@ -51,23 +52,24 @@ public class HttpGeneratorClientTest gen.setRequest(HttpMethod.GET,"/index.html",HttpVersion.HTTP_1_1); HttpGenerator.Result - result=gen.complete(null,null); - assertEquals(HttpGenerator.State.COMPLETING_UNCOMMITTED,gen.getState()); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); + result=gen.generate(null,null,null,null,Action.COMPLETE); + assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState()); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); - result=gen.commit(fields,header,null,null,true); - assertEquals(HttpGenerator.Result.NEED_COMPLETE,result); - String out = BufferUtil.toString(header); + result=gen.generate(header,null,null,null,null); + assertEquals(HttpGenerator.Result.FLUSH,result); + String head = BufferUtil.toString(header); BufferUtil.clear(header); - assertThat(out,containsString("GET /index.html HTTP/1.1")); - assertThat(out,not(containsString("Content-Length"))); - result=gen.complete(null,null); + result=gen.generate(null,null,null,null,null); assertEquals(HttpGenerator.Result.OK,result); - - assertEquals(HttpGenerator.State.END,gen.getState()); - assertEquals(0,gen.getContentWritten()); } + + assertEquals(0,gen.getContentWritten()); + assertThat(head,containsString("GET /index.html HTTP/1.1")); + assertThat(head,not(containsString("Content-Length"))); + + } @Test public void testRequestWithSmallContent() throws Exception @@ -77,7 +79,7 @@ public class HttpGeneratorClientTest ByteBuffer content=BufferUtil.toBuffer("Hello World"); ByteBuffer content1=BufferUtil.toBuffer(". The quick brown fox jumped over the lazy dog."); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setVersion(HttpVersion.HTTP_1_1); gen.setRequest("POST","/index.html"); @@ -86,35 +88,36 @@ public class HttpGeneratorClientTest HttpGenerator.Result - result=gen.prepareContent(null,null,content); + result=gen.generate(null,null,null,content,null); assertEquals(HttpGenerator.Result.NEED_BUFFER,result); assertEquals(HttpGenerator.State.START,gen.getState()); - result=gen.prepareContent(null,buffer,content); + result=gen.generate(null,null,buffer,content,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.START,gen.getState()); assertEquals("Hello World",BufferUtil.toString(buffer)); assertTrue(BufferUtil.isEmpty(content)); - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.START,gen.getState()); assertEquals("Hello World. The quick brown fox jumped over the lazy dog.",BufferUtil.toString(buffer)); - assertTrue(BufferUtil.isEmpty(content)); + assertTrue(BufferUtil.isEmpty(content1)); - result=gen.complete(null,buffer); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.COMPLETING_UNCOMMITTED,gen.getState()); + result=gen.generate(null,null,buffer,null,Action.COMPLETE); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState()); - result=gen.commit(fields,header,buffer,content,true); + result=gen.generate(header,null,buffer,null,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMPLETING,gen.getState()); + String head = BufferUtil.toString(header); BufferUtil.clear(header); String body = BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.complete(null,buffer); + result=gen.generate(null,null,buffer,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); @@ -136,7 +139,7 @@ public class HttpGeneratorClientTest ByteBuffer content0=BufferUtil.toBuffer("Hello World! "); ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setVersion(HttpVersion.HTTP_1_1); gen.setRequest("POST","/index.html"); @@ -145,25 +148,25 @@ public class HttpGeneratorClientTest HttpGenerator.Result - result=gen.prepareContent(null,null,content0); + result=gen.generate(null,null,null,content0,null); assertEquals(HttpGenerator.Result.NEED_BUFFER,result); assertEquals(HttpGenerator.State.START,gen.getState()); - result=gen.prepareContent(null,buffer,content0); + result=gen.generate(null,null,buffer,content0,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.START,gen.getState()); assertEquals("Hello World! ",BufferUtil.toString(buffer)); assertEquals(0,content0.remaining()); - result=gen.prepareContent(null,buffer,content1); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.START,gen.getState()); + result=gen.generate(null,null,buffer,content1,null); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING,gen.getState()); assertEquals("Hello World! The",BufferUtil.toString(buffer)); assertEquals(43,content1.remaining()); - result=gen.commit(fields,header,buffer,content1,false); + result=gen.generate(header,null,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); - assertEquals(HttpGenerator.State.COMMITTING,gen.getState()); + assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("Hello World! The",BufferUtil.toString(buffer)); assertEquals(43,content1.remaining()); assertTrue(gen.isChunking()); @@ -173,16 +176,12 @@ public class HttpGeneratorClientTest String body = BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.commit(fields,header,buffer,content1,false); - assertEquals(HttpGenerator.Result.OK,result); - assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); - - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.NEED_CHUNK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); - result=gen.prepareContent(chunk,buffer,content1); + result=gen.generate(null,chunk,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("\r\n10\r\n",BufferUtil.toString(chunk)); @@ -192,7 +191,7 @@ public class HttpGeneratorClientTest BufferUtil.clear(chunk); BufferUtil.clear(buffer); - result=gen.prepareContent(chunk,buffer,content1); + result=gen.generate(null,chunk,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("\r\n10\r\n",BufferUtil.toString(chunk)); @@ -202,14 +201,14 @@ public class HttpGeneratorClientTest BufferUtil.clear(chunk); BufferUtil.clear(buffer); - result=gen.prepareContent(chunk,buffer,content1); + result=gen.generate(null,chunk,buffer,content1,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("",BufferUtil.toString(chunk)); assertEquals(" lazy dog. ",BufferUtil.toString(buffer)); assertEquals(0,content1.remaining()); - result=gen.complete(chunk,buffer); + result=gen.generate(null,chunk,buffer,null,Action.COMPLETE); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMPLETING,gen.getState()); assertEquals("\r\nB\r\n",BufferUtil.toString(chunk)); @@ -218,16 +217,15 @@ public class HttpGeneratorClientTest BufferUtil.clear(chunk); BufferUtil.clear(buffer); - result=gen.complete(chunk,buffer); + result=gen.generate(null,chunk,buffer,null,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.END,gen.getState()); assertEquals("\r\n0\r\n\r\n",BufferUtil.toString(chunk)); assertEquals(0,buffer.remaining()); body += BufferUtil.toString(chunk); BufferUtil.clear(chunk); - BufferUtil.clear(buffer); - result=gen.complete(chunk,buffer); + result=gen.generate(null,chunk,buffer,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); @@ -249,7 +247,7 @@ public class HttpGeneratorClientTest ByteBuffer content0=BufferUtil.toBuffer("Hello Cruel World! "); ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setLargeContent(8); gen.setVersion(HttpVersion.HTTP_1_1); @@ -259,11 +257,11 @@ public class HttpGeneratorClientTest HttpGenerator.Result - result=gen.prepareContent(null,null,content0); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.START,gen.getState()); + result=gen.generate(null,null,null,content0,null); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING,gen.getState()); - result=gen.commit(fields,header,null,content0,false); + result=gen.generate(header,null,null,content0,null); assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertTrue(gen.isChunking()); @@ -273,16 +271,16 @@ public class HttpGeneratorClientTest String body = BufferUtil.toString(content0); BufferUtil.clear(content0); - result=gen.commit(fields,header,null,content0,false); + result=gen.generate(header,null,null,content0,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); - result=gen.prepareContent(null,null,content1); + result=gen.generate(null,null,null,content1,null); assertEquals(HttpGenerator.Result.NEED_CHUNK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); - result=gen.prepareContent(chunk,null,content1); + result=gen.generate(null,chunk,null,content1,null); assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("\r\n2E\r\n",BufferUtil.toString(chunk)); @@ -290,13 +288,13 @@ public class HttpGeneratorClientTest body += BufferUtil.toString(chunk)+BufferUtil.toString(content1); BufferUtil.clear(content1); - result=gen.complete(chunk,null); + result=gen.generate(null,chunk,null,null,Action.COMPLETE); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.END,gen.getState()); assertEquals("\r\n0\r\n\r\n",BufferUtil.toString(chunk)); body += BufferUtil.toString(chunk); - result=gen.complete(chunk,null); + result=gen.generate(null,chunk,null,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); @@ -320,7 +318,7 @@ public class HttpGeneratorClientTest ByteBuffer content0=BufferUtil.toBuffer("Hello World! "); ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setVersion(HttpVersion.HTTP_1_1); gen.setRequest("POST","/index.html"); @@ -331,23 +329,23 @@ public class HttpGeneratorClientTest HttpGenerator.Result - result=gen.prepareContent(null,null,content0); + result=gen.generate(null,null,null,content0,null); assertEquals(HttpGenerator.Result.NEED_BUFFER,result); assertEquals(HttpGenerator.State.START,gen.getState()); - result=gen.prepareContent(null,buffer,content0); + result=gen.generate(null,null,buffer,content0,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.START,gen.getState()); assertEquals("Hello World! ",BufferUtil.toString(buffer)); assertEquals(0,content0.remaining()); - result=gen.prepareContent(null,buffer,content1); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.START,gen.getState()); + result=gen.generate(null,null,buffer,content1,null); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING,gen.getState()); assertEquals("Hello World! The",BufferUtil.toString(buffer)); assertEquals(43,content1.remaining()); - result=gen.commit(fields,header,buffer,content1,false); + result=gen.generate(header,null,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("Hello World! The",BufferUtil.toString(buffer)); @@ -359,7 +357,7 @@ public class HttpGeneratorClientTest String body = BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals(" quick brown fox",BufferUtil.toString(buffer)); @@ -367,7 +365,7 @@ public class HttpGeneratorClientTest body += BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals(" jumped over the",BufferUtil.toString(buffer)); @@ -375,20 +373,20 @@ public class HttpGeneratorClientTest body += BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals(" lazy dog. ",BufferUtil.toString(buffer)); assertEquals(0,content1.remaining()); - result=gen.complete(null,buffer); + result=gen.generate(null,null,buffer,null,Action.COMPLETE); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMPLETING,gen.getState()); assertEquals(" lazy dog. ",BufferUtil.toString(buffer)); body += BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.complete(null,buffer); + result=gen.generate(null,null,buffer,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); assertEquals(0,buffer.remaining()); @@ -411,7 +409,7 @@ public class HttpGeneratorClientTest ByteBuffer content0=BufferUtil.toBuffer("Hello World! "); ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setLargeContent(8); gen.setVersion(HttpVersion.HTTP_1_1); @@ -423,11 +421,11 @@ public class HttpGeneratorClientTest HttpGenerator.Result - result=gen.prepareContent(null,null,content0); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.START,gen.getState()); + result=gen.generate(null,null,null,content0,null); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING,gen.getState()); - result=gen.commit(fields,header,null,content0,false); + result=gen.generate(header,null,null,content0,null); assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertTrue(!gen.isChunking()); @@ -437,21 +435,17 @@ public class HttpGeneratorClientTest String body = BufferUtil.toString(content0); BufferUtil.clear(content0); - result=gen.commit(fields,header,null,null,false); + result=gen.generate(header,null,null,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); - result=gen.prepareContent(null,null,content1); + result=gen.generate(null,null,null,content1,null); assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); body += BufferUtil.toString(content1); BufferUtil.clear(content1); - result=gen.complete(null,null); - assertEquals(HttpGenerator.Result.OK,result); - assertEquals(HttpGenerator.State.END,gen.getState()); - - result=gen.complete(null,null); + result=gen.generate(null,null,null,null,Action.COMPLETE); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorTest.java index 2d2c8ae9883..c020fc3631e 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorTest.java @@ -13,22 +13,29 @@ package org.eclipse.jetty.http; +import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.matchers.JUnitMatchers.containsString; +import static org.junit.matchers.JUnitMatchers.either; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import javax.swing.text.View; +import org.eclipse.jetty.http.HttpGenerator.Action; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.io.SimpleBuffers; import org.eclipse.jetty.util.BufferUtil; +import org.hamcrest.CoreMatchers; import org.junit.Test; +import org.junit.matchers.JUnitMatchers; /** * @@ -48,32 +55,31 @@ public class HttpGeneratorTest { ByteBuffer header=BufferUtil.allocate(8096); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); - fields.add("Host","something"); - fields.add("User-Agent","test"); - - gen.setRequest(HttpMethod.GET,"/index.html",HttpVersion.HTTP_1_1); + gen.setVersion(HttpVersion.HTTP_1_1); + gen.setResponse(200,null); + fields.add("Last-Modified",HttpFields.__01Jan1970); HttpGenerator.Result - result=gen.complete(null,null); - assertEquals(HttpGenerator.State.COMPLETING_UNCOMMITTED,gen.getState()); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); + result=gen.generate(null,null,null,null,Action.COMPLETE); + assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState()); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); - result=gen.commit(fields,header,null,null,true); - assertEquals(HttpGenerator.Result.NEED_COMPLETE,result); + result=gen.generate(header,null,null,null,null); + assertEquals(HttpGenerator.Result.FLUSH,result); String head = BufferUtil.toString(header); BufferUtil.clear(header); + + result=gen.generate(null,null,null,null,null); + assertEquals(HttpGenerator.Result.OK,result); + assertEquals(HttpGenerator.State.END,gen.getState()); + + assertEquals(0,gen.getContentWritten()); assertThat(head,containsString("HTTP/1.1 200 OK")); assertThat(head,containsString("Last-Modified: Thu, 01 Jan 1970 00?00?00 GMT")); - assertThat(head,not(containsString("Content-Length"))); + assertThat(head,containsString("Content-Length: 0")); - result=gen.complete(null,null); - assertEquals(HttpGenerator.Result.OK,result); - - - assertEquals(HttpGenerator.State.END,gen.getState()); - assertEquals(0,gen.getContentWritten()); } @Test @@ -84,7 +90,7 @@ public class HttpGeneratorTest ByteBuffer content=BufferUtil.toBuffer("Hello World"); ByteBuffer content1=BufferUtil.toBuffer(". The quick brown fox jumped over the lazy dog."); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setVersion(HttpVersion.HTTP_1_1); gen.setResponse(200,null); @@ -92,35 +98,36 @@ public class HttpGeneratorTest HttpGenerator.Result - result=gen.prepareContent(null,null,content); + result=gen.generate(null,null,null,content,null); assertEquals(HttpGenerator.Result.NEED_BUFFER,result); assertEquals(HttpGenerator.State.START,gen.getState()); - result=gen.prepareContent(null,buffer,content); + result=gen.generate(null,null,buffer,content,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.START,gen.getState()); assertEquals("Hello World",BufferUtil.toString(buffer)); assertTrue(BufferUtil.isEmpty(content)); - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.START,gen.getState()); assertEquals("Hello World. The quick brown fox jumped over the lazy dog.",BufferUtil.toString(buffer)); - assertTrue(BufferUtil.isEmpty(content)); + assertTrue(BufferUtil.isEmpty(content1)); - result=gen.complete(null,buffer); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.COMPLETING_UNCOMMITTED,gen.getState()); + result=gen.generate(null,null,buffer,null,Action.COMPLETE); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState()); - result=gen.commit(fields,header,buffer,content,true); + result=gen.generate(header,null,buffer,null,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMPLETING,gen.getState()); + String head = BufferUtil.toString(header); BufferUtil.clear(header); String body = BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.complete(null,buffer); + result=gen.generate(null,null,buffer,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); @@ -142,7 +149,7 @@ public class HttpGeneratorTest ByteBuffer content0=BufferUtil.toBuffer("Hello World! "); ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setVersion(HttpVersion.HTTP_1_1); gen.setResponse(200,null); @@ -150,23 +157,23 @@ public class HttpGeneratorTest HttpGenerator.Result - result=gen.prepareContent(null,null,content0); + result=gen.generate(null,null,null,content0,null); assertEquals(HttpGenerator.Result.NEED_BUFFER,result); assertEquals(HttpGenerator.State.START,gen.getState()); - result=gen.prepareContent(null,buffer,content0); + result=gen.generate(null,null,buffer,content0,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.START,gen.getState()); assertEquals("Hello World! ",BufferUtil.toString(buffer)); assertEquals(0,content0.remaining()); - result=gen.prepareContent(null,buffer,content1); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.START,gen.getState()); + result=gen.generate(null,null,buffer,content1,null); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING,gen.getState()); assertEquals("Hello World! The",BufferUtil.toString(buffer)); assertEquals(43,content1.remaining()); - result=gen.commit(fields,header,buffer,content1,false); + result=gen.generate(header,null,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("Hello World! The",BufferUtil.toString(buffer)); @@ -178,12 +185,12 @@ public class HttpGeneratorTest String body = BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.NEED_CHUNK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); - result=gen.prepareContent(chunk,buffer,content1); + result=gen.generate(null,chunk,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("\r\n10\r\n",BufferUtil.toString(chunk)); @@ -193,7 +200,7 @@ public class HttpGeneratorTest BufferUtil.clear(chunk); BufferUtil.clear(buffer); - result=gen.prepareContent(chunk,buffer,content1); + result=gen.generate(null,chunk,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("\r\n10\r\n",BufferUtil.toString(chunk)); @@ -203,14 +210,14 @@ public class HttpGeneratorTest BufferUtil.clear(chunk); BufferUtil.clear(buffer); - result=gen.prepareContent(chunk,buffer,content1); + result=gen.generate(null,chunk,buffer,content1,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("",BufferUtil.toString(chunk)); assertEquals(" lazy dog. ",BufferUtil.toString(buffer)); assertEquals(0,content1.remaining()); - result=gen.complete(chunk,buffer); + result=gen.generate(null,chunk,buffer,null,Action.COMPLETE); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMPLETING,gen.getState()); assertEquals("\r\nB\r\n",BufferUtil.toString(chunk)); @@ -219,16 +226,15 @@ public class HttpGeneratorTest BufferUtil.clear(chunk); BufferUtil.clear(buffer); - result=gen.complete(chunk,buffer); + result=gen.generate(null,chunk,buffer,null,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.END,gen.getState()); assertEquals("\r\n0\r\n\r\n",BufferUtil.toString(chunk)); assertEquals(0,buffer.remaining()); body += BufferUtil.toString(chunk); BufferUtil.clear(chunk); - BufferUtil.clear(buffer); - result=gen.complete(chunk,buffer); + result=gen.generate(null,chunk,buffer,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); @@ -250,7 +256,7 @@ public class HttpGeneratorTest ByteBuffer content0=BufferUtil.toBuffer("Hello Cruel World! "); ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setLargeContent(8); gen.setVersion(HttpVersion.HTTP_1_1); @@ -259,11 +265,11 @@ public class HttpGeneratorTest HttpGenerator.Result - result=gen.prepareContent(null,null,content0); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.START,gen.getState()); + result=gen.generate(null,null,null,content0,null); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING,gen.getState()); - result=gen.commit(fields,header,null,content0,false); + result=gen.generate(header,null,null,content0,null); assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertTrue(gen.isChunking()); @@ -273,16 +279,16 @@ public class HttpGeneratorTest String body = BufferUtil.toString(content0); BufferUtil.clear(content0); - result=gen.commit(fields,header,null,content0,false); + result=gen.generate(header,null,null,content0,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); - result=gen.prepareContent(null,null,content1); + result=gen.generate(null,null,null,content1,null); assertEquals(HttpGenerator.Result.NEED_CHUNK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); - result=gen.prepareContent(chunk,null,content1); + result=gen.generate(null,chunk,null,content1,null); assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("\r\n2E\r\n",BufferUtil.toString(chunk)); @@ -290,13 +296,13 @@ public class HttpGeneratorTest body += BufferUtil.toString(chunk)+BufferUtil.toString(content1); BufferUtil.clear(content1); - result=gen.complete(chunk,null); + result=gen.generate(null,chunk,null,null,Action.COMPLETE); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.END,gen.getState()); assertEquals("\r\n0\r\n\r\n",BufferUtil.toString(chunk)); body += BufferUtil.toString(chunk); - result=gen.complete(chunk,null); + result=gen.generate(null,chunk,null,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); @@ -320,7 +326,7 @@ public class HttpGeneratorTest ByteBuffer content0=BufferUtil.toBuffer("Hello World! "); ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setVersion(HttpVersion.HTTP_1_1); gen.setResponse(200,null); @@ -330,23 +336,23 @@ public class HttpGeneratorTest HttpGenerator.Result - result=gen.prepareContent(null,null,content0); + result=gen.generate(null,null,null,content0,null); assertEquals(HttpGenerator.Result.NEED_BUFFER,result); assertEquals(HttpGenerator.State.START,gen.getState()); - result=gen.prepareContent(null,buffer,content0); + result=gen.generate(null,null,buffer,content0,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.START,gen.getState()); assertEquals("Hello World! ",BufferUtil.toString(buffer)); assertEquals(0,content0.remaining()); - result=gen.prepareContent(null,buffer,content1); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.START,gen.getState()); + result=gen.generate(null,null,buffer,content1,null); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING,gen.getState()); assertEquals("Hello World! The",BufferUtil.toString(buffer)); assertEquals(43,content1.remaining()); - result=gen.commit(fields,header,buffer,content1,false); + result=gen.generate(header,null,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals("Hello World! The",BufferUtil.toString(buffer)); @@ -358,7 +364,7 @@ public class HttpGeneratorTest String body = BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals(" quick brown fox",BufferUtil.toString(buffer)); @@ -366,7 +372,7 @@ public class HttpGeneratorTest body += BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals(" jumped over the",BufferUtil.toString(buffer)); @@ -374,20 +380,20 @@ public class HttpGeneratorTest body += BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.prepareContent(null,buffer,content1); + result=gen.generate(null,null,buffer,content1,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertEquals(" lazy dog. ",BufferUtil.toString(buffer)); assertEquals(0,content1.remaining()); - result=gen.complete(null,buffer); + result=gen.generate(null,null,buffer,null,Action.COMPLETE); assertEquals(HttpGenerator.Result.FLUSH,result); assertEquals(HttpGenerator.State.COMPLETING,gen.getState()); assertEquals(" lazy dog. ",BufferUtil.toString(buffer)); body += BufferUtil.toString(buffer); BufferUtil.clear(buffer); - result=gen.complete(null,buffer); + result=gen.generate(null,null,buffer,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); assertEquals(0,buffer.remaining()); @@ -410,7 +416,7 @@ public class HttpGeneratorTest ByteBuffer content0=BufferUtil.toBuffer("Hello World! "); ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); + HttpGenerator gen = new HttpGenerator(fields); gen.setLargeContent(8); gen.setVersion(HttpVersion.HTTP_1_1); @@ -421,11 +427,11 @@ public class HttpGeneratorTest HttpGenerator.Result - result=gen.prepareContent(null,null,content0); - assertEquals(HttpGenerator.Result.NEED_COMMIT,result); - assertEquals(HttpGenerator.State.START,gen.getState()); + result=gen.generate(null,null,null,content0,null); + assertEquals(HttpGenerator.Result.NEED_HEADER,result); + assertEquals(HttpGenerator.State.COMMITTING,gen.getState()); - result=gen.commit(fields,header,null,content0,false); + result=gen.generate(header,null,null,content0,null); assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); assertTrue(!gen.isChunking()); @@ -435,24 +441,20 @@ public class HttpGeneratorTest String body = BufferUtil.toString(content0); BufferUtil.clear(content0); - result=gen.commit(fields,header,null,null,false); + result=gen.generate(header,null,null,null,null); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); - result=gen.prepareContent(null,null,content1); + result=gen.generate(null,null,null,content1,null); assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result); assertEquals(HttpGenerator.State.COMMITTED,gen.getState()); body += BufferUtil.toString(content1); BufferUtil.clear(content1); - result=gen.complete(null,null); + result=gen.generate(null,null,null,null,Action.COMPLETE); assertEquals(HttpGenerator.Result.OK,result); assertEquals(HttpGenerator.State.END,gen.getState()); - - result=gen.complete(null,null); - assertEquals(HttpGenerator.Result.OK,result); - assertEquals(HttpGenerator.State.END,gen.getState()); - + assertEquals(59,gen.getContentWritten()); // System.err.println(head+body); @@ -471,9 +473,9 @@ public class HttpGeneratorTest public void testHTTP() throws Exception { HttpFields fields = new HttpFields(); - HttpGenerator gen = new HttpGenerator(); - // Handler handler = new Handler(); - // HttpParser parser=null; + HttpGenerator gen = new HttpGenerator(fields); + Handler handler = new Handler(); + HttpParser parser=null; // For HTTP version @@ -488,7 +490,7 @@ public class HttpGeneratorTest // For none, keep-alive, close for (int c=0;c<(v==11?connect.length:(connect.length-1));c++) { - String t="v="+v+",r="+r+",chunks="+chunks+",connect="+c+",tr="+tr[r]; + String t="v="+v+",chunks="+chunks+",connect="+connect[c]+",tr="+r+"="+tr[r]; // System.err.println(t); gen.reset(); @@ -496,7 +498,7 @@ public class HttpGeneratorTest String response=tr[r].build(v,gen,"OK\r\nTest",connect[c],null,chunks, fields); - System.out.println("RESPONSE: "+t+"\n"+response+(gen.isPersistent()?"...\n":"---\n")); + // System.err.println("===\n"+t+"\n"+response+(gen.isPersistent()?"...\n":"---\n")); if (v==9) { @@ -506,13 +508,12 @@ public class HttpGeneratorTest continue; } - /* - parser=new HttpParser(new ByteArrayBuffer(response.getBytes()), handler); + parser=new HttpParser(handler); parser.setHeadResponse(tr[r]._head); try { - parser.parse(); + parser.parseNext(BufferUtil.toBuffer(response)); } catch(IOException e) { @@ -522,21 +523,21 @@ public class HttpGeneratorTest } if (tr[r]._body!=null) - assertEquals(t,tr[r]._body, this.content); + assertEquals(t,tr[r]._body, this._content); if (v==10) - assertTrue(t,hb.isPersistent() || tr[r]._contentLength==null || c==2 || c==0); + assertTrue(t,gen.isPersistent() || tr[r]._contentLength>=0|| c==2 || c==0); else - assertTrue(t,hb.isPersistent() || c==2 || c==3); + assertTrue(t,gen.isPersistent() || c==2 || c==3); if (v>9) - assertEquals("OK Test",f2); + assertEquals("OK??Test",_reason); - if (content==null) + if (_content==null) assertTrue(t,tr[r]._body==null); else - assertTrue(t,tr[r]._contentLength==null || content.length()==Integer.parseInt(tr[r]._contentLength)); - */ + assertThat(t,tr[r]._contentLength,either(equalTo(_content.length())).or(equalTo(-1))); + } } } @@ -550,12 +551,12 @@ public class HttpGeneratorTest private String _body; private boolean _head; String _contentType; - String _contentLength; + int _contentLength; String _connection; String _te; String _other; - private TR(int code,String contentType, String contentLength ,String content,boolean head) + private TR(int code,String contentType, int contentLength ,String content,boolean head) { _code=code; _contentType=contentType; @@ -576,10 +577,10 @@ public class HttpGeneratorTest if (_contentType!=null) fields.put("Content-Type",_contentType); - if (_contentLength!=null) + if (_contentLength>=0) { - fields.put("Content-Length",_contentLength); - gen.setContentLength(Long.parseLong(_contentLength)); + fields.put("Content-Length",""+_contentLength); + gen.setContentLength(_contentLength); } if (_connection!=null) fields.put("Connection",_connection); @@ -591,11 +592,12 @@ public class HttpGeneratorTest ByteBuffer content=_body==null?null:BufferUtil.toBuffer(_body); if (content!=null) content.limit(0); + ByteBuffer header=null; ByteBuffer chunk=null; ByteBuffer buffer=null; - mainLoop: while(true) + while(!gen.isComplete()) { // if we have unwritten content if (content!=null && content.position()1) content.limit(content.position()+content.remaining()/2); - else - content.limit(content.capacity()); - } - - switch(gen.getState()) - { - case START: - case COMPLETING_UNCOMMITTED: - case COMMITTED: - case COMPLETING: - case END: - + // System.err.printf("content %d %s%n",chunks,BufferUtil.toDetailString(content)); } - } + + // Generate + Action action=BufferUtil.hasContent(content)?null:Action.COMPLETE; + /* System.err.printf("generate(%s,%s,%s,%s,%s)@%s%n", + BufferUtil.toSummaryString(header), + BufferUtil.toSummaryString(chunk), + BufferUtil.toSummaryString(buffer), + BufferUtil.toSummaryString(content), + action,gen.getState());*/ + HttpGenerator.Result result=gen.generate(header,chunk,buffer,content,action); + /*System.err.printf("%s (%s,%s,%s,%s,%s)@%s%n", + result, + BufferUtil.toSummaryString(header), + BufferUtil.toSummaryString(chunk), + BufferUtil.toSummaryString(buffer), + BufferUtil.toSummaryString(content), + action,gen.getState());*/ - switch(gen.prepareContent(chunk,buffer,content)) - { - case FLUSH: - if (BufferUtil.hasContent(chunk)) - { - response+=BufferUtil.toString(chunk); - chunk.position(chunk.limit()); - } - if (BufferUtil.hasContent(buffer)) - { - response+=BufferUtil.toString(buffer); - buffer.position(buffer.limit()); - } - break; - - case FLUSH_CONTENT: - if (BufferUtil.hasContent(chunk)) - { - response+=BufferUtil.toString(chunk); - chunk.position(chunk.limit()); - } - if (BufferUtil.hasContent(content)) - { - response+=BufferUtil.toString(content); - content.position(content.limit()); - } - break; - - case NEED_BUFFER: - buffer=BufferUtil.allocate(8192); - break; - - case NEED_CHUNK: - chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); - break; - - case NEED_COMMIT: - { - commitLoop: while (true) - { - ByteBuffer header=BufferUtil.allocate(4096); - switch(gen.commit(fields,header,buffer,content,chunks==0)) - { - case FLUSH: - if (BufferUtil.hasContent(header)) - { - response+=BufferUtil.toString(header); - header.position(header.limit()); - } - if (BufferUtil.hasContent(buffer)) - { - response+=BufferUtil.toString(buffer); - buffer.position(buffer.limit()); - } - break; - - case FLUSH_CONTENT: - if (BufferUtil.hasContent(header)) - { - response+=BufferUtil.toString(header); - header.position(header.limit()); - } - if (BufferUtil.hasContent(content)) - { - response+=BufferUtil.toString(content); - content.position(content.limit()); - } - break; - - case NEED_BUFFER: - buffer=BufferUtil.allocate(8192); - break; - - case OK: - break commitLoop; - - default: - throw new IllegalStateException(gen.toString()); - } - } - } - break; - - - case NEED_COMPLETE: - { - completeLoop: while (true) - { - ByteBuffer header=BufferUtil.allocate(4096); - switch(gen.complete(chunk,buffer)) - { - case FLUSH: - if (BufferUtil.hasContent(chunk)) - { - response+=BufferUtil.toString(chunk); - chunk.position(chunk.limit()); - } - if (BufferUtil.hasContent(buffer)) - { - response+=BufferUtil.toString(buffer); - buffer.position(buffer.limit()); - } - break; - - case OK: - break completeLoop; - - default: - throw new IllegalStateException(gen.toString()); - } - } - } - break; - } - - continue; - } - - - while (true) + switch(result) { - switch(gen.complete(chunk,buffer)) - { - case FLUSH: - if (BufferUtil.hasContent(chunk)) - { - response+=BufferUtil.toString(chunk); - chunk.position(chunk.limit()); - } - if (BufferUtil.hasContent(buffer)) - { - response+=BufferUtil.toString(buffer); - buffer.position(buffer.limit()); - } - break; + case NEED_HEADER: + header=BufferUtil.allocate(2048); + break; + + case NEED_BUFFER: + buffer=BufferUtil.allocate(8192); + break; - case OK: - break mainLoop; - - default: - throw new IllegalStateException(gen.toString()); - } + case NEED_CHUNK: + header=null; + chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); + break; + + case FLUSH: + if (BufferUtil.hasContent(header)) + { + response+=BufferUtil.toString(header); + header.position(header.limit()); + } + else if (BufferUtil.hasContent(chunk)) + { + response+=BufferUtil.toString(chunk); + chunk.position(chunk.limit()); + } + if (BufferUtil.hasContent(buffer)) + { + response+=BufferUtil.toString(buffer); + buffer.position(buffer.limit()); + } + break; + + case FLUSH_CONTENT: + if (BufferUtil.hasContent(header)) + { + response+=BufferUtil.toString(header); + header.position(header.limit()); + } + else if (BufferUtil.hasContent(chunk)) + { + response+=BufferUtil.toString(chunk); + chunk.position(chunk.limit()); + } + if (BufferUtil.hasContent(content)) + { + response+=BufferUtil.toString(content); + content.position(content.limit()); + } + break; + + case OK: + case SHUTDOWN_OUT: + // TODO } } - return response; } @@ -780,87 +699,72 @@ public class HttpGeneratorTest private final TR[] tr = { - /* 0 */ new TR(200,null,null,null,false), - /* 1 */ new TR(200,null,null,CONTENT,false), - /* 2 */ new TR(200,null,""+CONTENT.length(),null,true), - /* 3 */ new TR(200,null,""+CONTENT.length(),CONTENT,false), - /* 4 */ new TR(200,"text/html",null,null,true), - /* 5 */ new TR(200,"text/html",null,CONTENT,false), - /* 6 */ new TR(200,"text/html",""+CONTENT.length(),null,true), - /* 7 */ new TR(200,"text/html",""+CONTENT.length(),CONTENT,false), + /* 0 */ new TR(200,null,-1,null,false), + /* 1 */ new TR(200,null,-1,CONTENT,false), + /* 2 */ new TR(200,null,CONTENT.length(),null,true), + /* 3 */ new TR(200,null,CONTENT.length(),CONTENT,false), + /* 4 */ new TR(200,"text/html",-1,null,true), + /* 5 */ new TR(200,"text/html",-1,CONTENT,false), + /* 6 */ new TR(200,"text/html",CONTENT.length(),null,true), + /* 7 */ new TR(200,"text/html",CONTENT.length(),CONTENT,false), }; - private String content; - private String f0; - private String f1; - private String f2; - private String[] hdr; - private String[] val; - private int h; + private String _content; + private String _version; + private int _status; + private String _reason; + private List _hdr=new ArrayList<>(); + private List _val=new ArrayList<>(); - private class Handler extends HttpParser.EventHandler + private class Handler implements HttpParser.ResponseHandler { - private int index=0; + @Override + public boolean startResponse(String version, int status, String reason) throws IOException + { + _version=version; + _status=status; + _reason=reason; + return false; + } + @Override - public void content(ByteBuffer ref) + public boolean parsedHeader(String name, String value) throws IOException { - if (index == 0) - content= ""; - content= content.substring(0, index) + ref; - index+=ref.length(); + _hdr.add(name); + _val.add(value); + return false; } @Override - public void startRequest(ByteBuffer tok0, ByteBuffer tok1, ByteBuffer tok2) + public boolean headerComplete() throws IOException { - h= -1; - hdr= new String[9]; - val= new String[9]; - f0= tok0.toString(); - f1= tok1.toString(); - if (tok2!=null) - f2= tok2.toString(); - else - f2=null; - index=0; - // System.out.println(f0+" "+f1+" "+f2); + _content= null; + return false; + } + + @Override + public boolean content(ByteBuffer ref) throws IOException + { + if (_content==null) + _content=""; + _content+=BufferUtil.toString(ref); + return false; } - /* (non-Javadoc) - * @see org.eclipse.jetty.EventHandler#startResponse(org.eclipse.io.Buffer, int, org.eclipse.io.Buffer) - */ + @Override - public void startResponse(ByteBuffer version, int status, ByteBuffer reason) + public boolean messageComplete(long contentLength) throws IOException { - h= -1; - hdr= new String[9]; - val= new String[9]; - f0= version.toString(); - f1= ""+status; - if (reason!=null) - f2= reason.toString(); - else - f2=null; - index=0; + return true; } @Override - public void parsedHeader(ByteBuffer name,ByteBuffer value) + public boolean earlyEOF() { - hdr[++h]= name.toString(); - val[h]= value.toString(); + return true; } - @Override - public void headerComplete() - { - content= null; - } - - @Override - public void messageComplete(long contentLength) - { - } + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java index 8dd025edda4..8c6c4954d19 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java @@ -79,10 +79,19 @@ public class BufferUtil } /* ------------------------------------------------------------ */ - public static void flipToFill(ByteBuffer buffer) + public static int flipToFill(ByteBuffer buffer) { - buffer.position(buffer.hasRemaining()?buffer.limit():0); + int position=buffer.position(); + int limit=buffer.limit(); + if (position==limit) + { + buffer.position(0); + buffer.limit(buffer.capacity()); + return 0; + } + buffer.position(limit); buffer.limit(buffer.capacity()); + return position; } @@ -155,11 +164,9 @@ public class BufferUtil public static int put(ByteBuffer from, ByteBuffer to, int maxBytes) { int put; - int pos=to.position(); + int pos=flipToFill(to); try { - flipToFill(to); - maxBytes=Math.min(maxBytes,to.remaining()); int remaining=from.remaining(); if (remaining>0) @@ -205,11 +212,9 @@ public class BufferUtil public static int put(ByteBuffer from, ByteBuffer to) { int put; - int pos=to.position(); + int pos= flipToFill(to); try { - flipToFill(to); - int remaining=from.remaining(); if (remaining>0) { @@ -561,9 +566,11 @@ public class BufferUtil { return ByteBuffer.wrap(s.getBytes(charset)); } - - public static String toDetailString(ByteBuffer buffer) + + public static String toSummaryString(ByteBuffer buffer) { + if (buffer==null) + return "null"; StringBuilder buf = new StringBuilder(); buf.append("[p="); buf.append(buffer.position()); @@ -571,6 +578,26 @@ public class BufferUtil buf.append(buffer.limit()); buf.append(",c="); buf.append(buffer.capacity()); + buf.append(",r="); + buf.append(buffer.remaining()); + buf.append("]"); + return buf.toString(); + } + + public static String toDetailString(ByteBuffer buffer) + { + if (buffer==null) + return "null"; + + StringBuilder buf = new StringBuilder(); + buf.append("[p="); + buf.append(buffer.position()); + buf.append(",l="); + buf.append(buffer.limit()); + buf.append(",c="); + buf.append(buffer.capacity()); + buf.append(",r="); + buf.append(buffer.remaining()); buf.append("]={"); for (int i=0;i