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.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.LEVEL=INFO
|
||||||
|
|
||||||
org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
|
# org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
|
||||||
|
|
||||||
# org.eclipse.jetty.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
|
# 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.TestTracker;
|
||||||
import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
||||||
import org.eclipse.jetty.util.Promise;
|
import org.eclipse.jetty.util.Promise;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -258,7 +259,7 @@ public class HttpSenderOverHTTPTest
|
||||||
|
|
||||||
String requestString = endPoint.takeOutputString();
|
String requestString = endPoint.takeOutputString();
|
||||||
Assert.assertTrue(requestString.startsWith("GET "));
|
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(headersLatch.await(5, TimeUnit.SECONDS));
|
||||||
Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,16 +18,18 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.http;
|
package org.eclipse.jetty.http;
|
||||||
|
|
||||||
|
import static org.eclipse.jetty.http.HttpStatus.INTERNAL_SERVER_ERROR_500;
|
||||||
|
|
||||||
import java.io.IOException;
|
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.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
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.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
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.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
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");
|
public final static boolean __STRICT=Boolean.getBoolean("org.eclipse.jetty.http.HttpGenerator.STRICT");
|
||||||
|
|
||||||
private final static byte[] __colon_space = new byte[] {':',' '};
|
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 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 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 =
|
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
|
// states
|
||||||
public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END }
|
public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END }
|
||||||
|
@ -63,13 +64,18 @@ public class HttpGenerator
|
||||||
private EndOfContent _endOfContent = EndOfContent.UNKNOWN_CONTENT;
|
private EndOfContent _endOfContent = EndOfContent.UNKNOWN_CONTENT;
|
||||||
|
|
||||||
private long _contentPrepared = 0;
|
private long _contentPrepared = 0;
|
||||||
private boolean _noContent = false;
|
private boolean _noContentResponse = false;
|
||||||
private Boolean _persistent = null;
|
private Boolean _persistent = null;
|
||||||
|
|
||||||
private final int _send;
|
private final int _send;
|
||||||
private final static int SEND_SERVER = 0x01;
|
private final static int SEND_SERVER = 0x01;
|
||||||
private final static int SEND_XPOWEREDBY = 0x02;
|
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)
|
public static void setJettyVersion(String serverVersion)
|
||||||
|
@ -101,7 +107,7 @@ public class HttpGenerator
|
||||||
{
|
{
|
||||||
_state = State.START;
|
_state = State.START;
|
||||||
_endOfContent = EndOfContent.UNKNOWN_CONTENT;
|
_endOfContent = EndOfContent.UNKNOWN_CONTENT;
|
||||||
_noContent=false;
|
_noContentResponse=false;
|
||||||
_persistent = null;
|
_persistent = null;
|
||||||
_contentPrepared = 0;
|
_contentPrepared = 0;
|
||||||
_needCRLF = false;
|
_needCRLF = false;
|
||||||
|
@ -160,7 +166,7 @@ public class HttpGenerator
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public boolean isNoContent()
|
public boolean isNoContent()
|
||||||
{
|
{
|
||||||
return _noContent;
|
return _noContentResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -227,7 +233,7 @@ public class HttpGenerator
|
||||||
generateRequestLine(info,header);
|
generateRequestLine(info,header);
|
||||||
|
|
||||||
if (info.getHttpVersion()==HttpVersion.HTTP_0_9)
|
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);
|
generateHeaders(info,header,content,last);
|
||||||
|
|
||||||
|
@ -252,10 +258,17 @@ public class HttpGenerator
|
||||||
|
|
||||||
return Result.FLUSH;
|
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)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
String message= (e instanceof BufferOverflowException)?"Request header too large":e.getMessage();
|
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,e.getMessage(),e);
|
||||||
throw new BadMessageException(500,message,e);
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -344,7 +357,7 @@ public class HttpGenerator
|
||||||
return Result.NEED_INFO;
|
return Result.NEED_INFO;
|
||||||
HttpVersion version=info.getHttpVersion();
|
HttpVersion version=info.getHttpVersion();
|
||||||
if (version==null)
|
if (version==null)
|
||||||
throw new BadMessageException(500,"No version");
|
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"No version");
|
||||||
switch(version)
|
switch(version)
|
||||||
{
|
{
|
||||||
case HTTP_1_0:
|
case HTTP_1_0:
|
||||||
|
@ -381,7 +394,7 @@ public class HttpGenerator
|
||||||
int status=info.getStatus();
|
int status=info.getStatus();
|
||||||
if (status>=100 && status<200 )
|
if (status>=100 && status<200 )
|
||||||
{
|
{
|
||||||
_noContent=true;
|
_noContentResponse=true;
|
||||||
|
|
||||||
if (status!=HttpStatus.SWITCHING_PROTOCOLS_101 )
|
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)
|
else if (status==HttpStatus.NO_CONTENT_204 || status==HttpStatus.NOT_MODIFIED_304)
|
||||||
{
|
{
|
||||||
_noContent=true;
|
_noContentResponse=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
generateHeaders(info,header,content,last);
|
generateHeaders(info,header,content,last);
|
||||||
|
@ -407,10 +420,17 @@ public class HttpGenerator
|
||||||
}
|
}
|
||||||
_state = last?State.COMPLETING:State.COMMITTED;
|
_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)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
String message= (e instanceof BufferOverflowException)?"Response header too large":e.getMessage();
|
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,e.getMessage(),e);
|
||||||
throw new BadMessageException(500,message,e);
|
|
||||||
}
|
}
|
||||||
finally
|
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.Request request=(info instanceof MetaData.Request)?(MetaData.Request)info:null;
|
||||||
final MetaData.Response response=(_info instanceof MetaData.Response)?(MetaData.Response)_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
|
// default field values
|
||||||
int send=_send;
|
int send=_send;
|
||||||
HttpField transfer_encoding=null;
|
HttpField transfer_encoding=null;
|
||||||
boolean keep_alive=false;
|
boolean http11 = info.getHttpVersion() == HttpVersion.HTTP_1_1;
|
||||||
boolean close = false;
|
boolean close = false;
|
||||||
|
boolean chunked = false;
|
||||||
boolean content_type = 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
|
// Generate fields
|
||||||
HttpFields fields = _info.getFields();
|
HttpFields fields = info.getFields();
|
||||||
if (fields != null)
|
if (fields != null)
|
||||||
{
|
{
|
||||||
int n=fields.size();
|
int n=fields.size();
|
||||||
|
@ -612,10 +639,11 @@ public class HttpGenerator
|
||||||
switch (h)
|
switch (h)
|
||||||
{
|
{
|
||||||
case CONTENT_LENGTH:
|
case CONTENT_LENGTH:
|
||||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
|
||||||
if (content_length<0)
|
if (content_length<0)
|
||||||
content_length=Long.valueOf(field.getValue());
|
content_length = field.getLongValue();
|
||||||
// handle setting the field specially below
|
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;
|
break;
|
||||||
|
|
||||||
case CONTENT_TYPE:
|
case CONTENT_TYPE:
|
||||||
|
@ -628,84 +656,32 @@ public class HttpGenerator
|
||||||
|
|
||||||
case TRANSFER_ENCODING:
|
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;
|
transfer_encoding = field;
|
||||||
// Do NOT add yet!
|
chunked = field.contains(HttpHeaderValue.CHUNKED.asString());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case CONNECTION:
|
case CONNECTION:
|
||||||
{
|
{
|
||||||
if (request!=null)
|
|
||||||
putTo(field,header);
|
putTo(field,header);
|
||||||
|
if (field.contains(HttpHeaderValue.CLOSE.asString()))
|
||||||
// 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:
|
|
||||||
{
|
{
|
||||||
close=true;
|
close=true;
|
||||||
_persistent=false;
|
_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;
|
_persistent=true;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case SERVER:
|
||||||
{
|
{
|
||||||
send=send&~SEND_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
|
// Calculate how to end _content and connection, _content length and transfer encoding
|
||||||
// settings.
|
// settings from http://tools.ietf.org/html/rfc7230#section-3.3.3
|
||||||
// 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
|
|
||||||
|
|
||||||
|
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;
|
// If the message is known not to have content
|
||||||
switch (_endOfContent)
|
if (_noContentResponse || nocontent_request)
|
||||||
{
|
{
|
||||||
case UNKNOWN_CONTENT:
|
// We don't need to indicate a body length
|
||||||
// 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)
|
|
||||||
_endOfContent=EndOfContent.NO_CONTENT;
|
_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)
|
// But it is an error if there actually is content
|
||||||
throw new BadMessageException(500,"Content-Length header("+content_length+") != actual("+actual_length+")");
|
if (_contentPrepared>0 || content_length>0)
|
||||||
|
{
|
||||||
// Do we need to tell the headers about it
|
if (_contentPrepared==0 && last)
|
||||||
putContentLength(header,actual_length,content_type,request,response);
|
{
|
||||||
|
// 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
|
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;
|
_endOfContent = EndOfContent.CHUNKED_CONTENT;
|
||||||
// HTTP 1.0 does not understand chunked content, so we must use EOF content.
|
chunked = true;
|
||||||
// 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;
|
|
||||||
|
|
||||||
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.
|
// try to use user supplied encoding as it may have other values.
|
||||||
if (transfer_encoding != null && !HttpHeaderValue.CHUNKED.toString().equalsIgnoreCase(transfer_encoding.getValue()))
|
if (transfer_encoding == null)
|
||||||
{
|
|
||||||
String c = transfer_encoding.getValue();
|
|
||||||
if (c.endsWith(HttpHeaderValue.CHUNKED.toString()))
|
|
||||||
putTo(transfer_encoding,header);
|
|
||||||
else
|
|
||||||
throw new BadMessageException(500,"BAD TE");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
header.put(TRANSFER_ENCODING_CHUNKED);
|
header.put(TRANSFER_ENCODING_CHUNKED);
|
||||||
}
|
else if (transfer_encoding.toString().endsWith(HttpHeaderValue.CHUNKED.toString()))
|
||||||
|
|
||||||
// Handle connection if need be
|
|
||||||
if (_endOfContent==EndOfContent.EOF_CONTENT)
|
|
||||||
{
|
{
|
||||||
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;
|
_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 (http11 && !close)
|
||||||
if (response!=null)
|
|
||||||
{
|
|
||||||
if (!isPersistent() && (close || _info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal()))
|
|
||||||
{
|
|
||||||
if (connection==null)
|
|
||||||
header.put(CONNECTION_CLOSE);
|
header.put(CONNECTION_CLOSE);
|
||||||
|
}
|
||||||
|
// Else we must be a request
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
header.put(CONNECTION_CLOSE,0,CONNECTION_CLOSE.length-2);
|
// with no way to indicate body length
|
||||||
header.put((byte)',');
|
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Unknown content length for request");
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
if (status>199)
|
||||||
header.put(SEND[send]);
|
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());
|
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
|
||||||
BufferUtil.putDecLong(header, contentLength);
|
BufferUtil.putDecLong(header, contentLength);
|
||||||
header.put(HttpTokens.CRLF);
|
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
|
// common _content
|
||||||
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_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[] 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[] 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[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012");
|
||||||
private static final byte[][] SEND = new byte[][]{
|
private static final byte[][] SEND = new byte[][]{
|
||||||
new byte[0],
|
new byte[0],
|
||||||
|
|
|
@ -225,8 +225,8 @@ public class MetaData implements Iterable<HttpField>
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
HttpFields fields = getFields();
|
HttpFields fields = getFields();
|
||||||
return String.format("%s{u=%s,%s,h=%d}",
|
return String.format("%s{u=%s,%s,h=%d,cl=%d}",
|
||||||
getMethod(), getURI(), getHttpVersion(), fields == null ? -1 : fields.size());
|
getMethod(), getURI(), getHttpVersion(), fields == null ? -1 : fields.size(), getContentLength());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ public class MetaData implements Iterable<HttpField>
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
HttpFields fields = getFields();
|
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;
|
package org.eclipse.jetty.http;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -27,6 +28,7 @@ import static org.junit.Assert.assertThat;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -229,7 +231,7 @@ public class HttpGeneratorServerTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseNoContent() throws Exception
|
public void testResponseIncorrectContentLength() throws Exception
|
||||||
{
|
{
|
||||||
ByteBuffer header = BufferUtil.allocate(8096);
|
ByteBuffer header = BufferUtil.allocate(8096);
|
||||||
|
|
||||||
|
@ -239,7 +241,36 @@ public class HttpGeneratorServerTest
|
||||||
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(), 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);
|
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
|
||||||
|
|
||||||
result = gen.generateResponse(info, null, null, null, true);
|
result = gen.generateResponse(info, null, null, null, true);
|
||||||
|
@ -261,6 +292,40 @@ public class HttpGeneratorServerTest
|
||||||
assertThat(head, containsString("Content-Length: 0"));
|
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
|
@Test
|
||||||
public void testResponseUpgrade() throws Exception
|
public void testResponseUpgrade() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -344,19 +409,23 @@ public class HttpGeneratorServerTest
|
||||||
assertEquals(HttpGenerator.Result.DONE, result);
|
assertEquals(HttpGenerator.Result.DONE, result);
|
||||||
assertEquals(HttpGenerator.State.END, gen.getState());
|
assertEquals(HttpGenerator.State.END, gen.getState());
|
||||||
|
|
||||||
|
|
||||||
assertThat(out, containsString("HTTP/1.1 200 OK"));
|
assertThat(out, containsString("HTTP/1.1 200 OK"));
|
||||||
assertThat(out, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
assertThat(out, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||||
assertThat(out, not(containsString("Content-Length")));
|
assertThat(out, not(containsString("Content-Length")));
|
||||||
assertThat(out, containsString("Transfer-Encoding: chunked"));
|
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, endsWith(
|
||||||
assertThat(out, containsString("\r\n2E\r\n"));
|
"\r\n\r\nD\r\n"+
|
||||||
assertThat(out, containsString("\r\nThe quick brown fox jumped over the lazy dog. \r\n"));
|
"Hello World! \r\n"+
|
||||||
assertThat(out, containsString("\r\n0\r\n"));
|
"2E\r\n"+
|
||||||
|
"The quick brown fox jumped over the lazy dog. \r\n"+
|
||||||
|
"0\r\n"+
|
||||||
|
"\r\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseWithKnownContent() throws Exception
|
public void testResponseWithKnownContentLengthFromMetaData() throws Exception
|
||||||
{
|
{
|
||||||
ByteBuffer header = BufferUtil.allocate(4096);
|
ByteBuffer header = BufferUtil.allocate(4096);
|
||||||
ByteBuffer content0 = BufferUtil.toBuffer("Hello World! ");
|
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. "));
|
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
|
@Test
|
||||||
public void test100ThenResponseWithContent() throws Exception
|
public void test100ThenResponseWithContent() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -215,14 +215,20 @@ public class HttpTester
|
||||||
|
|
||||||
ByteBuffer buffer = in.getBuffer();
|
ByteBuffer buffer = in.getBuffer();
|
||||||
|
|
||||||
int len=0;
|
while(true)
|
||||||
while(len>=0)
|
|
||||||
{
|
{
|
||||||
if (BufferUtil.hasContent(buffer))
|
if (BufferUtil.hasContent(buffer))
|
||||||
if (parser.parseNext(buffer))
|
if (parser.parseNext(buffer))
|
||||||
break;
|
break;
|
||||||
if (in.fillBuffer()<=0)
|
int len=in.fillBuffer();
|
||||||
|
if (len==0)
|
||||||
break;
|
break;
|
||||||
|
if (len<=0)
|
||||||
|
{
|
||||||
|
parser.atEOF();
|
||||||
|
parser.parseNext(buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.isComplete())
|
if (r.isComplete())
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||||
org.eclipse.jetty.alpn.LEVEL=DEBUG
|
# org.eclipse.jetty.alpn.LEVEL=DEBUG
|
||||||
org.eclipse.jetty.http2.LEVEL=DEBUG
|
# org.eclipse.jetty.http2.LEVEL=DEBUG
|
||||||
|
|
|
@ -257,8 +257,11 @@ public class ProxyServletFailureTest
|
||||||
public void testProxyRequestStallsContentServerIdlesTimeout() throws Exception
|
public void testProxyRequestStallsContentServerIdlesTimeout() throws Exception
|
||||||
{
|
{
|
||||||
final byte[] content = new byte[]{'C', '0', 'F', 'F', 'E', 'E'};
|
final byte[] content = new byte[]{'C', '0', 'F', 'F', 'E', 'E'};
|
||||||
|
int expected = -1;
|
||||||
if (proxyServlet instanceof AsyncProxyServlet)
|
if (proxyServlet instanceof AsyncProxyServlet)
|
||||||
{
|
{
|
||||||
|
// TODO should this be a 502 also???
|
||||||
|
expected = 500;
|
||||||
proxyServlet = new AsyncProxyServlet()
|
proxyServlet = new AsyncProxyServlet()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -281,6 +284,7 @@ public class ProxyServletFailureTest
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
expected = 502;
|
||||||
proxyServlet = new ProxyServlet()
|
proxyServlet = new ProxyServlet()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -310,7 +314,7 @@ public class ProxyServletFailureTest
|
||||||
.content(new BytesContentProvider(content))
|
.content(new BytesContentProvider(content))
|
||||||
.send();
|
.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()));
|
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
|
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:"));
|
assertThat(in.readLine(),containsString("Server:"));
|
||||||
in.readLine();
|
in.readLine();
|
||||||
assertThat(in.readLine(),containsString("XXXXXXX"));
|
assertThat(in.readLine(),containsString("XXXXXXX"));
|
||||||
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
|
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
|
||||||
assertThat(in.readLine(),containsString("Connection: close"));
|
assertThat(in.readLine(),containsString("Connection: close"));
|
||||||
|
assertThat(in.readLine(),containsString("Content-Length: 11"));
|
||||||
assertThat(in.readLine(),containsString("Server:"));
|
assertThat(in.readLine(),containsString("Server:"));
|
||||||
in.readLine();
|
in.readLine();
|
||||||
assertThat(in.readLine(),containsString("XXXXXXX"));
|
assertThat(in.readLine(),containsString("XXXXXXX"));
|
||||||
|
|
|
@ -266,6 +266,51 @@ public class HttpConnectionTest
|
||||||
checkContains(response,offset,"/R1");
|
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
|
@Test
|
||||||
public void testEmptyChunk() throws Exception
|
public void testEmptyChunk() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -132,6 +132,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
SimpleHttpResponse response = executeRequest();
|
SimpleHttpResponse response = executeRequest();
|
||||||
|
|
||||||
assertThat("response code is 200", response.getCode(), is("200"));
|
assertThat("response code is 200", response.getCode(), is("200"));
|
||||||
|
if (HttpVersion.HTTP_1_1.asString().equals(httpVersion))
|
||||||
assertHeader(response, "content-length", "0");
|
assertHeader(response, "content-length", "0");
|
||||||
assertThat("no exceptions", handler.failure(), is(nullValue()));
|
assertThat("no exceptions", handler.failure(), is(nullValue()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,8 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
SimpleHttpResponse response = executeRequest();
|
SimpleHttpResponse response = executeRequest();
|
||||||
|
|
||||||
assertThat("response code is 200", response.getCode(), is("200"));
|
assertThat("response code is 200", response.getCode(), is("200"));
|
||||||
|
|
||||||
|
if (HttpVersion.HTTP_1_1.asString().equals(httpVersion))
|
||||||
assertHeader(response, "content-length", "0");
|
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.http.HttpVersion;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
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.hamcrest.Matchers;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Rule;
|
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
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
|
response.setStatus(500);
|
||||||
Assert.assertEquals(HttpVersion.HTTP_1_1.asString(), request.getProtocol());
|
Assert.assertEquals(HttpVersion.HTTP_1_1.asString(), request.getProtocol());
|
||||||
|
response.setStatus(200);
|
||||||
|
response.getWriter().println("OK");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
server.start();
|
server.start();
|
||||||
|
|
|
@ -1096,7 +1096,8 @@ public class RequestTest
|
||||||
200, TimeUnit.MILLISECONDS
|
200, TimeUnit.MILLISECONDS
|
||||||
);
|
);
|
||||||
assertThat(response, Matchers.containsString("200"));
|
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"));
|
assertThat(response, Matchers.containsString("Hello World"));
|
||||||
|
|
||||||
response=_connector.getResponse(
|
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;
|
private static final String REQUEST1=REQUEST1_HEADER+REQUEST_CONTENT.getBytes().length+"\n\n"+REQUEST_CONTENT;
|
||||||
|
|
||||||
/** The expected response. */
|
/** 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 RESPONSE0="HTTP/1.1 200 OK\n"+
|
||||||
private static final String RESPONSE1="HTTP/1.1 200 OK\n"+"Connection: close\n"+"Server: Jetty("+JETTY_VERSION+")\n"+'\n'+HELLO_WORLD;
|
"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;
|
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.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpServletResponseWrapper;
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpParser;
|
|
||||||
import org.eclipse.jetty.server.Handler;
|
import org.eclipse.jetty.server.Handler;
|
||||||
import org.eclipse.jetty.server.HttpChannel;
|
import org.eclipse.jetty.server.HttpChannel;
|
||||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||||
|
@ -169,9 +168,7 @@ public class AsyncContextTest
|
||||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||||
|
|
||||||
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
||||||
br.readLine();// connection close
|
readHeader(br);
|
||||||
br.readLine();// server
|
|
||||||
br.readLine();// empty
|
|
||||||
Assert.assertEquals("ERROR: /error", br.readLine());
|
Assert.assertEquals("ERROR: /error", br.readLine());
|
||||||
Assert.assertEquals("PathInfo= /IOE", br.readLine());
|
Assert.assertEquals("PathInfo= /IOE", br.readLine());
|
||||||
Assert.assertEquals("EXCEPTION: org.eclipse.jetty.server.QuietServletException: java.io.IOException: Test", 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));
|
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||||
|
|
||||||
assertEquals("HTTP/1.1 200 OK",br.readLine());
|
assertEquals("HTTP/1.1 200 OK",br.readLine());
|
||||||
br.readLine();// connection close
|
readHeader(br);
|
||||||
br.readLine();// server
|
|
||||||
br.readLine();// empty
|
|
||||||
|
|
||||||
Assert.assertEquals("error servlet","completeBeforeThrow",br.readLine());
|
Assert.assertEquals("error servlet","completeBeforeThrow",br.readLine());
|
||||||
}
|
}
|
||||||
|
@ -273,10 +268,15 @@ public class AsyncContextTest
|
||||||
@Test
|
@Test
|
||||||
public void testDispatch() throws Exception
|
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"
|
String request =
|
||||||
+ "\r\n";
|
"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);
|
BufferedReader br = parseHeader(responseString);
|
||||||
assertThat("!ForwardingServlet", br.readLine(), equalTo("Dispatched back to ForwardingServlet"));
|
assertThat("!ForwardingServlet", br.readLine(), equalTo("Dispatched back to ForwardingServlet"));
|
||||||
}
|
}
|
||||||
|
@ -300,15 +300,18 @@ public class AsyncContextTest
|
||||||
private BufferedReader parseHeader(String responseString) throws IOException
|
private BufferedReader parseHeader(String responseString) throws IOException
|
||||||
{
|
{
|
||||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||||
|
|
||||||
assertEquals("HTTP/1.1 200 OK", br.readLine());
|
assertEquals("HTTP/1.1 200 OK", br.readLine());
|
||||||
|
readHeader(br);
|
||||||
br.readLine();// connection close
|
|
||||||
br.readLine();// server
|
|
||||||
br.readLine();// empty
|
|
||||||
return 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 class ForwardingServlet extends HttpServlet
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ -371,11 +374,7 @@ public class AsyncContextTest
|
||||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||||
|
|
||||||
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
||||||
|
readHeader(br);
|
||||||
br.readLine();// connection close
|
|
||||||
br.readLine();// server
|
|
||||||
br.readLine();// empty
|
|
||||||
|
|
||||||
Assert.assertEquals("error servlet", "ERROR: /error", br.readLine());
|
Assert.assertEquals("error servlet", "ERROR: /error", br.readLine());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,9 +391,7 @@ public class AsyncContextTest
|
||||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||||
|
|
||||||
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
||||||
br.readLine();// connection close
|
readHeader(br);
|
||||||
br.readLine();// server
|
|
||||||
br.readLine();// empty
|
|
||||||
|
|
||||||
Assert.assertEquals("error servlet", "ERROR: /error", br.readLine());
|
Assert.assertEquals("error servlet", "ERROR: /error", br.readLine());
|
||||||
Assert.assertEquals("error servlet", "PathInfo= /500", br.readLine());
|
Assert.assertEquals("error servlet", "PathInfo= /500", br.readLine());
|
||||||
|
|
|
@ -115,7 +115,6 @@ public class DefaultServletRangesTest
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertResponseContains("206 Partial", response);
|
assertResponseContains("206 Partial", response);
|
||||||
assertResponseContains("Content-Type: text/plain", response);
|
assertResponseContains("Content-Type: text/plain", response);
|
||||||
assertResponseContains("Content-Length: 10", response);
|
|
||||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||||
assertResponseContains(DATA.substring(0,10), response);
|
assertResponseContains(DATA.substring(0,10), response);
|
||||||
}
|
}
|
||||||
|
@ -133,7 +132,6 @@ public class DefaultServletRangesTest
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertResponseContains("206 Partial", response);
|
assertResponseContains("206 Partial", response);
|
||||||
assertResponseContains("Content-Type: text/plain", response);
|
assertResponseContains("Content-Type: text/plain", response);
|
||||||
assertResponseContains("Content-Length: 7", response);
|
|
||||||
assertResponseContains("Content-Range: bytes 3-9/80", response);
|
assertResponseContains("Content-Range: bytes 3-9/80", response);
|
||||||
assertResponseContains(DATA.substring(3,10), 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 0-9/80", response);
|
||||||
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||||
assertResponseContains("Content-Range: bytes 40-49/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(0,10), response);
|
||||||
assertResponseContains(DATA.substring(20,30), response);
|
assertResponseContains(DATA.substring(20,30), response);
|
||||||
assertResponseContains(DATA.substring(40,50), response);
|
assertResponseContains(DATA.substring(40,50), response);
|
||||||
|
@ -177,7 +174,6 @@ public class DefaultServletRangesTest
|
||||||
assertResponseContains("206 Partial", response);
|
assertResponseContains("206 Partial", response);
|
||||||
assertResponseNotContains("Content-Type: multipart/byteranges; boundary=", response);
|
assertResponseNotContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||||
assertResponseContains("Content-Range: bytes 20-79/80", response);
|
assertResponseContains("Content-Range: bytes 20-79/80", response);
|
||||||
assertResponseContains("Content-Length: 60", response);
|
|
||||||
assertResponseContains(DATA.substring(60), response);
|
assertResponseContains(DATA.substring(60), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +190,6 @@ public class DefaultServletRangesTest
|
||||||
assertResponseContains("206 Partial", response);
|
assertResponseContains("206 Partial", response);
|
||||||
assertResponseNotContains("Content-Type: multipart/byteranges; boundary=", 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-Range: bytes 60-79/80", response); // yes the spec says it is these bytes
|
||||||
assertResponseContains("Content-Length: 20", response);
|
|
||||||
assertResponseContains(DATA.substring(60), 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" +
|
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n"+
|
|
||||||
"Range: bytes=0-9\r\n" +
|
"Range: bytes=0-9\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertResponseContains("206 Partial", response);
|
assertResponseContains("206 Partial", response);
|
||||||
|
@ -599,10 +598,17 @@ public class DefaultServletTest
|
||||||
assertResponseContains("Content-Length: 10", response);
|
assertResponseContains("Content-Length: 10", response);
|
||||||
assertResponseContains("Content-Range: bytes 0-9/80", 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" +
|
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n"+
|
|
||||||
"Range: bytes=0-9,20-29,40-49\r\n" +
|
"Range: bytes=0-9,20-29,40-49\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
int start = response.indexOf("--jetty");
|
int start = response.indexOf("--jetty");
|
||||||
|
@ -617,7 +623,6 @@ public class DefaultServletTest
|
||||||
|
|
||||||
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n"+
|
|
||||||
"Range: bytes=0-9,20-29,40-49,70-79\r\n" +
|
"Range: bytes=0-9,20-29,40-49,70-79\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
start = response.indexOf("--jetty");
|
start = response.indexOf("--jetty");
|
||||||
|
@ -633,7 +638,6 @@ public class DefaultServletTest
|
||||||
|
|
||||||
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
response = connector.getResponse("GET /context/data.txt HTTP/1.1\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n"+
|
|
||||||
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
start = response.indexOf("--jetty");
|
start = response.indexOf("--jetty");
|
||||||
|
@ -655,7 +659,6 @@ public class DefaultServletTest
|
||||||
|
|
||||||
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n"+
|
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertResponseContains("200 OK", response);
|
assertResponseContains("200 OK", response);
|
||||||
assertResponseContains("Accept-Ranges: bytes", response);
|
assertResponseContains("Accept-Ranges: bytes", response);
|
||||||
|
@ -664,7 +667,6 @@ public class DefaultServletTest
|
||||||
|
|
||||||
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n"+
|
|
||||||
"Range: bytes=0-9\r\n" +
|
"Range: bytes=0-9\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertResponseContains("206 Partial", response);
|
assertResponseContains("206 Partial", response);
|
||||||
|
@ -674,7 +676,6 @@ public class DefaultServletTest
|
||||||
|
|
||||||
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n"+
|
|
||||||
"Range: bytes=0-9,20-29,40-49\r\n" +
|
"Range: bytes=0-9,20-29,40-49\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
start = response.indexOf("--jetty");
|
start = response.indexOf("--jetty");
|
||||||
|
@ -687,11 +688,8 @@ public class DefaultServletTest
|
||||||
assertResponseContains("Content-Length: " + body.length(), response);
|
assertResponseContains("Content-Length: " + body.length(), response);
|
||||||
assertTrue(body.endsWith(boundary + "--\r\n"));
|
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
response = connector.getResponse("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n"+
|
|
||||||
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
start = response.indexOf("--jetty");
|
start = response.indexOf("--jetty");
|
||||||
|
|
|
@ -165,7 +165,6 @@ public class DispatcherTest
|
||||||
|
|
||||||
String expected=
|
String expected=
|
||||||
"HTTP/1.1 200 OK\r\n"+
|
"HTTP/1.1 200 OK\r\n"+
|
||||||
"Content-Length: 0\r\n"+
|
|
||||||
"\r\n";
|
"\r\n";
|
||||||
|
|
||||||
String responses = _connector.getResponses("GET /context/IncludeServlet?do=assertinclude&do=more&test=1 HTTP/1.0\n\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=
|
String expected=
|
||||||
"HTTP/1.1 200 OK\r\n"+
|
"HTTP/1.1 200 OK\r\n"+
|
||||||
"Content-Length: 0\r\n"+
|
|
||||||
"\r\n";
|
"\r\n";
|
||||||
|
|
||||||
String responses = _connector.getResponses("GET /context/ForwardServlet/forwardpath?do=include HTTP/1.0\n\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()
|
public void testWithCharSet()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
((StdErrLog)Log.getLogger(MultiPartFilter.class)).setDebugEnabled(true);
|
|
||||||
((StdErrLog)Log.getLogger(MultiPartInputStreamParser.class)).setDebugEnabled(true);
|
|
||||||
|
|
||||||
// generated and parsed test
|
// generated and parsed test
|
||||||
HttpTester.Request request = HttpTester.newRequest();
|
HttpTester.Request request = HttpTester.newRequest();
|
||||||
HttpTester.Response response;
|
HttpTester.Response response;
|
||||||
|
|
Loading…
Reference in New Issue