Trailers for generated requests

This commit is contained in:
Greg Wilkins 2017-02-02 13:27:12 +11:00
parent 7923032582
commit 80386028c1
7 changed files with 384 additions and 169 deletions

View File

@ -24,6 +24,7 @@ import java.io.IOException;
import java.nio.BufferOverflowException; import java.nio.BufferOverflowException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.function.Supplier;
import org.eclipse.jetty.http.HttpTokens.EndOfContent; import org.eclipse.jetty.http.HttpTokens.EndOfContent;
import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.ArrayTrie;
@ -55,7 +56,7 @@ public class HttpGenerator
// states // states
public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END } public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END }
public enum Result { NEED_CHUNK,NEED_INFO,NEED_HEADER,FLUSH,CONTINUE,SHUTDOWN_OUT,DONE} public enum Result { NEED_CHUNK,NEED_INFO,NEED_HEADER,NEED_CHUNK_TRAILER, FLUSH,CONTINUE,SHUTDOWN_OUT,DONE}
// other statics // other statics
public static final int CHUNK_SIZE = 12; public static final int CHUNK_SIZE = 12;
@ -66,6 +67,7 @@ public class HttpGenerator
private long _contentPrepared = 0; private long _contentPrepared = 0;
private boolean _noContentResponse = false; private boolean _noContentResponse = false;
private Boolean _persistent = null; private Boolean _persistent = null;
private Supplier<HttpFields> _trailers = null;
private final int _send; private final int _send;
private final static int SEND_SERVER = 0x01; private final static int SEND_SERVER = 0x01;
@ -111,6 +113,7 @@ public class HttpGenerator
_persistent = null; _persistent = null;
_contentPrepared = 0; _contentPrepared = 0;
_needCRLF = false; _needCRLF = false;
_trailers = null;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -278,52 +281,12 @@ public class HttpGenerator
case COMMITTED: case COMMITTED:
{ {
int len = BufferUtil.length(content); return committed(chunk,content,last);
if (len>0)
{
// Do we need a chunk buffer?
if (isChunking())
{
// Do we need a chunk buffer?
if (chunk==null)
return Result.NEED_CHUNK;
BufferUtil.clearToFill(chunk);
prepareChunk(chunk,len);
BufferUtil.flipToFlush(chunk,0);
}
_contentPrepared+=len;
}
if (last)
_state=State.COMPLETING;
return len>0?Result.FLUSH:Result.CONTINUE;
} }
case COMPLETING: case COMPLETING:
{ {
if (BufferUtil.hasContent(content)) return completing(chunk,content);
{
if (LOG.isDebugEnabled())
LOG.debug("discarding content in COMPLETING");
BufferUtil.clear(content);
}
if (isChunking())
{
// Do we need a chunk buffer?
if (chunk==null)
return Result.NEED_CHUNK;
BufferUtil.clearToFill(chunk);
prepareChunk(chunk,0);
BufferUtil.flipToFlush(chunk,0);
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
return Result.FLUSH;
}
_state=State.END;
return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT;
} }
case END: case END:
@ -340,7 +303,82 @@ public class HttpGenerator
} }
} }
private Result committed( ByteBuffer chunk, ByteBuffer content, boolean last)
{
int len = BufferUtil.length(content);
// handle the content.
if (len>0)
{
if (isChunking())
{
if (chunk==null)
return Result.NEED_CHUNK;
BufferUtil.clearToFill(chunk);
prepareChunk(chunk,len);
BufferUtil.flipToFlush(chunk,0);
}
_contentPrepared+=len;
}
if (last)
{
_state=State.COMPLETING;
return len>0?Result.FLUSH:Result.CONTINUE;
}
return len>0?Result.FLUSH:Result.DONE;
}
private Result completing( ByteBuffer chunk, ByteBuffer content)
{
if (BufferUtil.hasContent(content))
{
if (LOG.isDebugEnabled())
LOG.debug("discarding content in COMPLETING");
BufferUtil.clear(content);
}
if (isChunking())
{
if (_trailers!=null)
{
// Do we need a chunk buffer?
if (chunk==null || chunk.capacity()<=CHUNK_SIZE)
return Result.NEED_CHUNK_TRAILER;
HttpFields trailers = _trailers.get();
if (trailers!=null)
{
// Write the last chunk
BufferUtil.clearToFill(chunk);
generateTrailers(chunk,trailers);
BufferUtil.flipToFlush(chunk,0);
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
return Result.FLUSH;
}
}
// Do we need a chunk buffer?
if (chunk==null)
return Result.NEED_CHUNK;
// Write the last chunk
BufferUtil.clearToFill(chunk);
prepareChunk(chunk,0);
BufferUtil.flipToFlush(chunk,0);
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
return Result.FLUSH;
}
_state=State.END;
return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT;
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Deprecated
public Result generateResponse(MetaData.Response info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException public Result generateResponse(MetaData.Response info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException
{ {
return generateResponse(info,false,header,chunk,content,last); return generateResponse(info,false,header,chunk,content,last);
@ -386,7 +424,7 @@ public class HttpGenerator
// prepare the header // prepare the header
int pos=BufferUtil.flipToFill(header); int pos=BufferUtil.flipToFill(header);
try try
{ {
// generate ResponseLine // generate ResponseLine
generateResponseLine(info,header); generateResponseLine(info,header);
@ -442,29 +480,7 @@ public class HttpGenerator
case COMMITTED: case COMMITTED:
{ {
int len = BufferUtil.length(content); return committed(chunk,content,last);
// handle the content.
if (len>0)
{
if (isChunking())
{
if (chunk==null)
return Result.NEED_CHUNK;
BufferUtil.clearToFill(chunk);
prepareChunk(chunk,len);
BufferUtil.flipToFlush(chunk,0);
}
_contentPrepared+=len;
}
if (last)
{
_state=State.COMPLETING;
return len>0?Result.FLUSH:Result.CONTINUE;
}
return len>0?Result.FLUSH:Result.DONE;
} }
case COMPLETING_1XX: case COMPLETING_1XX:
@ -475,30 +491,7 @@ public class HttpGenerator
case COMPLETING: case COMPLETING:
{ {
if (BufferUtil.hasContent(content)) return completing(chunk,content);
{
if (LOG.isDebugEnabled())
LOG.debug("discarding content in COMPLETING");
BufferUtil.clear(content);
}
if (isChunking())
{
// Do we need a chunk buffer?
if (chunk==null)
return Result.NEED_CHUNK;
// Write the last chunk
BufferUtil.clearToFill(chunk);
prepareChunk(chunk,0);
BufferUtil.flipToFlush(chunk,0);
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
return Result.FLUSH;
}
_state=State.END;
return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT;
} }
case END: case END:
@ -535,6 +528,30 @@ public class HttpGenerator
_needCRLF=false; _needCRLF=false;
} }
} }
/* ------------------------------------------------------------ */
private void generateTrailers(ByteBuffer buffer, HttpFields trailer)
{
// if we need CRLF add this to header
if (_needCRLF)
BufferUtil.putCRLF(buffer);
// Add the chunk size to the header
buffer.put(ZERO_CHUNK);
int n=trailer.size();
for (int f=0;f<n;f++)
{
HttpField field = trailer.getField(f);
String v = field.getValue();
if (v==null || v.length()==0)
continue; // rfc7230 does not allow no value
putTo(field,buffer);
}
BufferUtil.putCRLF(buffer);
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private void generateRequestLine(MetaData.Request request,ByteBuffer header) private void generateRequestLine(MetaData.Request request,ByteBuffer header)
@ -614,7 +631,8 @@ public class HttpGenerator
HttpField transfer_encoding=null; HttpField transfer_encoding=null;
boolean http11 = info.getHttpVersion() == HttpVersion.HTTP_1_1; boolean http11 = info.getHttpVersion() == HttpVersion.HTTP_1_1;
boolean close = false; boolean close = false;
boolean chunked_hint = false; _trailers = http11?info.getTrailerSupplier():null;
boolean chunked_hint = _trailers!=null;
boolean content_type = false; boolean content_type = false;
long content_length = info.getContentLength(); long content_length = info.getContentLength();
boolean content_length_field = false; boolean content_length_field = false;
@ -697,7 +715,7 @@ public class HttpGenerator
} }
// Can we work out the content length? // Can we work out the content length?
if (last && content_length<0) if (last && content_length<0 && _trailers==null)
content_length = _contentPrepared+BufferUtil.length(content); content_length = _contentPrepared+BufferUtil.length(content);
// Calculate how to end _content and connection, _content length and transfer encoding // Calculate how to end _content and connection, _content length and transfer encoding
@ -840,6 +858,7 @@ public class HttpGenerator
/* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */
// common _content // common _content
private static final byte[] ZERO_CHUNK = { (byte) '0', (byte) '\015', (byte) '\012'};
private static final byte[] LAST_CHUNK = { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'}; private static final byte[] LAST_CHUNK = { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'};
private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012"); private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012");
private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012"); private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012");

View File

@ -20,12 +20,14 @@ package org.eclipse.jetty.http;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.function.Supplier;
public class MetaData implements Iterable<HttpField> public class MetaData implements Iterable<HttpField>
{ {
private HttpVersion _httpVersion; private HttpVersion _httpVersion;
private HttpFields _fields; private final HttpFields _fields;
private long _contentLength; private long _contentLength;
private Supplier<HttpFields> _trailers;
public MetaData(HttpVersion version, HttpFields fields) public MetaData(HttpVersion version, HttpFields fields)
{ {
@ -90,6 +92,16 @@ public class MetaData implements Iterable<HttpField>
return _fields; return _fields;
} }
public Supplier<HttpFields> getTrailerSupplier()
{
return _trailers;
}
public void setTrailerSupplier(Supplier<HttpFields> trailers)
{
_trailers = trailers;
}
/** /**
* @return the content length if available, otherwise {@link Long#MIN_VALUE} * @return the content length if available, otherwise {@link Long#MIN_VALUE}
*/ */

View File

@ -69,7 +69,7 @@ public class HttpGeneratorClientTest
String out = BufferUtil.toString(header); String out = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
result=gen.generateResponse(null,null,null,null, false); result=gen.generateResponse(null,false,null,null, null, false);
Assert.assertEquals(HttpGenerator.Result.DONE, result); Assert.assertEquals(HttpGenerator.Result.DONE, result);
Assert.assertEquals(HttpGenerator.State.END, gen.getState()); Assert.assertEquals(HttpGenerator.State.END, gen.getState());
Assert.assertTrue(!gen.isChunking()); Assert.assertTrue(!gen.isChunking());
@ -106,7 +106,7 @@ public class HttpGeneratorClientTest
String out = BufferUtil.toString(header); String out = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
result=gen.generateResponse(null,null,null,null, false); result=gen.generateResponse(null,false,null,null, null, false);
Assert.assertEquals(HttpGenerator.Result.DONE, result); Assert.assertEquals(HttpGenerator.Result.DONE, result);
Assert.assertEquals(HttpGenerator.State.END, gen.getState()); Assert.assertEquals(HttpGenerator.State.END, gen.getState());
Assert.assertTrue(!gen.isChunking()); Assert.assertTrue(!gen.isChunking());
@ -146,7 +146,7 @@ public class HttpGeneratorClientTest
out+=BufferUtil.toString(content0); out+=BufferUtil.toString(content0);
BufferUtil.clear(content0); BufferUtil.clear(content0);
result=gen.generateResponse(null,null,null,null, false); result=gen.generateResponse(null,false,null,null, null, false);
Assert.assertEquals(HttpGenerator.Result.DONE, result); Assert.assertEquals(HttpGenerator.Result.DONE, result);
Assert.assertEquals(HttpGenerator.State.END, gen.getState()); Assert.assertEquals(HttpGenerator.State.END, gen.getState());
Assert.assertTrue(!gen.isChunking()); Assert.assertTrue(!gen.isChunking());
@ -205,19 +205,19 @@ public class HttpGeneratorClientTest
out+=BufferUtil.toString(content1); out+=BufferUtil.toString(content1);
BufferUtil.clear(content1); BufferUtil.clear(content1);
result=gen.generateResponse(null,null,chunk,null, true); result=gen.generateResponse(null,false,null,chunk, null, true);
Assert.assertEquals(HttpGenerator.Result.CONTINUE, result); Assert.assertEquals(HttpGenerator.Result.CONTINUE, result);
Assert.assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); Assert.assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
Assert.assertTrue(gen.isChunking()); Assert.assertTrue(gen.isChunking());
result=gen.generateResponse(null,null,chunk,null, true); result=gen.generateResponse(null,false,null,chunk, null, true);
Assert.assertEquals(HttpGenerator.Result.FLUSH, result); Assert.assertEquals(HttpGenerator.Result.FLUSH, result);
Assert.assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); Assert.assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
out+=BufferUtil.toString(chunk); out+=BufferUtil.toString(chunk);
BufferUtil.clear(chunk); BufferUtil.clear(chunk);
Assert.assertTrue(!gen.isChunking()); Assert.assertTrue(!gen.isChunking());
result=gen.generateResponse(null,null,chunk,null, true); result=gen.generateResponse(null,false,null,chunk, null, true);
Assert.assertEquals(HttpGenerator.Result.DONE, result); Assert.assertEquals(HttpGenerator.Result.DONE, result);
Assert.assertEquals(HttpGenerator.State.END, gen.getState()); Assert.assertEquals(HttpGenerator.State.END, gen.getState());
@ -271,12 +271,12 @@ public class HttpGeneratorClientTest
out+=BufferUtil.toString(content1); out+=BufferUtil.toString(content1);
BufferUtil.clear(content1); BufferUtil.clear(content1);
result=gen.generateResponse(null,null,null,null, true); result=gen.generateResponse(null,false,null,null, null, true);
Assert.assertEquals(HttpGenerator.Result.CONTINUE, result); Assert.assertEquals(HttpGenerator.Result.CONTINUE, result);
Assert.assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); Assert.assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
Assert.assertTrue(!gen.isChunking()); Assert.assertTrue(!gen.isChunking());
result=gen.generateResponse(null,null,null,null, true); result=gen.generateResponse(null,false,null,null, null, true);
Assert.assertEquals(HttpGenerator.Result.DONE, result); Assert.assertEquals(HttpGenerator.Result.DONE, result);
Assert.assertEquals(HttpGenerator.State.END, gen.getState()); Assert.assertEquals(HttpGenerator.State.END, gen.getState());
out+=BufferUtil.toString(chunk); out+=BufferUtil.toString(chunk);

View File

@ -164,6 +164,11 @@ public class HttpGeneratorServerHTTPTest
chunk = BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); chunk = BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
continue; continue;
case NEED_CHUNK_TRAILER:
chunk = BufferUtil.allocate(2048);
continue;
case FLUSH: case FLUSH:
if (BufferUtil.hasContent(header)) if (BufferUtil.hasContent(header))
{ {

View File

@ -26,6 +26,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.function.Supplier;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
@ -42,7 +43,7 @@ public class HttpGeneratorServerTest
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, content, true); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, content, true);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
@ -50,7 +51,7 @@ public class HttpGeneratorServerTest
info.getFields().add("Content-Type", "test/data"); info.getFields().add("Content-Type", "test/data");
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
result = gen.generateResponse(info, null, null, content, true); result = gen.generateResponse(info, false, null, null, content, true);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
String response = BufferUtil.toString(header); String response = BufferUtil.toString(header);
@ -58,7 +59,7 @@ public class HttpGeneratorServerTest
response += BufferUtil.toString(content); response += BufferUtil.toString(content);
BufferUtil.clear(content); BufferUtil.clear(content);
result = gen.generateResponse(null, null, null, content, false); result = gen.generateResponse(null, false, null, null, content, false);
assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result); assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -78,7 +79,7 @@ public class HttpGeneratorServerTest
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, content, true); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, content, true);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
@ -86,10 +87,10 @@ public class HttpGeneratorServerTest
info.getFields().add("Content-Type", "test/data"); info.getFields().add("Content-Type", "test/data");
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
result = gen.generateResponse(info, null, null, content, true); result = gen.generateResponse(info, false, null, null, content, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
result = gen.generateResponse(info, header, null, content, true); result = gen.generateResponse(info, false, header, null, content, true);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
String response = BufferUtil.toString(header); String response = BufferUtil.toString(header);
@ -97,7 +98,7 @@ public class HttpGeneratorServerTest
response += BufferUtil.toString(content); response += BufferUtil.toString(content);
BufferUtil.clear(content); BufferUtil.clear(content);
result = gen.generateResponse(null, null, null, content, false); result = gen.generateResponse(null, false, null, null, content, false);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -121,7 +122,7 @@ public class HttpGeneratorServerTest
info.getFields().add("Content-Type", "test/data"); info.getFields().add("Content-Type", "test/data");
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
HttpGenerator.Result result = gen.generateResponse(info, header, null, content, true); HttpGenerator.Result result = gen.generateResponse(info, false, header, null, content, true);
assertEquals(gen.isNoContent(), true); assertEquals(gen.isNoContent(), true);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
@ -129,7 +130,7 @@ public class HttpGeneratorServerTest
String responseheaders = BufferUtil.toString(header); String responseheaders = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
result = gen.generateResponse(null, null, null, content, false); result = gen.generateResponse(null, false, null, null, content, false);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -150,7 +151,7 @@ public class HttpGeneratorServerTest
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, content, true); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, content, true);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
@ -158,10 +159,10 @@ public class HttpGeneratorServerTest
info.getFields().add("Content-Type", "test/data;\r\nextra=value"); info.getFields().add("Content-Type", "test/data;\r\nextra=value");
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
result = gen.generateResponse(info, null, null, content, true); result = gen.generateResponse(info, false, null, null, content, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
result = gen.generateResponse(info, header, null, content, true); result = gen.generateResponse(info, false, header, null, content, true);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
String response = BufferUtil.toString(header); String response = BufferUtil.toString(header);
@ -169,7 +170,7 @@ public class HttpGeneratorServerTest
response += BufferUtil.toString(content); response += BufferUtil.toString(content);
BufferUtil.clear(content); BufferUtil.clear(content);
result = gen.generateResponse(null, null, null, content, false); result = gen.generateResponse(null, false, null, null, content, false);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -194,14 +195,14 @@ public class HttpGeneratorServerTest
String head; String head;
HttpGenerator gen = new HttpGenerator(true, true); HttpGenerator gen = new HttpGenerator(true, true);
gen.generateResponse(info, header, null, null, true); gen.generateResponse(info, false, header, null, null, true);
head = BufferUtil.toString(header); head = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
assertThat(head, containsString("HTTP/1.1 200 OK")); assertThat(head, containsString("HTTP/1.1 200 OK"));
assertThat(head, containsString("Server: Jetty(9.x.x)")); assertThat(head, containsString("Server: Jetty(9.x.x)"));
assertThat(head, containsString("X-Powered-By: Jetty(9.x.x)")); assertThat(head, containsString("X-Powered-By: Jetty(9.x.x)"));
gen.reset(); gen.reset();
gen.generateResponse(infoF, header, null, null, true); gen.generateResponse(infoF, false, header, null, null, true);
head = BufferUtil.toString(header); head = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
assertThat(head, containsString("HTTP/1.1 200 OK")); assertThat(head, containsString("HTTP/1.1 200 OK"));
@ -212,14 +213,14 @@ public class HttpGeneratorServerTest
gen.reset(); gen.reset();
gen = new HttpGenerator(false, false); gen = new HttpGenerator(false, false);
gen.generateResponse(info, header, null, null, true); gen.generateResponse(info, false, header, null, null, true);
head = BufferUtil.toString(header); head = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
assertThat(head, containsString("HTTP/1.1 200 OK")); assertThat(head, containsString("HTTP/1.1 200 OK"));
assertThat(head, not(containsString("Server: Jetty(9.x.x)"))); assertThat(head, not(containsString("Server: Jetty(9.x.x)")));
assertThat(head, not(containsString("X-Powered-By: Jetty(9.x.x)"))); assertThat(head, not(containsString("X-Powered-By: Jetty(9.x.x)")));
gen.reset(); gen.reset();
gen.generateResponse(infoF, header, null, null, true); gen.generateResponse(infoF, false, header, null, null, true);
head = BufferUtil.toString(header); head = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
assertThat(head, containsString("HTTP/1.1 200 OK")); assertThat(head, containsString("HTTP/1.1 200 OK"));
@ -237,7 +238,7 @@ public class HttpGeneratorServerTest
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, null, true); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
@ -245,12 +246,12 @@ public class HttpGeneratorServerTest
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add("Content-Length", "11"); info.getFields().add("Content-Length", "11");
result = gen.generateResponse(info, null, null, null, true); result = gen.generateResponse(info, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
try try
{ {
gen.generateResponse(info, header, null, null, true); gen.generateResponse(info, false, header, null, null, true);
Assert.fail(); Assert.fail();
} }
catch(BadMessageException e) catch(BadMessageException e)
@ -266,23 +267,23 @@ public class HttpGeneratorServerTest
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, null, true); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 0); MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 0);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
result = gen.generateResponse(info, null, null, null, true); result = gen.generateResponse(info, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
result = gen.generateResponse(info, header, null, null, true); result = gen.generateResponse(info, false, header, null, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
String head = BufferUtil.toString(header); String head = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
result = gen.generateResponse(null, null, null, null, false); result = gen.generateResponse(null, false, null, null, null, false);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -299,7 +300,7 @@ public class HttpGeneratorServerTest
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, null, true); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
@ -307,16 +308,16 @@ public class HttpGeneratorServerTest
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add("Connection", "close"); info.getFields().add("Connection", "close");
result = gen.generateResponse(info, null, null, null, true); result = gen.generateResponse(info, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
result = gen.generateResponse(info, header, null, null, true); result = gen.generateResponse(info, false, header, null, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
String head = BufferUtil.toString(header); String head = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
result = gen.generateResponse(null, null, null, null, false); result = gen.generateResponse(null, false, null, null, null, false);
assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result); assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -333,7 +334,7 @@ public class HttpGeneratorServerTest
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, null, true); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
@ -342,13 +343,13 @@ public class HttpGeneratorServerTest
info.getFields().add("Connection", "Upgrade"); info.getFields().add("Connection", "Upgrade");
info.getFields().add("Sec-WebSocket-Accept", "123456789=="); info.getFields().add("Sec-WebSocket-Accept", "123456789==");
result = gen.generateResponse(info, header, null, null, true); result = gen.generateResponse(info, false, header, null, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
String head = BufferUtil.toString(header); String head = BufferUtil.toString(header);
BufferUtil.clear(header); BufferUtil.clear(header);
result = gen.generateResponse(info, null, null, null, false); result = gen.generateResponse(info, false, null, null, null, false);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -368,17 +369,17 @@ public class HttpGeneratorServerTest
ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, content0, false); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1); MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
result = gen.generateResponse(info, null, null, content0, false); result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
result = gen.generateResponse(info, header, null, content0, false); result = gen.generateResponse(info, false, header, null, content0, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
@ -387,7 +388,7 @@ public class HttpGeneratorServerTest
out += BufferUtil.toString(content0); out += BufferUtil.toString(content0);
BufferUtil.clear(content0); BufferUtil.clear(content0);
result = gen.generateResponse(null, null, chunk, content1, false); result = gen.generateResponse(null, false, null, chunk, content1, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
out += BufferUtil.toString(chunk); out += BufferUtil.toString(chunk);
@ -395,17 +396,17 @@ public class HttpGeneratorServerTest
out += BufferUtil.toString(content1); out += BufferUtil.toString(content1);
BufferUtil.clear(content1); BufferUtil.clear(content1);
result = gen.generateResponse(null, null, chunk, null, true); result = gen.generateResponse(null, false, null, chunk, null, true);
assertEquals(HttpGenerator.Result.CONTINUE, result); assertEquals(HttpGenerator.Result.CONTINUE, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
result = gen.generateResponse(null, null, chunk, null, true); result = gen.generateResponse(null, false, null, chunk, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
out += BufferUtil.toString(chunk); out += BufferUtil.toString(chunk);
BufferUtil.clear(chunk); BufferUtil.clear(chunk);
result = gen.generateResponse(null, null, chunk, null, true); result = gen.generateResponse(null, false, null, chunk, null, true);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -433,18 +434,18 @@ public class HttpGeneratorServerTest
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
gen.setPersistent(false); gen.setPersistent(false);
HttpGenerator.Result result = gen.generateResponse(null, null, null, content0, false); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1); MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED); info.getFields().add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
result = gen.generateResponse(info, null, null, content0, false); result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
result = gen.generateResponse(info, header, null, content0, false); result = gen.generateResponse(info, false, header, null, content0, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
@ -453,7 +454,10 @@ public class HttpGeneratorServerTest
out += BufferUtil.toString(content0); out += BufferUtil.toString(content0);
BufferUtil.clear(content0); BufferUtil.clear(content0);
result = gen.generateResponse(null, null, chunk, content1, false); result = gen.generateResponse(null, false, null, null, content1, false);
assertEquals(HttpGenerator.Result.NEED_CHUNK, result);
result = gen.generateResponse(null, false, null, chunk, content1, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
out += BufferUtil.toString(chunk); out += BufferUtil.toString(chunk);
@ -461,17 +465,17 @@ public class HttpGeneratorServerTest
out += BufferUtil.toString(content1); out += BufferUtil.toString(content1);
BufferUtil.clear(content1); BufferUtil.clear(content1);
result = gen.generateResponse(null, null, chunk, null, true); result = gen.generateResponse(null, false, null, chunk, null, true);
assertEquals(HttpGenerator.Result.CONTINUE, result); assertEquals(HttpGenerator.Result.CONTINUE, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
result = gen.generateResponse(null, null, chunk, null, true); result = gen.generateResponse(null, false, null, chunk, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
out += BufferUtil.toString(chunk); out += BufferUtil.toString(chunk);
BufferUtil.clear(chunk); BufferUtil.clear(chunk);
result = gen.generateResponse(null, null, chunk, null, true); result = gen.generateResponse(null, false, null, chunk, null, true);
assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result); assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -489,6 +493,170 @@ public class HttpGeneratorServerTest
"\r\n")); "\r\n"));
} }
@Test
public void testResponseWithContentAndTrailer() throws Exception
{
ByteBuffer header = BufferUtil.allocate(4096);
ByteBuffer chunk = BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
ByteBuffer trailer = BufferUtil.allocate(4096);
ByteBuffer content0 = BufferUtil.toBuffer("Hello World! ");
ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
HttpGenerator gen = new HttpGenerator();
gen.setPersistent(false);
HttpGenerator.Result result = gen.generateResponse(null, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
info.setTrailerSupplier(new Supplier<HttpFields>()
{
@Override
public HttpFields get()
{
HttpFields trailer = new HttpFields();
trailer.add("T-Name0","T-ValueA");
trailer.add("T-Name0","T-ValueB");
trailer.add("T-Name1","T-ValueC");
return trailer;
}
});
result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState());
result = gen.generateResponse(info, false, header, null, content0, false);
assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
String out = BufferUtil.toString(header);
BufferUtil.clear(header);
out += BufferUtil.toString(content0);
BufferUtil.clear(content0);
result = gen.generateResponse(null, false, null, null, content1, false);
assertEquals(HttpGenerator.Result.NEED_CHUNK, result);
result = gen.generateResponse(null, false, null, chunk, content1, false);
assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
out += BufferUtil.toString(chunk);
BufferUtil.clear(chunk);
out += BufferUtil.toString(content1);
BufferUtil.clear(content1);
result = gen.generateResponse(null, false, null, chunk, null, true);
assertEquals(HttpGenerator.Result.CONTINUE, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
result = gen.generateResponse(null, false, null, chunk, null, true);
assertEquals(HttpGenerator.Result.NEED_CHUNK_TRAILER, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
result = gen.generateResponse(null, false, null, trailer, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
out += BufferUtil.toString(trailer);
BufferUtil.clear(trailer);
result = gen.generateResponse(null, false, null, trailer, null, true);
assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result);
assertEquals(HttpGenerator.State.END, gen.getState());
assertThat(out, containsString("HTTP/1.1 200 OK"));
assertThat(out, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
assertThat(out, not(containsString("Content-Length")));
assertThat(out, containsString("Transfer-Encoding: chunked"));
assertThat(out, endsWith(
"\r\n\r\nD\r\n"+
"Hello World! \r\n"+
"2E\r\n"+
"The quick brown fox jumped over the lazy dog. \r\n"+
"0\r\n"+
"T-Name0: T-ValueA\r\n"+
"T-Name0: T-ValueB\r\n"+
"T-Name1: T-ValueC\r\n"+
"\r\n"));
}
@Test
public void testResponseWithTrailer() throws Exception
{
ByteBuffer header = BufferUtil.allocate(4096);
ByteBuffer chunk = BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
ByteBuffer trailer = BufferUtil.allocate(4096);
HttpGenerator gen = new HttpGenerator();
gen.setPersistent(false);
HttpGenerator.Result result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
info.setTrailerSupplier(new Supplier<HttpFields>()
{
@Override
public HttpFields get()
{
HttpFields trailer = new HttpFields();
trailer.add("T-Name0","T-ValueA");
trailer.add("T-Name0","T-ValueB");
trailer.add("T-Name1","T-ValueC");
return trailer;
}
});
result = gen.generateResponse(info, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState());
result = gen.generateResponse(info, false, header, null, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
String out = BufferUtil.toString(header);
BufferUtil.clear(header);
result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_CHUNK_TRAILER, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
result = gen.generateResponse(null, false, null, chunk, null, true);
assertEquals(HttpGenerator.Result.NEED_CHUNK_TRAILER, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
result = gen.generateResponse(null, false, null, trailer, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
out += BufferUtil.toString(trailer);
BufferUtil.clear(trailer);
result = gen.generateResponse(null, false, null, trailer, null, true);
assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result);
assertEquals(HttpGenerator.State.END, gen.getState());
assertThat(out, containsString("HTTP/1.1 200 OK"));
assertThat(out, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
assertThat(out, not(containsString("Content-Length")));
assertThat(out, containsString("Transfer-Encoding: chunked"));
assertThat(out, endsWith(
"\r\n\r\n"+
"0\r\n"+
"T-Name0: T-ValueA\r\n"+
"T-Name0: T-ValueB\r\n"+
"T-Name1: T-ValueC\r\n"+
"\r\n"));
}
@Test @Test
public void testResponseWithKnownContentLengthFromMetaData() throws Exception public void testResponseWithKnownContentLengthFromMetaData() throws Exception
@ -498,17 +666,17 @@ public class HttpGeneratorServerTest
ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, content0, false); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 59); MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 59);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
result = gen.generateResponse(info, null, null, content0, false); result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
result = gen.generateResponse(info, header, null, content0, false); result = gen.generateResponse(info, false, header, null, content0, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
@ -517,17 +685,17 @@ public class HttpGeneratorServerTest
out += BufferUtil.toString(content0); out += BufferUtil.toString(content0);
BufferUtil.clear(content0); BufferUtil.clear(content0);
result = gen.generateResponse(null, null, null, content1, false); result = gen.generateResponse(null, false, null, null, content1, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
out += BufferUtil.toString(content1); out += BufferUtil.toString(content1);
BufferUtil.clear(content1); BufferUtil.clear(content1);
result = gen.generateResponse(null, null, null, null, true); result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.CONTINUE, result); assertEquals(HttpGenerator.Result.CONTINUE, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
result = gen.generateResponse(null, null, null, null, true); result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -546,18 +714,18 @@ public class HttpGeneratorServerTest
ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(null, null, null, content0, false); HttpGenerator.Result result = gen.generateResponse(null, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1); MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add("Content-Length",""+(content0.remaining()+content1.remaining())); info.getFields().add("Content-Length",""+(content0.remaining()+content1.remaining()));
result = gen.generateResponse(info, null, null, content0, false); result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
result = gen.generateResponse(info, header, null, content0, false); result = gen.generateResponse(info, false, header, null, content0, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
@ -566,17 +734,17 @@ public class HttpGeneratorServerTest
out += BufferUtil.toString(content0); out += BufferUtil.toString(content0);
BufferUtil.clear(content0); BufferUtil.clear(content0);
result = gen.generateResponse(null, null, null, content1, false); result = gen.generateResponse(null, false, null, null, content1, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
out += BufferUtil.toString(content1); out += BufferUtil.toString(content1);
BufferUtil.clear(content1); BufferUtil.clear(content1);
result = gen.generateResponse(null, null, null, null, true); result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.CONTINUE, result); assertEquals(HttpGenerator.Result.CONTINUE, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
result = gen.generateResponse(null, null, null, null, true); result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -598,32 +766,32 @@ public class HttpGeneratorServerTest
ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. "); ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
HttpGenerator gen = new HttpGenerator(); HttpGenerator gen = new HttpGenerator();
HttpGenerator.Result result = gen.generateResponse(HttpGenerator.CONTINUE_100_INFO, null, null, null, false); HttpGenerator.Result result = gen.generateResponse(HttpGenerator.CONTINUE_100_INFO, false, null, null, null, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
result = gen.generateResponse(HttpGenerator.CONTINUE_100_INFO, header, null, null, false); result = gen.generateResponse(HttpGenerator.CONTINUE_100_INFO, false, header, null, null, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING_1XX, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING_1XX, gen.getState());
String out = BufferUtil.toString(header); String out = BufferUtil.toString(header);
result = gen.generateResponse(null, null, null, null, false); result = gen.generateResponse(null, false, null, null, null, false);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
assertThat(out, containsString("HTTP/1.1 100 Continue")); assertThat(out, containsString("HTTP/1.1 100 Continue"));
result = gen.generateResponse(null, null, null, content0, false); result = gen.generateResponse(null, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), BufferUtil.length(content0)+BufferUtil.length(content1)); MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), BufferUtil.length(content0)+BufferUtil.length(content1));
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
result = gen.generateResponse(info, null, null, content0, false); result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState()); assertEquals(HttpGenerator.State.START, gen.getState());
result = gen.generateResponse(info, header, null, content0, false); result = gen.generateResponse(info, false, header, null, content0, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
@ -632,17 +800,17 @@ public class HttpGeneratorServerTest
out += BufferUtil.toString(content0); out += BufferUtil.toString(content0);
BufferUtil.clear(content0); BufferUtil.clear(content0);
result = gen.generateResponse(null, null, null, content1, false); result = gen.generateResponse(null, false, null, null, content1, false);
assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
out += BufferUtil.toString(content1); out += BufferUtil.toString(content1);
BufferUtil.clear(content1); BufferUtil.clear(content1);
result = gen.generateResponse(null, null, null, null, true); result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.CONTINUE, result); assertEquals(HttpGenerator.Result.CONTINUE, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
result = gen.generateResponse(null, null, null, null, true); result = gen.generateResponse(null, false, null, null, null, true);
assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState()); assertEquals(HttpGenerator.State.END, gen.getState());
@ -664,7 +832,7 @@ public class HttpGeneratorServerTest
fields.add(HttpHeader.CONNECTION, customValue); fields.add(HttpHeader.CONNECTION, customValue);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_0, 200, "OK", fields, -1); MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_0, 200, "OK", fields, -1);
ByteBuffer header = BufferUtil.allocate(4096); ByteBuffer header = BufferUtil.allocate(4096);
HttpGenerator.Result result = generator.generateResponse(info, header, null, null, true); HttpGenerator.Result result = generator.generateResponse(info, false, header, null, null, true);
Assert.assertSame(HttpGenerator.Result.FLUSH, result); Assert.assertSame(HttpGenerator.Result.FLUSH, result);
String headers = BufferUtil.toString(header); String headers = BufferUtil.toString(header);
Assert.assertTrue(headers.contains(HttpHeaderValue.KEEP_ALIVE.asString())); Assert.assertTrue(headers.contains(HttpHeaderValue.KEEP_ALIVE.asString()));

View File

@ -404,6 +404,10 @@ public class HttpTester
chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
continue; continue;
case NEED_CHUNK_TRAILER:
chunk=BufferUtil.allocate(8192);
continue;
case NEED_INFO: case NEED_INFO:
throw new IllegalStateException(); throw new IllegalStateException();

View File

@ -716,6 +716,13 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
chunk = _chunk = _bufferPool.acquire(HttpGenerator.CHUNK_SIZE, CHUNK_BUFFER_DIRECT); chunk = _chunk = _bufferPool.acquire(HttpGenerator.CHUNK_SIZE, CHUNK_BUFFER_DIRECT);
continue; continue;
} }
case NEED_CHUNK_TRAILER:
{
if (_chunk!=null)
_bufferPool.release(_chunk);
chunk = _chunk = _bufferPool.acquire(_config.getResponseHeaderSize(), CHUNK_BUFFER_DIRECT);
continue;
}
case FLUSH: case FLUSH:
{ {
// Don't write the chunk or the content if this is a HEAD response, or any other type of response that should have no content // Don't write the chunk or the content if this is a HEAD response, or any other type of response that should have no content