Issue#1066 Simplify HttpGeneration
Reduce the transformations needed on header fields, so they can be more often set directly and no need to split and recombine. The Content-Length field is added IF it is needed for framing or if it was explicitly set The Transfer-Encoding: chunk field is used only as a hint that there is content. Connection fields are used as is, but are checked for close and keep-alive
This commit is contained in:
parent
41d506fe4e
commit
6781a949b1
|
@ -1,10 +1,10 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.jboss.LEVEL=DEBUG
|
||||
# org.jboss.LEVEL=DEBUG
|
||||
org.eclipse.jetty.LEVEL=INFO
|
||||
|
||||
org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
|
||||
|
||||
# org.eclipse.jetty.LEVEL=DEBUG
|
||||
org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.client.LEVEL=DEBUG
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.eclipse.jetty.io.ByteArrayEndPoint;
|
|||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
@ -258,7 +259,7 @@ public class HttpSenderOverHTTPTest
|
|||
|
||||
String requestString = endPoint.takeOutputString();
|
||||
Assert.assertTrue(requestString.startsWith("GET "));
|
||||
Assert.assertTrue(requestString.endsWith("\r\n\r\n" + content1 + content2));
|
||||
Assert.assertThat(requestString,Matchers.endsWith("\r\n\r\n" + content1 + content2));
|
||||
Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
|
|
@ -18,16 +18,18 @@
|
|||
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
import static org.eclipse.jetty.http.HttpStatus.INTERNAL_SERVER_ERROR_500;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.http.HttpTokens.EndOfContent;
|
||||
import org.eclipse.jetty.util.ArrayTrie;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
@ -46,11 +48,10 @@ public class HttpGenerator
|
|||
public final static boolean __STRICT=Boolean.getBoolean("org.eclipse.jetty.http.HttpGenerator.STRICT");
|
||||
|
||||
private final static byte[] __colon_space = new byte[] {':',' '};
|
||||
private final static HttpHeaderValue[] CLOSE = {HttpHeaderValue.CLOSE};
|
||||
public static final MetaData.Response CONTINUE_100_INFO = new MetaData.Response(HttpVersion.HTTP_1_1,100,null,null,-1);
|
||||
public static final MetaData.Response PROGRESS_102_INFO = new MetaData.Response(HttpVersion.HTTP_1_1,102,null,null,-1);
|
||||
public final static MetaData.Response RESPONSE_500_INFO =
|
||||
new MetaData.Response(HttpVersion.HTTP_1_1,HttpStatus.INTERNAL_SERVER_ERROR_500,null,new HttpFields(){{put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);}},0);
|
||||
new MetaData.Response(HttpVersion.HTTP_1_1,INTERNAL_SERVER_ERROR_500,null,new HttpFields(){{put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);}},0);
|
||||
|
||||
// states
|
||||
public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END }
|
||||
|
@ -63,13 +64,18 @@ public class HttpGenerator
|
|||
private EndOfContent _endOfContent = EndOfContent.UNKNOWN_CONTENT;
|
||||
|
||||
private long _contentPrepared = 0;
|
||||
private boolean _noContent = false;
|
||||
private boolean _noContentResponse = false;
|
||||
private Boolean _persistent = null;
|
||||
|
||||
private final int _send;
|
||||
private final static int SEND_SERVER = 0x01;
|
||||
private final static int SEND_XPOWEREDBY = 0x02;
|
||||
private final static Set<String> __assumedContentMethods = new HashSet<>(Arrays.asList(new String[]{HttpMethod.POST.asString(),HttpMethod.PUT.asString()}));
|
||||
private final static Trie<Boolean> __assumedContentMethods = new ArrayTrie<>(8);
|
||||
static
|
||||
{
|
||||
__assumedContentMethods.put(HttpMethod.POST.asString(),Boolean.TRUE);
|
||||
__assumedContentMethods.put(HttpMethod.PUT.asString(),Boolean.TRUE);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public static void setJettyVersion(String serverVersion)
|
||||
|
@ -101,7 +107,7 @@ public class HttpGenerator
|
|||
{
|
||||
_state = State.START;
|
||||
_endOfContent = EndOfContent.UNKNOWN_CONTENT;
|
||||
_noContent=false;
|
||||
_noContentResponse=false;
|
||||
_persistent = null;
|
||||
_contentPrepared = 0;
|
||||
_needCRLF = false;
|
||||
|
@ -160,7 +166,7 @@ public class HttpGenerator
|
|||
/* ------------------------------------------------------------ */
|
||||
public boolean isNoContent()
|
||||
{
|
||||
return _noContent;
|
||||
return _noContentResponse;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -227,7 +233,7 @@ public class HttpGenerator
|
|||
generateRequestLine(info,header);
|
||||
|
||||
if (info.getHttpVersion()==HttpVersion.HTTP_0_9)
|
||||
throw new BadMessageException(500,"HTTP/0.9 not supported");
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"HTTP/0.9 not supported");
|
||||
|
||||
generateHeaders(info,header,content,last);
|
||||
|
||||
|
@ -252,10 +258,17 @@ public class HttpGenerator
|
|||
|
||||
return Result.FLUSH;
|
||||
}
|
||||
catch(BadMessageException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch(BufferOverflowException e)
|
||||
{
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Request header too large",e);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
String message= (e instanceof BufferOverflowException)?"Request header too large":e.getMessage();
|
||||
throw new BadMessageException(500,message,e);
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,e.getMessage(),e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -344,7 +357,7 @@ public class HttpGenerator
|
|||
return Result.NEED_INFO;
|
||||
HttpVersion version=info.getHttpVersion();
|
||||
if (version==null)
|
||||
throw new BadMessageException(500,"No version");
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"No version");
|
||||
switch(version)
|
||||
{
|
||||
case HTTP_1_0:
|
||||
|
@ -381,7 +394,7 @@ public class HttpGenerator
|
|||
int status=info.getStatus();
|
||||
if (status>=100 && status<200 )
|
||||
{
|
||||
_noContent=true;
|
||||
_noContentResponse=true;
|
||||
|
||||
if (status!=HttpStatus.SWITCHING_PROTOCOLS_101 )
|
||||
{
|
||||
|
@ -392,7 +405,7 @@ public class HttpGenerator
|
|||
}
|
||||
else if (status==HttpStatus.NO_CONTENT_204 || status==HttpStatus.NOT_MODIFIED_304)
|
||||
{
|
||||
_noContent=true;
|
||||
_noContentResponse=true;
|
||||
}
|
||||
|
||||
generateHeaders(info,header,content,last);
|
||||
|
@ -407,10 +420,17 @@ public class HttpGenerator
|
|||
}
|
||||
_state = last?State.COMPLETING:State.COMMITTED;
|
||||
}
|
||||
catch(BadMessageException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch(BufferOverflowException e)
|
||||
{
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Request header too large",e);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
String message= (e instanceof BufferOverflowException)?"Response header too large":e.getMessage();
|
||||
throw new BadMessageException(500,message,e);
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,e.getMessage(),e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -578,22 +598,29 @@ public class HttpGenerator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void generateHeaders(MetaData _info,ByteBuffer header,ByteBuffer content,boolean last)
|
||||
private void generateHeaders(MetaData info,ByteBuffer header,ByteBuffer content,boolean last)
|
||||
{
|
||||
final MetaData.Request request=(_info instanceof MetaData.Request)?(MetaData.Request)_info:null;
|
||||
final MetaData.Response response=(_info instanceof MetaData.Response)?(MetaData.Response)_info:null;
|
||||
final MetaData.Request request=(info instanceof MetaData.Request)?(MetaData.Request)info:null;
|
||||
final MetaData.Response response=(info instanceof MetaData.Response)?(MetaData.Response)info:null;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("generateHeaders {} last={} content={}",info,last,BufferUtil.toDetailString(content));
|
||||
LOG.debug(info.getFields().toString());
|
||||
}
|
||||
|
||||
// default field values
|
||||
int send=_send;
|
||||
HttpField transfer_encoding=null;
|
||||
boolean keep_alive=false;
|
||||
boolean http11 = info.getHttpVersion() == HttpVersion.HTTP_1_1;
|
||||
boolean close = false;
|
||||
boolean chunked = false;
|
||||
boolean content_type = false;
|
||||
StringBuilder connection = null;
|
||||
long content_length = _info.getContentLength();
|
||||
long content_length = info.getContentLength();
|
||||
boolean content_length_field = false;
|
||||
|
||||
// Generate fields
|
||||
HttpFields fields = _info.getFields();
|
||||
HttpFields fields = info.getFields();
|
||||
if (fields != null)
|
||||
{
|
||||
int n=fields.size();
|
||||
|
@ -612,10 +639,11 @@ public class HttpGenerator
|
|||
switch (h)
|
||||
{
|
||||
case CONTENT_LENGTH:
|
||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
||||
if (content_length<0)
|
||||
content_length=Long.valueOf(field.getValue());
|
||||
// handle setting the field specially below
|
||||
content_length = field.getLongValue();
|
||||
else if (content_length!=field.getLongValue())
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,String.format("Incorrect Content-Length %d!=%d",content_length,field.getLongValue()));
|
||||
content_length_field = true;
|
||||
break;
|
||||
|
||||
case CONTENT_TYPE:
|
||||
|
@ -628,84 +656,32 @@ public class HttpGenerator
|
|||
|
||||
case TRANSFER_ENCODING:
|
||||
{
|
||||
if (_info.getHttpVersion() == HttpVersion.HTTP_1_1)
|
||||
if (http11)
|
||||
{
|
||||
// Don't add yet, treat this only as a hint that there is content
|
||||
// with a preference to chunk if we can
|
||||
transfer_encoding = field;
|
||||
// Do NOT add yet!
|
||||
chunked = field.contains(HttpHeaderValue.CHUNKED.asString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CONNECTION:
|
||||
{
|
||||
if (request!=null)
|
||||
putTo(field,header);
|
||||
|
||||
// Lookup and/or split connection value field
|
||||
HttpHeaderValue[] values = HttpHeaderValue.CLOSE.is(field.getValue())?CLOSE:new HttpHeaderValue[]{HttpHeaderValue.CACHE.get(field.getValue())};
|
||||
String[] split = null;
|
||||
|
||||
if (values[0]==null)
|
||||
{
|
||||
split = StringUtil.csvSplit(field.getValue());
|
||||
if (split.length>0)
|
||||
{
|
||||
values=new HttpHeaderValue[split.length];
|
||||
for (int i=0;i<split.length;i++)
|
||||
values[i]=HttpHeaderValue.CACHE.get(split[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle connection values
|
||||
for (int i=0;i<values.length;i++)
|
||||
{
|
||||
HttpHeaderValue value=values[i];
|
||||
switch (value==null?HttpHeaderValue.UNKNOWN:value)
|
||||
{
|
||||
case UPGRADE:
|
||||
{
|
||||
// special case for websocket connection ordering
|
||||
header.put(HttpHeader.CONNECTION.getBytesColonSpace()).put(HttpHeader.UPGRADE.getBytes());
|
||||
header.put(CRLF);
|
||||
break;
|
||||
}
|
||||
|
||||
case CLOSE:
|
||||
if (field.contains(HttpHeaderValue.CLOSE.asString()))
|
||||
{
|
||||
close=true;
|
||||
_persistent=false;
|
||||
if (response!=null)
|
||||
{
|
||||
if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
|
||||
_endOfContent=EndOfContent.EOF_CONTENT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KEEP_ALIVE:
|
||||
if (!http11 && field.contains(HttpHeaderValue.KEEP_ALIVE.asString()))
|
||||
{
|
||||
if (_info.getHttpVersion() == HttpVersion.HTTP_1_0)
|
||||
{
|
||||
keep_alive = true;
|
||||
if (response!=null)
|
||||
_persistent=true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if (connection==null)
|
||||
connection=new StringBuilder();
|
||||
else
|
||||
connection.append(',');
|
||||
connection.append(split==null?field.getValue():split[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do NOT add yet!
|
||||
break;
|
||||
}
|
||||
|
||||
case SERVER:
|
||||
{
|
||||
send=send&~SEND_SERVER;
|
||||
|
@ -720,143 +696,91 @@ public class HttpGenerator
|
|||
}
|
||||
}
|
||||
|
||||
// Can we work out the content length?
|
||||
if (last && content_length<0)
|
||||
content_length = _contentPrepared+BufferUtil.length(content);
|
||||
|
||||
// Calculate how to end _content and connection, _content length and transfer encoding
|
||||
// settings.
|
||||
// From http://tools.ietf.org/html/rfc7230#section-3.3.3
|
||||
// From RFC 2616 4.4:
|
||||
// 1. No body for 1xx, 204, 304 & HEAD response
|
||||
// 3. If Transfer-Encoding==(.*,)?chunked && HTTP/1.1 && !HttpConnection==close then chunk
|
||||
// 5. Content-Length without Transfer-Encoding
|
||||
// 6. Request and none over the above, then Content-Length=0 if POST/PUT
|
||||
// 7. close
|
||||
// settings from http://tools.ietf.org/html/rfc7230#section-3.3.3
|
||||
|
||||
boolean assumed_content_request = request!=null && Boolean.TRUE.equals(__assumedContentMethods.get(request.getMethod()));
|
||||
boolean assumed_content = assumed_content_request || content_type || chunked;
|
||||
boolean nocontent_request = request!=null && content_length<=0 && !assumed_content;
|
||||
|
||||
int status=response!=null?response.getStatus():-1;
|
||||
switch (_endOfContent)
|
||||
// If the message is known not to have content
|
||||
if (_noContentResponse || nocontent_request)
|
||||
{
|
||||
case UNKNOWN_CONTENT:
|
||||
// It may be that we have no _content, or perhaps _content just has not been
|
||||
// written yet?
|
||||
|
||||
// Response known not to have a body
|
||||
if (_contentPrepared == 0 && response!=null && _noContent)
|
||||
// We don't need to indicate a body length
|
||||
_endOfContent=EndOfContent.NO_CONTENT;
|
||||
else if (_info.getContentLength()>0)
|
||||
{
|
||||
// we have been given a content length
|
||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
||||
if ((response!=null || content_length>0 || content_type ) && !_noContent)
|
||||
{
|
||||
// known length but not actually set.
|
||||
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
|
||||
BufferUtil.putDecLong(header, content_length);
|
||||
header.put(HttpTokens.CRLF);
|
||||
}
|
||||
}
|
||||
else if (last)
|
||||
{
|
||||
// we have seen all the _content there is, so we can be content-length limited.
|
||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
||||
long actual_length = _contentPrepared+BufferUtil.length(content);
|
||||
|
||||
if (content_length>=0 && content_length!=actual_length)
|
||||
throw new BadMessageException(500,"Content-Length header("+content_length+") != actual("+actual_length+")");
|
||||
|
||||
// Do we need to tell the headers about it
|
||||
putContentLength(header,actual_length,content_type,request,response);
|
||||
// But it is an error if there actually is content
|
||||
if (_contentPrepared>0 || content_length>0)
|
||||
{
|
||||
if (_contentPrepared==0 && last)
|
||||
{
|
||||
// TODO discard content for backward compatibility with 9.3 releases
|
||||
// TODO review if it is still needed in 9.4 or can we just throw.
|
||||
content.clear();
|
||||
content_length=0;
|
||||
}
|
||||
else
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Content for no content response");
|
||||
}
|
||||
}
|
||||
// Else if we are HTTP/1.1 and the content length is unknown and we are either persistent
|
||||
// or it is a request with content (which cannot EOF)
|
||||
else if (http11 && content_length<0 && (_persistent || assumed_content_request))
|
||||
{
|
||||
// No idea, so we must assume that a body is coming.
|
||||
// we use chunking
|
||||
_endOfContent = EndOfContent.CHUNKED_CONTENT;
|
||||
// HTTP 1.0 does not understand chunked content, so we must use EOF content.
|
||||
// For a request with HTTP 1.0 & Connection: keep-alive
|
||||
// we *must* close the connection, otherwise the client
|
||||
// has no way to detect the end of the content.
|
||||
if (!isPersistent() || _info.getHttpVersion().ordinal() < HttpVersion.HTTP_1_1.ordinal())
|
||||
_endOfContent = EndOfContent.EOF_CONTENT;
|
||||
}
|
||||
break;
|
||||
chunked = true;
|
||||
|
||||
case CONTENT_LENGTH:
|
||||
{
|
||||
putContentLength(header,content_length,content_type,request,response);
|
||||
break;
|
||||
}
|
||||
|
||||
case NO_CONTENT:
|
||||
throw new BadMessageException(500);
|
||||
|
||||
case EOF_CONTENT:
|
||||
_persistent = request!=null;
|
||||
break;
|
||||
|
||||
case CHUNKED_CONTENT:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Add transfer_encoding if needed
|
||||
if (isChunking())
|
||||
{
|
||||
// try to use user supplied encoding as it may have other values.
|
||||
if (transfer_encoding != null && !HttpHeaderValue.CHUNKED.toString().equalsIgnoreCase(transfer_encoding.getValue()))
|
||||
{
|
||||
String c = transfer_encoding.getValue();
|
||||
if (c.endsWith(HttpHeaderValue.CHUNKED.toString()))
|
||||
putTo(transfer_encoding,header);
|
||||
else
|
||||
throw new BadMessageException(500,"BAD TE");
|
||||
}
|
||||
else
|
||||
if (transfer_encoding == null)
|
||||
header.put(TRANSFER_ENCODING_CHUNKED);
|
||||
}
|
||||
|
||||
// Handle connection if need be
|
||||
if (_endOfContent==EndOfContent.EOF_CONTENT)
|
||||
else if (transfer_encoding.toString().endsWith(HttpHeaderValue.CHUNKED.toString()))
|
||||
{
|
||||
keep_alive=false;
|
||||
putTo(transfer_encoding,header);
|
||||
transfer_encoding = null;
|
||||
}
|
||||
else
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"BAD TE");
|
||||
}
|
||||
// Else if we known the content length and are a request or a persistent response,
|
||||
else if (content_length>=0 && (request!=null || _persistent))
|
||||
{
|
||||
// Use the content length
|
||||
_endOfContent = EndOfContent.CONTENT_LENGTH;
|
||||
putContentLength(header,content_length);
|
||||
}
|
||||
// Else if we are a response
|
||||
else if (response!=null)
|
||||
{
|
||||
// We can use EOF
|
||||
_endOfContent = EndOfContent.EOF_CONTENT;
|
||||
_persistent=false;
|
||||
}
|
||||
if (content_length>=0 && ( content_length> 0 || assumed_content || content_length_field ))
|
||||
putContentLength(header,content_length);
|
||||
|
||||
// If this is a response, work out persistence
|
||||
if (response!=null)
|
||||
{
|
||||
if (!isPersistent() && (close || _info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal()))
|
||||
{
|
||||
if (connection==null)
|
||||
if (http11 && !close)
|
||||
header.put(CONNECTION_CLOSE);
|
||||
}
|
||||
// Else we must be a request
|
||||
else
|
||||
{
|
||||
header.put(CONNECTION_CLOSE,0,CONNECTION_CLOSE.length-2);
|
||||
header.put((byte)',');
|
||||
header.put(StringUtil.getBytes(connection.toString()));
|
||||
header.put(CRLF);
|
||||
}
|
||||
}
|
||||
else if (keep_alive)
|
||||
{
|
||||
if (connection==null)
|
||||
header.put(CONNECTION_KEEP_ALIVE);
|
||||
else
|
||||
{
|
||||
header.put(CONNECTION_KEEP_ALIVE,0,CONNECTION_KEEP_ALIVE.length-2);
|
||||
header.put((byte)',');
|
||||
header.put(StringUtil.getBytes(connection.toString()));
|
||||
header.put(CRLF);
|
||||
}
|
||||
}
|
||||
else if (connection!=null)
|
||||
{
|
||||
header.put(HttpHeader.CONNECTION.getBytesColonSpace());
|
||||
header.put(StringUtil.getBytes(connection.toString()));
|
||||
header.put(CRLF);
|
||||
}
|
||||
// with no way to indicate body length
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Unknown content length for request");
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(_endOfContent.toString());
|
||||
|
||||
// Add transfer encoding if it is not chunking
|
||||
if (transfer_encoding!=null && !chunked)
|
||||
putTo(transfer_encoding,header);
|
||||
|
||||
// Send server?
|
||||
int status=response!=null?response.getStatus():-1;
|
||||
if (status>199)
|
||||
header.put(SEND[send]);
|
||||
|
||||
|
@ -865,19 +789,16 @@ public class HttpGenerator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
private void putContentLength(ByteBuffer header, long contentLength, boolean contentType, MetaData.Request request, MetaData.Response response)
|
||||
private static void putContentLength(ByteBuffer header,long contentLength)
|
||||
{
|
||||
if (contentLength>0)
|
||||
if (contentLength==0)
|
||||
header.put(CONTENT_LENGTH_0);
|
||||
else
|
||||
{
|
||||
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
|
||||
BufferUtil.putDecLong(header, contentLength);
|
||||
header.put(HttpTokens.CRLF);
|
||||
}
|
||||
else if (!_noContent)
|
||||
{
|
||||
if (contentType || response!=null || (request!=null && __assumedContentMethods.contains(request.getMethod())))
|
||||
header.put(CONTENT_LENGTH_0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
@ -905,10 +826,8 @@ public class HttpGenerator
|
|||
// common _content
|
||||
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[] CONNECTION_KEEP_ALIVE = StringUtil.getBytes("Connection: keep-alive\015\012");
|
||||
private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012");
|
||||
private static final byte[] HTTP_1_1_SPACE = StringUtil.getBytes(HttpVersion.HTTP_1_1+" ");
|
||||
private static final byte[] CRLF = StringUtil.getBytes("\015\012");
|
||||
private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012");
|
||||
private static final byte[][] SEND = new byte[][]{
|
||||
new byte[0],
|
||||
|
|
|
@ -225,8 +225,8 @@ public class MetaData implements Iterable<HttpField>
|
|||
public String toString()
|
||||
{
|
||||
HttpFields fields = getFields();
|
||||
return String.format("%s{u=%s,%s,h=%d}",
|
||||
getMethod(), getURI(), getHttpVersion(), fields == null ? -1 : fields.size());
|
||||
return String.format("%s{u=%s,%s,h=%d,cl=%d}",
|
||||
getMethod(), getURI(), getHttpVersion(), fields == null ? -1 : fields.size(), getContentLength());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -300,7 +300,7 @@ public class MetaData implements Iterable<HttpField>
|
|||
public String toString()
|
||||
{
|
||||
HttpFields fields = getFields();
|
||||
return String.format("%s{s=%d,h=%d}", getHttpVersion(), getStatus(), fields == null ? -1 : fields.size());
|
||||
return String.format("%s{s=%d,h=%d,cl=%d}", getHttpVersion(), getStatus(), fields == null ? -1 : fields.size(), getContentLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.http;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -27,6 +28,7 @@ import static org.junit.Assert.assertThat;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -229,7 +231,7 @@ public class HttpGeneratorServerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testResponseNoContent() throws Exception
|
||||
public void testResponseIncorrectContentLength() throws Exception
|
||||
{
|
||||
ByteBuffer header = BufferUtil.allocate(8096);
|
||||
|
||||
|
@ -239,7 +241,36 @@ public class HttpGeneratorServerTest
|
|||
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);
|
||||
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 10);
|
||||
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
|
||||
info.getFields().add("Content-Length", "11");
|
||||
|
||||
result = gen.generateResponse(info, null, null, null, true);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
|
||||
|
||||
try
|
||||
{
|
||||
gen.generateResponse(info, header, null, null, true);
|
||||
Assert.fail();
|
||||
}
|
||||
catch(BadMessageException e)
|
||||
{
|
||||
assertEquals(e._code,500);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseNoContentPersistent() throws Exception
|
||||
{
|
||||
ByteBuffer header = BufferUtil.allocate(8096);
|
||||
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result result = gen.generateResponse(null, 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(), 0);
|
||||
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
|
||||
|
||||
result = gen.generateResponse(info, null, null, null, true);
|
||||
|
@ -261,6 +292,40 @@ public class HttpGeneratorServerTest
|
|||
assertThat(head, containsString("Content-Length: 0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseKnownNoContentNotPersistent() throws Exception
|
||||
{
|
||||
ByteBuffer header = BufferUtil.allocate(8096);
|
||||
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result result = gen.generateResponse(null, 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(), 0);
|
||||
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
|
||||
info.getFields().add("Connection", "close");
|
||||
|
||||
result = gen.generateResponse(info, null, null, null, true);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
|
||||
|
||||
result = gen.generateResponse(info, header, null, null, true);
|
||||
assertEquals(HttpGenerator.Result.FLUSH, result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
|
||||
result = gen.generateResponse(null, null, null, null, false);
|
||||
assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result);
|
||||
assertEquals(HttpGenerator.State.END, gen.getState());
|
||||
|
||||
assertEquals(0, gen.getContentPrepared());
|
||||
assertThat(head, containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(head, containsString("Connection: close"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseUpgrade() throws Exception
|
||||
{
|
||||
|
@ -344,19 +409,23 @@ public class HttpGeneratorServerTest
|
|||
assertEquals(HttpGenerator.Result.DONE, 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, containsString("\r\n\r\nD\r\n"));
|
||||
assertThat(out, containsString("\r\nHello World! \r\n"));
|
||||
assertThat(out, containsString("\r\n2E\r\n"));
|
||||
assertThat(out, containsString("\r\nThe quick brown fox jumped over the lazy dog. \r\n"));
|
||||
assertThat(out, containsString("\r\n0\r\n"));
|
||||
|
||||
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"+
|
||||
"\r\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseWithKnownContent() throws Exception
|
||||
public void testResponseWithKnownContentLengthFromMetaData() throws Exception
|
||||
{
|
||||
ByteBuffer header = BufferUtil.allocate(4096);
|
||||
ByteBuffer content0 = BufferUtil.toBuffer("Hello World! ");
|
||||
|
@ -403,6 +472,58 @@ public class HttpGeneratorServerTest
|
|||
assertThat(out, containsString("\r\n\r\nHello World! The quick brown fox jumped over the lazy dog. "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseWithKnownContentLengthFromHeader() throws Exception
|
||||
{
|
||||
ByteBuffer header = 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();
|
||||
|
||||
HttpGenerator.Result result = gen.generateResponse(null, 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("Content-Length",""+(content0.remaining()+content1.remaining()));
|
||||
result = gen.generateResponse(info, null, null, content0, false);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
|
||||
assertEquals(HttpGenerator.State.START, gen.getState());
|
||||
|
||||
result = gen.generateResponse(info, 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, null, null, content1, false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH, result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
|
||||
out += BufferUtil.toString(content1);
|
||||
BufferUtil.clear(content1);
|
||||
|
||||
result = gen.generateResponse(null, null, null, null, true);
|
||||
assertEquals(HttpGenerator.Result.CONTINUE, result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
|
||||
|
||||
result = gen.generateResponse(null, null, null, null, true);
|
||||
assertEquals(HttpGenerator.Result.DONE, 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("chunked")));
|
||||
assertThat(out, containsString("Content-Length: 59"));
|
||||
assertThat(out, containsString("\r\n\r\nHello World! The quick brown fox jumped over the lazy dog. "));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void test100ThenResponseWithContent() throws Exception
|
||||
{
|
||||
|
|
|
@ -215,14 +215,20 @@ public class HttpTester
|
|||
|
||||
ByteBuffer buffer = in.getBuffer();
|
||||
|
||||
int len=0;
|
||||
while(len>=0)
|
||||
while(true)
|
||||
{
|
||||
if (BufferUtil.hasContent(buffer))
|
||||
if (parser.parseNext(buffer))
|
||||
break;
|
||||
if (in.fillBuffer()<=0)
|
||||
int len=in.fillBuffer();
|
||||
if (len==0)
|
||||
break;
|
||||
if (len<=0)
|
||||
{
|
||||
parser.atEOF();
|
||||
parser.parseNext(buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (r.isComplete())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.alpn.LEVEL=DEBUG
|
||||
org.eclipse.jetty.http2.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.alpn.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.http2.LEVEL=DEBUG
|
||||
|
|
|
@ -257,8 +257,11 @@ public class ProxyServletFailureTest
|
|||
public void testProxyRequestStallsContentServerIdlesTimeout() throws Exception
|
||||
{
|
||||
final byte[] content = new byte[]{'C', '0', 'F', 'F', 'E', 'E'};
|
||||
int expected = -1;
|
||||
if (proxyServlet instanceof AsyncProxyServlet)
|
||||
{
|
||||
// TODO should this be a 502 also???
|
||||
expected = 500;
|
||||
proxyServlet = new AsyncProxyServlet()
|
||||
{
|
||||
@Override
|
||||
|
@ -281,6 +284,7 @@ public class ProxyServletFailureTest
|
|||
}
|
||||
else
|
||||
{
|
||||
expected = 502;
|
||||
proxyServlet = new ProxyServlet()
|
||||
{
|
||||
@Override
|
||||
|
@ -310,7 +314,7 @@ public class ProxyServletFailureTest
|
|||
.content(new BytesContentProvider(content))
|
||||
.send();
|
||||
|
||||
Assert.assertEquals(500, response.getStatus());
|
||||
Assert.assertEquals(expected, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -255,12 +255,13 @@ public class AsyncRequestReadTest
|
|||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(in.readLine(),containsString("Content-Length:"));
|
||||
assertThat(in.readLine(),containsString("Content-Length: 11"));
|
||||
assertThat(in.readLine(),containsString("Server:"));
|
||||
in.readLine();
|
||||
assertThat(in.readLine(),containsString("XXXXXXX"));
|
||||
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(in.readLine(),containsString("Connection: close"));
|
||||
assertThat(in.readLine(),containsString("Content-Length: 11"));
|
||||
assertThat(in.readLine(),containsString("Server:"));
|
||||
in.readLine();
|
||||
assertThat(in.readLine(),containsString("XXXXXXX"));
|
||||
|
|
|
@ -266,6 +266,51 @@ public class HttpConnectionTest
|
|||
checkContains(response,offset,"/R1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyNotPersistent() throws Exception
|
||||
{
|
||||
String response=connector.getResponse("GET /R1?empty=true HTTP/1.0\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"\r\n");
|
||||
|
||||
int offset=0;
|
||||
offset = checkContains(response,offset,"HTTP/1.1 200");
|
||||
checkNotContained(response,offset,"Content-Length");
|
||||
|
||||
response=connector.getResponse("GET /R1?empty=true HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n");
|
||||
|
||||
offset=0;
|
||||
offset = checkContains(response,offset,"HTTP/1.1 200");
|
||||
checkContains(response,offset,"Connection: close");
|
||||
checkNotContained(response,offset,"Content-Length");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyPersistent() throws Exception
|
||||
{
|
||||
String response=connector.getResponse("GET /R1?empty=true HTTP/1.0\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Connection: keep-alive\r\n"+
|
||||
"\r\n");
|
||||
|
||||
int offset=0;
|
||||
offset = checkContains(response,offset,"HTTP/1.1 200");
|
||||
checkContains(response,offset,"Content-Length: 0");
|
||||
checkNotContained(response,offset,"Connection: close");
|
||||
|
||||
response=connector.getResponse("GET /R1?empty=true HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"\r\n");
|
||||
|
||||
offset=0;
|
||||
offset = checkContains(response,offset,"HTTP/1.1 200");
|
||||
checkContains(response,offset,"Content-Length: 0");
|
||||
checkNotContained(response,offset,"Connection: close");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyChunk() throws Exception
|
||||
{
|
||||
|
|
|
@ -132,6 +132,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
SimpleHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if (HttpVersion.HTTP_1_1.asString().equals(httpVersion))
|
||||
assertHeader(response, "content-length", "0");
|
||||
assertThat("no exceptions", handler.failure(), is(nullValue()));
|
||||
}
|
||||
|
|
|
@ -102,6 +102,8 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
SimpleHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
|
||||
if (HttpVersion.HTTP_1_1.asString().equals(httpVersion))
|
||||
assertHeader(response, "content-length", "0");
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ import org.eclipse.jetty.http.HttpTester;
|
|||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
|
@ -55,7 +57,10 @@ public class HttpVersionCustomizerTest
|
|||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(500);
|
||||
Assert.assertEquals(HttpVersion.HTTP_1_1.asString(), request.getProtocol());
|
||||
response.setStatus(200);
|
||||
response.getWriter().println("OK");
|
||||
}
|
||||
});
|
||||
server.start();
|
||||
|
|
|
@ -1096,7 +1096,8 @@ public class RequestTest
|
|||
200, TimeUnit.MILLISECONDS
|
||||
);
|
||||
assertThat(response, Matchers.containsString("200"));
|
||||
assertThat(response, Matchers.containsString("Connection: TE,Other"));
|
||||
assertThat(response, Matchers.containsString("Connection: TE"));
|
||||
assertThat(response, Matchers.containsString("Connection: Other"));
|
||||
assertThat(response, Matchers.containsString("Hello World"));
|
||||
|
||||
response=_connector.getResponse(
|
||||
|
|
|
@ -85,8 +85,18 @@ public class SSLEngineTest
|
|||
private static final String REQUEST1=REQUEST1_HEADER+REQUEST_CONTENT.getBytes().length+"\n\n"+REQUEST_CONTENT;
|
||||
|
||||
/** The expected response. */
|
||||
private static final String RESPONSE0="HTTP/1.1 200 OK\n"+"Content-Length: "+HELLO_WORLD.length()+"\n"+"Server: Jetty("+JETTY_VERSION+")\n"+'\n'+HELLO_WORLD;
|
||||
private static final String RESPONSE1="HTTP/1.1 200 OK\n"+"Connection: close\n"+"Server: Jetty("+JETTY_VERSION+")\n"+'\n'+HELLO_WORLD;
|
||||
private static final String RESPONSE0="HTTP/1.1 200 OK\n"+
|
||||
"Content-Length: "+HELLO_WORLD.length()+"\n"+
|
||||
"Server: Jetty("+JETTY_VERSION+")\n"+
|
||||
'\n'+
|
||||
HELLO_WORLD;
|
||||
|
||||
private static final String RESPONSE1="HTTP/1.1 200 OK\n"+
|
||||
"Connection: close\n"+
|
||||
"Content-Length: "+HELLO_WORLD.length()+"\n"+
|
||||
"Server: Jetty("+JETTY_VERSION+")\n"+
|
||||
'\n'+
|
||||
HELLO_WORLD;
|
||||
|
||||
private static final int BODY_SIZE=300;
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
|
@ -169,9 +168,7 @@ public class AsyncContextTest
|
|||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||
|
||||
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
||||
br.readLine();// connection close
|
||||
br.readLine();// server
|
||||
br.readLine();// empty
|
||||
readHeader(br);
|
||||
Assert.assertEquals("ERROR: /error", br.readLine());
|
||||
Assert.assertEquals("PathInfo= /IOE", br.readLine());
|
||||
Assert.assertEquals("EXCEPTION: org.eclipse.jetty.server.QuietServletException: java.io.IOException: Test", br.readLine());
|
||||
|
@ -192,9 +189,7 @@ public class AsyncContextTest
|
|||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||
|
||||
assertEquals("HTTP/1.1 200 OK",br.readLine());
|
||||
br.readLine();// connection close
|
||||
br.readLine();// server
|
||||
br.readLine();// empty
|
||||
readHeader(br);
|
||||
|
||||
Assert.assertEquals("error servlet","completeBeforeThrow",br.readLine());
|
||||
}
|
||||
|
@ -273,10 +268,15 @@ public class AsyncContextTest
|
|||
@Test
|
||||
public void testDispatch() throws Exception
|
||||
{
|
||||
String request = "GET /ctx/forward HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Connection: close\r\n"
|
||||
+ "\r\n";
|
||||
String request =
|
||||
"GET /ctx/forward HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
|
||||
String responseString = _connector.getResponses(request);
|
||||
String responseString = _connector.getResponse(request);
|
||||
System.err.println(responseString);
|
||||
BufferedReader br = parseHeader(responseString);
|
||||
assertThat("!ForwardingServlet", br.readLine(), equalTo("Dispatched back to ForwardingServlet"));
|
||||
}
|
||||
|
@ -300,15 +300,18 @@ public class AsyncContextTest
|
|||
private BufferedReader parseHeader(String responseString) throws IOException
|
||||
{
|
||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||
|
||||
assertEquals("HTTP/1.1 200 OK", br.readLine());
|
||||
|
||||
br.readLine();// connection close
|
||||
br.readLine();// server
|
||||
br.readLine();// empty
|
||||
readHeader(br);
|
||||
return br;
|
||||
}
|
||||
|
||||
private void readHeader(BufferedReader br) throws IOException
|
||||
{
|
||||
String line = br.readLine();
|
||||
while (line!=null && !line.isEmpty())
|
||||
line = br.readLine();
|
||||
}
|
||||
|
||||
private class ForwardingServlet extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -371,11 +374,7 @@ public class AsyncContextTest
|
|||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||
|
||||
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
||||
|
||||
br.readLine();// connection close
|
||||
br.readLine();// server
|
||||
br.readLine();// empty
|
||||
|
||||
readHeader(br);
|
||||
Assert.assertEquals("error servlet", "ERROR: /error", br.readLine());
|
||||
}
|
||||
|
||||
|
@ -392,9 +391,7 @@ public class AsyncContextTest
|
|||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||
|
||||
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
||||
br.readLine();// connection close
|
||||
br.readLine();// server
|
||||
br.readLine();// empty
|
||||
readHeader(br);
|
||||
|
||||
Assert.assertEquals("error servlet", "ERROR: /error", br.readLine());
|
||||
Assert.assertEquals("error servlet", "PathInfo= /500", br.readLine());
|
||||
|
|
|
@ -115,7 +115,6 @@ public class DefaultServletRangesTest
|
|||
"\r\n");
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Type: text/plain", response);
|
||||
assertResponseContains("Content-Length: 10", response);
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
assertResponseContains(DATA.substring(0,10), response);
|
||||
}
|
||||
|
@ -133,7 +132,6 @@ public class DefaultServletRangesTest
|
|||
"\r\n");
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Type: text/plain", response);
|
||||
assertResponseContains("Content-Length: 7", response);
|
||||
assertResponseContains("Content-Range: bytes 3-9/80", response);
|
||||
assertResponseContains(DATA.substring(3,10), response);
|
||||
}
|
||||
|
@ -156,7 +154,6 @@ public class DefaultServletRangesTest
|
|||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||
assertResponseContains("Content-Range: bytes 40-49/80", response);
|
||||
assertResponseContains("Content-Length: " + body.length(), response);
|
||||
assertResponseContains(DATA.substring(0,10), response);
|
||||
assertResponseContains(DATA.substring(20,30), response);
|
||||
assertResponseContains(DATA.substring(40,50), response);
|
||||
|
@ -177,7 +174,6 @@ public class DefaultServletRangesTest
|
|||
assertResponseContains("206 Partial", response);
|
||||
assertResponseNotContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||
assertResponseContains("Content-Range: bytes 20-79/80", response);
|
||||
assertResponseContains("Content-Length: 60", response);
|
||||
assertResponseContains(DATA.substring(60), response);
|
||||
}
|
||||
|
||||
|
@ -194,7 +190,6 @@ public class DefaultServletRangesTest
|
|||
assertResponseContains("206 Partial", response);
|
||||
assertResponseNotContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||
assertResponseContains("Content-Range: bytes 60-79/80", response); // yes the spec says it is these bytes
|
||||
assertResponseContains("Content-Length: 20", response);
|
||||
assertResponseContains(DATA.substring(60), response);
|
||||
}
|
||||
|
||||
|
|
|
@ -591,7 +591,6 @@ public class DefaultServletTest
|
|||
|
||||
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9\r\n" +
|
||||
"\r\n");
|
||||
assertResponseContains("206 Partial", response);
|
||||
|
@ -599,10 +598,17 @@ public class DefaultServletTest
|
|||
assertResponseContains("Content-Length: 10", response);
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
|
||||
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Range: bytes=0-9\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n");
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Type: text/plain", response);
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
|
||||
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49\r\n" +
|
||||
"\r\n");
|
||||
int start = response.indexOf("--jetty");
|
||||
|
@ -617,7 +623,6 @@ public class DefaultServletTest
|
|||
|
||||
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49,70-79\r\n" +
|
||||
"\r\n");
|
||||
start = response.indexOf("--jetty");
|
||||
|
@ -633,7 +638,6 @@ public class DefaultServletTest
|
|||
|
||||
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
||||
"\r\n");
|
||||
start = response.indexOf("--jetty");
|
||||
|
@ -655,7 +659,6 @@ public class DefaultServletTest
|
|||
|
||||
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"\r\n");
|
||||
assertResponseContains("200 OK", response);
|
||||
assertResponseContains("Accept-Ranges: bytes", response);
|
||||
|
@ -664,7 +667,6 @@ public class DefaultServletTest
|
|||
|
||||
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9\r\n" +
|
||||
"\r\n");
|
||||
assertResponseContains("206 Partial", response);
|
||||
|
@ -674,7 +676,6 @@ public class DefaultServletTest
|
|||
|
||||
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49\r\n" +
|
||||
"\r\n");
|
||||
start = response.indexOf("--jetty");
|
||||
|
@ -687,11 +688,8 @@ public class DefaultServletTest
|
|||
assertResponseContains("Content-Length: " + body.length(), response);
|
||||
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||
|
||||
|
||||
|
||||
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
||||
"\r\n");
|
||||
start = response.indexOf("--jetty");
|
||||
|
|
|
@ -165,7 +165,6 @@ public class DispatcherTest
|
|||
|
||||
String expected=
|
||||
"HTTP/1.1 200 OK\r\n"+
|
||||
"Content-Length: 0\r\n"+
|
||||
"\r\n";
|
||||
|
||||
String responses = _connector.getResponses("GET /context/IncludeServlet?do=assertinclude&do=more&test=1 HTTP/1.0\n\n");
|
||||
|
@ -182,7 +181,6 @@ public class DispatcherTest
|
|||
|
||||
String expected=
|
||||
"HTTP/1.1 200 OK\r\n"+
|
||||
"Content-Length: 0\r\n"+
|
||||
"\r\n";
|
||||
|
||||
String responses = _connector.getResponses("GET /context/ForwardServlet/forwardpath?do=include HTTP/1.0\n\n");
|
||||
|
|
|
@ -1040,9 +1040,6 @@ public class MultipartFilterTest
|
|||
public void testWithCharSet()
|
||||
throws Exception
|
||||
{
|
||||
((StdErrLog)Log.getLogger(MultiPartFilter.class)).setDebugEnabled(true);
|
||||
((StdErrLog)Log.getLogger(MultiPartInputStreamParser.class)).setDebugEnabled(true);
|
||||
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
|
|
Loading…
Reference in New Issue