Merge remote-tracking branch 'origin/jetty-9.3.x' into jetty-9.4.x
This commit is contained in:
commit
aa97518d0b
|
@ -50,15 +50,17 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
*/
|
*/
|
||||||
public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so that extra custom modes can be defined dynamically
|
public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so that extra custom modes can be defined dynamically
|
||||||
{
|
{
|
||||||
/** A Legacy compliance mode to match jetty's behavior prior to RFC2616 and RFC7230. It only
|
/** A Legacy compliance mode to match jetty's behavior prior to RFC2616 and RFC7230.
|
||||||
* contains {@link HttpComplianceSection#METHOD_CASE_SENSITIVE}
|
|
||||||
*/
|
*/
|
||||||
LEGACY(sectionsBySpec("0,METHOD_CASE_SENSITIVE")),
|
LEGACY(sectionsBySpec("0,METHOD_CASE_SENSITIVE")),
|
||||||
|
|
||||||
/** The legacy RFC2616 support, which incorrectly excludes
|
/** The legacy RFC2616 support, which incorrectly excludes
|
||||||
* {@link HttpComplianceSection#METHOD_CASE_SENSITIVE}, {@link HttpComplianceSection#FIELD_COLON}
|
* {@link HttpComplianceSection#METHOD_CASE_SENSITIVE},
|
||||||
|
* {@link HttpComplianceSection#FIELD_COLON},
|
||||||
|
* {@link HttpComplianceSection#TRANSFER_ENCODING_WITH_CONTENT_LENGTH},
|
||||||
|
* {@link HttpComplianceSection#MULTIPLE_CONTENT_LENGTHS},
|
||||||
*/
|
*/
|
||||||
RFC2616_LEGACY(sectionsBySpec("RFC2616,-FIELD_COLON,-METHOD_CASE_SENSITIVE")),
|
RFC2616_LEGACY(sectionsBySpec("RFC2616,-FIELD_COLON,-METHOD_CASE_SENSITIVE,-TRANSFER_ENCODING_WITH_CONTENT_LENGTH,-MULTIPLE_CONTENT_LENGTHS")),
|
||||||
|
|
||||||
/** The strict RFC2616 support mode */
|
/** The strict RFC2616 support mode */
|
||||||
RFC2616(sectionsBySpec("RFC2616")),
|
RFC2616(sectionsBySpec("RFC2616")),
|
||||||
|
|
|
@ -28,7 +28,9 @@ public enum HttpComplianceSection
|
||||||
FIELD_NAME_CASE_INSENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.2","Field name is case-insensitive"),
|
FIELD_NAME_CASE_INSENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.2","Field name is case-insensitive"),
|
||||||
NO_WS_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4","Whitespace not allowed after field name"),
|
NO_WS_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4","Whitespace not allowed after field name"),
|
||||||
NO_FIELD_FOLDING("https://tools.ietf.org/html/rfc7230#section-3.2.4","No line Folding"),
|
NO_FIELD_FOLDING("https://tools.ietf.org/html/rfc7230#section-3.2.4","No line Folding"),
|
||||||
NO_HTTP_0_9("https://tools.ietf.org/html/rfc7230#appendix-A.2","No HTTP/0.9");
|
NO_HTTP_0_9("https://tools.ietf.org/html/rfc7230#appendix-A.2","No HTTP/0.9"),
|
||||||
|
TRANSFER_ENCODING_WITH_CONTENT_LENGTH("https://tools.ietf.org/html/rfc7230#section-3.3.1","Transfer-Encoding and Content-Length"),
|
||||||
|
MULTIPLE_CONTENT_LENGTHS("https://tools.ietf.org/html/rfc7230#section-3.3.1","Multiple Content-Lengths");
|
||||||
|
|
||||||
final String url;
|
final String url;
|
||||||
final String description;
|
final String description;
|
||||||
|
|
|
@ -35,6 +35,8 @@ import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||||
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;
|
||||||
|
|
||||||
|
import static org.eclipse.jetty.http.HttpComplianceSection.MULTIPLE_CONTENT_LENGTHS;
|
||||||
|
import static org.eclipse.jetty.http.HttpComplianceSection.TRANSFER_ENCODING_WITH_CONTENT_LENGTH;
|
||||||
import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN;
|
import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN;
|
||||||
import static org.eclipse.jetty.http.HttpTokens.COLON;
|
import static org.eclipse.jetty.http.HttpTokens.COLON;
|
||||||
import static org.eclipse.jetty.http.HttpTokens.LINE_FEED;
|
import static org.eclipse.jetty.http.HttpTokens.LINE_FEED;
|
||||||
|
@ -92,6 +94,7 @@ public class HttpParser
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public final static String __STRICT="org.eclipse.jetty.http.HttpParser.STRICT";
|
public final static String __STRICT="org.eclipse.jetty.http.HttpParser.STRICT";
|
||||||
public final static int INITIAL_URI_LENGTH=256;
|
public final static int INITIAL_URI_LENGTH=256;
|
||||||
|
private final static int MAX_CHUNK_LENGTH=Integer.MAX_VALUE/16-16;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache of common {@link HttpField}s including: <UL>
|
* Cache of common {@link HttpField}s including: <UL>
|
||||||
|
@ -172,6 +175,7 @@ public class HttpParser
|
||||||
private HttpVersion _version;
|
private HttpVersion _version;
|
||||||
private Utf8StringBuilder _uri=new Utf8StringBuilder(INITIAL_URI_LENGTH); // Tune?
|
private Utf8StringBuilder _uri=new Utf8StringBuilder(INITIAL_URI_LENGTH); // Tune?
|
||||||
private EndOfContent _endOfContent;
|
private EndOfContent _endOfContent;
|
||||||
|
private boolean _hasContentLength;
|
||||||
private long _contentLength = -1;
|
private long _contentLength = -1;
|
||||||
private long _contentPosition;
|
private long _contentPosition;
|
||||||
private int _chunkLength;
|
private int _chunkLength;
|
||||||
|
@ -323,6 +327,16 @@ public class HttpParser
|
||||||
{
|
{
|
||||||
return _handler;
|
return _handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------- */
|
||||||
|
/** Check RFC compliance violation
|
||||||
|
* @param violation The compliance section violation
|
||||||
|
* @return True if the current compliance level is set so as to Not allow this violation
|
||||||
|
*/
|
||||||
|
protected boolean complianceViolation(HttpComplianceSection violation)
|
||||||
|
{
|
||||||
|
return complianceViolation(violation,null);
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
/** Check RFC compliance violation
|
/** Check RFC compliance violation
|
||||||
|
@ -334,7 +348,8 @@ public class HttpParser
|
||||||
{
|
{
|
||||||
if (_compliances.contains(violation))
|
if (_compliances.contains(violation))
|
||||||
return true;
|
return true;
|
||||||
|
if (reason==null)
|
||||||
|
reason=violation.description;
|
||||||
if (_complianceHandler!=null)
|
if (_complianceHandler!=null)
|
||||||
_complianceHandler.onComplianceViolation(_compliance,violation,reason);
|
_complianceHandler.onComplianceViolation(_compliance,violation,reason);
|
||||||
|
|
||||||
|
@ -580,8 +595,8 @@ public class HttpParser
|
||||||
}
|
}
|
||||||
else if (ch==0)
|
else if (ch==0)
|
||||||
break;
|
break;
|
||||||
else if (ch<0)
|
else if (ch!='\n')
|
||||||
throw new BadMessageException();
|
throw new BadMessageException("Bad preamble");
|
||||||
|
|
||||||
// count this white space as a header byte to avoid DOS
|
// count this white space as a header byte to avoid DOS
|
||||||
if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
|
if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
|
||||||
|
@ -706,8 +721,7 @@ public class HttpParser
|
||||||
_length=_string.length();
|
_length=_string.length();
|
||||||
String version=takeString();
|
String version=takeString();
|
||||||
_version=HttpVersion.CACHE.get(version);
|
_version=HttpVersion.CACHE.get(version);
|
||||||
if (_version==null)
|
checkVersion();
|
||||||
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version");
|
|
||||||
setState(State.SPACE1);
|
setState(State.SPACE1);
|
||||||
}
|
}
|
||||||
else if (b < HttpTokens.SPACE)
|
else if (b < HttpTokens.SPACE)
|
||||||
|
@ -822,7 +836,7 @@ public class HttpParser
|
||||||
version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining());
|
version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining());
|
||||||
|
|
||||||
if (version!=null)
|
if (version!=null)
|
||||||
{
|
{
|
||||||
int pos = buffer.position()+version.asString().length()-1;
|
int pos = buffer.position()+version.asString().length()-1;
|
||||||
if (pos<buffer.limit())
|
if (pos<buffer.limit())
|
||||||
{
|
{
|
||||||
|
@ -831,12 +845,14 @@ public class HttpParser
|
||||||
{
|
{
|
||||||
_cr=true;
|
_cr=true;
|
||||||
_version=version;
|
_version=version;
|
||||||
|
checkVersion();
|
||||||
_string.setLength(0);
|
_string.setLength(0);
|
||||||
buffer.position(pos+1);
|
buffer.position(pos+1);
|
||||||
}
|
}
|
||||||
else if (n==HttpTokens.LINE_FEED)
|
else if (n==HttpTokens.LINE_FEED)
|
||||||
{
|
{
|
||||||
_version=version;
|
_version=version;
|
||||||
|
checkVersion();
|
||||||
_string.setLength(0);
|
_string.setLength(0);
|
||||||
buffer.position(pos);
|
buffer.position(pos);
|
||||||
}
|
}
|
||||||
|
@ -875,8 +891,7 @@ public class HttpParser
|
||||||
_length=_string.length();
|
_length=_string.length();
|
||||||
_version=HttpVersion.CACHE.get(takeString());
|
_version=HttpVersion.CACHE.get(takeString());
|
||||||
}
|
}
|
||||||
if (_version==null)
|
checkVersion();
|
||||||
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version");
|
|
||||||
|
|
||||||
// Should we try to cache header fields?
|
// Should we try to cache header fields?
|
||||||
if (_fieldCache==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion() && _handler.getHeaderCacheSize()>0)
|
if (_fieldCache==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion() && _handler.getHeaderCacheSize()>0)
|
||||||
|
@ -923,6 +938,15 @@ public class HttpParser
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkVersion()
|
||||||
|
{
|
||||||
|
if (_version==null)
|
||||||
|
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version");
|
||||||
|
|
||||||
|
if (_version.getVersion()<10 || _version.getVersion()>20)
|
||||||
|
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Version");
|
||||||
|
}
|
||||||
|
|
||||||
private void parsedHeader()
|
private void parsedHeader()
|
||||||
{
|
{
|
||||||
// handler last header if any. Delayed to here just in case there was a continuation line (above)
|
// handler last header if any. Delayed to here just in case there was a continuation line (above)
|
||||||
|
@ -935,11 +959,19 @@ public class HttpParser
|
||||||
switch (_header)
|
switch (_header)
|
||||||
{
|
{
|
||||||
case CONTENT_LENGTH:
|
case CONTENT_LENGTH:
|
||||||
if (_endOfContent == EndOfContent.CONTENT_LENGTH)
|
if (_hasContentLength)
|
||||||
{
|
{
|
||||||
throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Duplicate Content-Length");
|
if(complianceViolation(MULTIPLE_CONTENT_LENGTHS))
|
||||||
|
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,MULTIPLE_CONTENT_LENGTHS.description);
|
||||||
|
if (convertContentLength(_valueString)!=_contentLength)
|
||||||
|
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,MULTIPLE_CONTENT_LENGTHS.description);
|
||||||
}
|
}
|
||||||
else if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
|
_hasContentLength = true;
|
||||||
|
|
||||||
|
if (_endOfContent == EndOfContent.CHUNKED_CONTENT && complianceViolation(TRANSFER_ENCODING_WITH_CONTENT_LENGTH))
|
||||||
|
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
|
||||||
|
|
||||||
|
if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
|
||||||
{
|
{
|
||||||
_contentLength=convertContentLength(_valueString);
|
_contentLength=convertContentLength(_valueString);
|
||||||
if (_contentLength <= 0)
|
if (_contentLength <= 0)
|
||||||
|
@ -950,6 +982,9 @@ public class HttpParser
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRANSFER_ENCODING:
|
case TRANSFER_ENCODING:
|
||||||
|
if (_hasContentLength && complianceViolation(TRANSFER_ENCODING_WITH_CONTENT_LENGTH))
|
||||||
|
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Transfer-Encoding and Content-Length");
|
||||||
|
|
||||||
if (HttpHeaderValue.CHUNKED.is(_valueString))
|
if (HttpHeaderValue.CHUNKED.is(_valueString))
|
||||||
{
|
{
|
||||||
_endOfContent=EndOfContent.CHUNKED_CONTENT;
|
_endOfContent=EndOfContent.CHUNKED_CONTENT;
|
||||||
|
@ -966,6 +1001,8 @@ public class HttpParser
|
||||||
else if (values.stream().anyMatch(HttpHeaderValue.CHUNKED::is))
|
else if (values.stream().anyMatch(HttpHeaderValue.CHUNKED::is))
|
||||||
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad chunking");
|
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad chunking");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HOST:
|
case HOST:
|
||||||
|
@ -1627,9 +1664,16 @@ public class HttpParser
|
||||||
setState(State.CHUNK);
|
setState(State.CHUNK);
|
||||||
}
|
}
|
||||||
else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
|
else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
|
||||||
|
{
|
||||||
setState(State.CHUNK_PARAMS);
|
setState(State.CHUNK_PARAMS);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (_chunkLength>MAX_CHUNK_LENGTH)
|
||||||
|
throw new BadMessageException(HttpStatus.PAYLOAD_TOO_LARGE_413);
|
||||||
|
|
||||||
_chunkLength=_chunkLength * 16 + TypeUtil.convertHexDigit(ch);
|
_chunkLength=_chunkLength * 16 + TypeUtil.convertHexDigit(ch);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1730,6 +1774,7 @@ public class HttpParser
|
||||||
setState(State.START);
|
setState(State.START);
|
||||||
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
|
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
|
||||||
_contentLength=-1;
|
_contentLength=-1;
|
||||||
|
_hasContentLength=false;
|
||||||
_contentPosition=0;
|
_contentPosition=0;
|
||||||
_responseStatus=0;
|
_responseStatus=0;
|
||||||
_contentChunk=null;
|
_contentChunk=null;
|
||||||
|
|
|
@ -216,6 +216,32 @@ public class HttpParserTest
|
||||||
Assert.assertEquals(-1, _headers);
|
Assert.assertEquals(-1, _headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllowedLinePreamble() throws Exception
|
||||||
|
{
|
||||||
|
ByteBuffer buffer= BufferUtil.toBuffer("\r\n\r\nGET / HTTP/1.0\r\n");
|
||||||
|
|
||||||
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
|
HttpParser parser= new HttpParser(handler);
|
||||||
|
parseAll(parser,buffer);
|
||||||
|
Assert.assertEquals("GET", _methodOrVersion);
|
||||||
|
Assert.assertEquals("/", _uriOrStatus);
|
||||||
|
Assert.assertEquals("HTTP/1.0", _versionOrReason);
|
||||||
|
Assert.assertEquals(-1, _headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisallowedLinePreamble() throws Exception
|
||||||
|
{
|
||||||
|
ByteBuffer buffer= BufferUtil.toBuffer("\r\n \r\nGET / HTTP/1.0\r\n");
|
||||||
|
|
||||||
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
|
HttpParser parser= new HttpParser(handler);
|
||||||
|
parseAll(parser,buffer);
|
||||||
|
Assert.assertEquals("Bad preamble", _bad);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConnect() throws Exception
|
public void testConnect() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -1741,7 +1767,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDuplicateContentLengthWithLargerThenCorrectValue()
|
public void testMultipleContentLengthWithLargerThenCorrectValue()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"POST / HTTP/1.1\r\n"
|
"POST / HTTP/1.1\r\n"
|
||||||
|
@ -1756,7 +1782,7 @@ public class HttpParserTest
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
Assert.assertEquals("POST", _methodOrVersion);
|
Assert.assertEquals("POST", _methodOrVersion);
|
||||||
Assert.assertEquals("Duplicate Content-Length", _bad);
|
Assert.assertEquals("Multiple Content-Lengths", _bad);
|
||||||
Assert.assertFalse(buffer.hasRemaining());
|
Assert.assertFalse(buffer.hasRemaining());
|
||||||
Assert.assertEquals(HttpParser.State.CLOSE, parser.getState());
|
Assert.assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
parser.atEOF();
|
parser.atEOF();
|
||||||
|
@ -1765,7 +1791,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDuplicateContentLengthWithCorrectThenLargerValue()
|
public void testMultipleContentLengthWithCorrectThenLargerValue()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"POST / HTTP/1.1\r\n"
|
"POST / HTTP/1.1\r\n"
|
||||||
|
@ -1780,7 +1806,7 @@ public class HttpParserTest
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
Assert.assertEquals("POST", _methodOrVersion);
|
Assert.assertEquals("POST", _methodOrVersion);
|
||||||
Assert.assertEquals("Duplicate Content-Length", _bad);
|
Assert.assertEquals("Multiple Content-Lengths", _bad);
|
||||||
Assert.assertFalse(buffer.hasRemaining());
|
Assert.assertFalse(buffer.hasRemaining());
|
||||||
Assert.assertEquals(HttpParser.State.CLOSE, parser.getState());
|
Assert.assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
parser.atEOF();
|
parser.atEOF();
|
||||||
|
@ -1803,7 +1829,7 @@ public class HttpParserTest
|
||||||
+ "\r\n");
|
+ "\r\n");
|
||||||
|
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
|
|
||||||
Assert.assertEquals("POST", _methodOrVersion);
|
Assert.assertEquals("POST", _methodOrVersion);
|
||||||
|
@ -1813,6 +1839,8 @@ public class HttpParserTest
|
||||||
|
|
||||||
Assert.assertTrue(_headerCompleted);
|
Assert.assertTrue(_headerCompleted);
|
||||||
Assert.assertTrue(_messageCompleted);
|
Assert.assertTrue(_messageCompleted);
|
||||||
|
|
||||||
|
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.TRANSFER_ENCODING_WITH_CONTENT_LENGTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1830,7 +1858,7 @@ public class HttpParserTest
|
||||||
+ "\r\n");
|
+ "\r\n");
|
||||||
|
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
|
|
||||||
Assert.assertEquals("POST", _methodOrVersion);
|
Assert.assertEquals("POST", _methodOrVersion);
|
||||||
|
@ -1840,6 +1868,8 @@ public class HttpParserTest
|
||||||
|
|
||||||
Assert.assertTrue(_headerCompleted);
|
Assert.assertTrue(_headerCompleted);
|
||||||
Assert.assertTrue(_messageCompleted);
|
Assert.assertTrue(_messageCompleted);
|
||||||
|
|
||||||
|
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.TRANSFER_ENCODING_WITH_CONTENT_LENGTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -721,7 +721,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
{
|
{
|
||||||
action=_state.handling();
|
action=_state.handling();
|
||||||
}
|
}
|
||||||
catch(IllegalStateException e)
|
catch(Throwable e)
|
||||||
{
|
{
|
||||||
// The bad message cannot be handled in the current state,
|
// The bad message cannot be handled in the current state,
|
||||||
// so rethrow, hopefully somebody will be able to handle.
|
// so rethrow, hopefully somebody will be able to handle.
|
||||||
|
@ -749,12 +749,15 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// TODO: review whether it's the right state to check.
|
try
|
||||||
if (_state.unhandle()==Action.COMPLETE)
|
{
|
||||||
_state.onComplete();
|
onCompleted();
|
||||||
else
|
}
|
||||||
throw new IllegalStateException(); // TODO: don't throw from finally blocks !
|
catch(Throwable e)
|
||||||
onCompleted();
|
{
|
||||||
|
LOG.debug(e);
|
||||||
|
abort(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
*/
|
*/
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.CoreMatchers.not;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
@ -45,6 +48,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import org.eclipse.jetty.http.HttpCompliance;
|
import org.eclipse.jetty.http.HttpCompliance;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpParser;
|
import org.eclipse.jetty.http.HttpParser;
|
||||||
|
import org.eclipse.jetty.http.HttpTester;
|
||||||
import org.eclipse.jetty.http.MimeTypes;
|
import org.eclipse.jetty.http.MimeTypes;
|
||||||
import org.eclipse.jetty.server.LocalConnector.LocalEndPoint;
|
import org.eclipse.jetty.server.LocalConnector.LocalEndPoint;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
@ -140,6 +144,167 @@ public class HttpConnectionTest
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP/0.9 does not support HttpVersion (this is a bad request)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testHttp09_NoVersion() throws Exception
|
||||||
|
{
|
||||||
|
connector.getConnectionFactory(HttpConnectionFactory.class).setHttpCompliance(HttpCompliance.RFC2616);
|
||||||
|
String request = "GET / HTTP/0.9\r\n\r\n";
|
||||||
|
String response = connector.getResponse(request);
|
||||||
|
assertThat(response, containsString("400 Bad Version"));
|
||||||
|
|
||||||
|
connector.getConnectionFactory(HttpConnectionFactory.class).setHttpCompliance(HttpCompliance.RFC7230);
|
||||||
|
request = "GET / HTTP/0.9\r\n\r\n";
|
||||||
|
response = connector.getResponse(request);
|
||||||
|
assertThat(response, containsString("400 Bad Version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP/0.9 does not support headers
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testHttp09_NoHeaders() throws Exception
|
||||||
|
{
|
||||||
|
connector.getConnectionFactory(HttpConnectionFactory.class).setHttpCompliance(HttpCompliance.RFC2616);
|
||||||
|
// header looking like another request is ignored
|
||||||
|
String request = "GET /one\r\nGET :/two\r\n\r\n";
|
||||||
|
String response = BufferUtil.toString(connector.executeRequest(request).waitForOutput(10,TimeUnit.SECONDS));
|
||||||
|
assertThat(response, containsString("pathInfo=/"));
|
||||||
|
assertThat(response, not(containsString("two")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Http/0.9 does not support pipelining.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testHttp09_MultipleRequests() throws Exception
|
||||||
|
{
|
||||||
|
connector.getConnectionFactory(HttpConnectionFactory.class).setHttpCompliance(HttpCompliance.RFC2616);
|
||||||
|
|
||||||
|
// Verify that pipelining does not work with HTTP/0.9.
|
||||||
|
String requests = "GET /?id=123\r\n\r\nGET /?id=456\r\n\r\n";
|
||||||
|
LocalEndPoint endp = connector.executeRequest(requests);
|
||||||
|
String response = BufferUtil.toString(endp.waitForOutput(10,TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
assertThat(response, containsString("id=123"));
|
||||||
|
assertThat(response, not(containsString("id=456")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that excessively large hexadecimal chunk body length is parsed properly.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testHttp11_ChunkedBodyTruncation() throws Exception
|
||||||
|
{
|
||||||
|
String request = "POST /?id=123 HTTP/1.1\r\n" +
|
||||||
|
"Host: local\r\n" +
|
||||||
|
"Transfer-Encoding: chunked\r\n" +
|
||||||
|
"Content-Type: text/plain\r\n" +
|
||||||
|
"Connection: close\r\n" +
|
||||||
|
"\r\n" +
|
||||||
|
"1ff00000008\r\n" +
|
||||||
|
"abcdefgh\r\n" +
|
||||||
|
"\r\n" +
|
||||||
|
"0\r\n" +
|
||||||
|
"\r\n" +
|
||||||
|
"POST /?id=bogus HTTP/1.1\r\n" +
|
||||||
|
"Content-Length: 5\r\n" +
|
||||||
|
"Host: dummy-host.example.com\r\n" +
|
||||||
|
"\r\n" +
|
||||||
|
"12345";
|
||||||
|
|
||||||
|
String response = connector.getResponse(request);
|
||||||
|
assertThat(response,containsString(" 200 OK"));
|
||||||
|
assertThat(response,containsString("Connection: close"));
|
||||||
|
assertThat(response,containsString("Early EOF"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* More then 1 Content-Length is a bad requests per HTTP rfcs.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testHttp11_MultipleContentLength() throws Exception
|
||||||
|
{
|
||||||
|
HttpParser.LOG.info("badMessage: 400 Bad messages EXPECTED...");
|
||||||
|
int contentLengths[][]= {
|
||||||
|
{0,8},
|
||||||
|
{8,0},
|
||||||
|
{8,8},
|
||||||
|
{0,8,0},
|
||||||
|
{1,2,3,4,5,6,7,8},
|
||||||
|
{8,2,1},
|
||||||
|
{0,0},
|
||||||
|
{8,0,8},
|
||||||
|
{-1,8},
|
||||||
|
{8,-1},
|
||||||
|
{-1,8,-1},
|
||||||
|
{-1,-1},
|
||||||
|
{8,-1,8},
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int x = 0; x < contentLengths.length; x++)
|
||||||
|
{
|
||||||
|
StringBuilder request = new StringBuilder();
|
||||||
|
request.append("POST /?id=").append(Integer.toString(x)).append(" HTTP/1.1\r\n");
|
||||||
|
request.append("Host: local\r\n");
|
||||||
|
int clen[] = contentLengths[x];
|
||||||
|
for(int n = 0; n<clen.length; n++)
|
||||||
|
{
|
||||||
|
request.append("Content-Length: ").append(Integer.toString(clen[n])).append("\r\n");
|
||||||
|
}
|
||||||
|
request.append("Content-Type: text/plain\r\n");
|
||||||
|
request.append("Connection: close\r\n");
|
||||||
|
request.append("\r\n");
|
||||||
|
request.append("abcdefgh"); // actual content of 8 bytes
|
||||||
|
|
||||||
|
String rawResponse = connector.getResponse(request.toString());
|
||||||
|
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_BAD_REQUEST));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* More then 1 Content-Length is a bad requests per HTTP rfcs.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testHttp11_ContentLengthAndChunk() throws Exception
|
||||||
|
{
|
||||||
|
HttpParser.LOG.info("badMessage: 400 Bad messages EXPECTED...");
|
||||||
|
int contentLengths[][]= {
|
||||||
|
{-1,8},
|
||||||
|
{8,-1},
|
||||||
|
{8,-1,8},
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int x = 0; x < contentLengths.length; x++)
|
||||||
|
{
|
||||||
|
StringBuilder request = new StringBuilder();
|
||||||
|
request.append("POST /?id=").append(Integer.toString(x)).append(" HTTP/1.1\r\n");
|
||||||
|
request.append("Host: local\r\n");
|
||||||
|
int clen[] = contentLengths[x];
|
||||||
|
for(int n = 0; n<clen.length; n++)
|
||||||
|
{
|
||||||
|
if (clen[n]==-1)
|
||||||
|
request.append("Transfer-Encoding: chunked\r\n");
|
||||||
|
else
|
||||||
|
request.append("Content-Length: ").append(Integer.toString(clen[n])).append("\r\n");
|
||||||
|
}
|
||||||
|
request.append("Content-Type: text/plain\r\n");
|
||||||
|
request.append("Connection: close\r\n");
|
||||||
|
request.append("\r\n");
|
||||||
|
request.append("8;\r\n"); // chunk header
|
||||||
|
request.append("abcdefgh"); // actual content of 8 bytes
|
||||||
|
request.append("\r\n0;\r\n"); // last chunk
|
||||||
|
|
||||||
|
String rawResponse = connector.getResponse(request.toString());
|
||||||
|
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_BAD_REQUEST));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoPath() throws Exception
|
public void testNoPath() throws Exception
|
||||||
|
@ -588,6 +753,7 @@ public class HttpConnectionTest
|
||||||
server.stop();
|
server.stop();
|
||||||
server.setHandler(new AbstractHandler()
|
server.setHandler(new AbstractHandler()
|
||||||
{
|
{
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Override
|
@Override
|
||||||
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
|
||||||
{
|
{
|
||||||
|
@ -921,10 +1087,10 @@ public class HttpConnectionTest
|
||||||
str+="xxxxxxxxxxxx";
|
str+="xxxxxxxxxxxx";
|
||||||
final String longstr = str;
|
final String longstr = str;
|
||||||
final CountDownLatch checkError = new CountDownLatch(1);
|
final CountDownLatch checkError = new CountDownLatch(1);
|
||||||
String response = null;
|
|
||||||
server.stop();
|
server.stop();
|
||||||
server.setHandler(new AbstractHandler.ErrorDispatchHandler()
|
server.setHandler(new AbstractHandler.ErrorDispatchHandler()
|
||||||
{
|
{
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
|
@ -941,7 +1107,8 @@ public class HttpConnectionTest
|
||||||
});
|
});
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
Logger logger = Log.getLogger(HttpChannel.class);
|
Logger logger = Log.getLogger(HttpChannel.class);
|
||||||
|
String response = null;
|
||||||
try (StacklessLogging stackless = new StacklessLogging(logger))
|
try (StacklessLogging stackless = new StacklessLogging(logger))
|
||||||
{
|
{
|
||||||
logger.info("Expect IOException: Response header too large...");
|
logger.info("Expect IOException: Response header too large...");
|
||||||
|
|
|
@ -269,6 +269,39 @@ public class PartialRFC2616Test
|
||||||
assertEquals("Quality parameters","ccc",HttpFields.valueParameters(list.get(4),null));
|
assertEquals("Quality parameters","ccc",HttpFields.valueParameters(list.get(4),null));
|
||||||
assertEquals("Quality parameters","ddd",HttpFields.valueParameters(list.get(5),null));
|
assertEquals("Quality parameters","ddd",HttpFields.valueParameters(list.get(5),null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test4_1() throws Exception
|
||||||
|
{
|
||||||
|
int offset=0;
|
||||||
|
// If _content length not used, second request will not be read.
|
||||||
|
String response = connector.getResponses(
|
||||||
|
"\r\n" +
|
||||||
|
"GET /R1 HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"\r\n" +
|
||||||
|
"\r\n" +
|
||||||
|
"\r\n" +
|
||||||
|
"\r\n" +
|
||||||
|
"GET /R2 HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"\r\n" +
|
||||||
|
" \r\n" +
|
||||||
|
"GET /R3 HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n" +
|
||||||
|
"\r\n"
|
||||||
|
);
|
||||||
|
offset=checkContains(response,offset,"HTTP/1.1 200 OK","2. identity")+10;
|
||||||
|
offset=checkContains(response,offset,"/R1","2. identity")+3;
|
||||||
|
offset=checkContains(response,offset,"HTTP/1.1 200 OK","2. identity")+10;
|
||||||
|
offset=checkContains(response,offset,"/R2","2. identity")+3;
|
||||||
|
checkNotContained(response,offset,"HTTP/1.1 200 OK","2. identity");
|
||||||
|
checkNotContained(response,offset,"/R3","2. identity");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test4_4_2() throws Exception
|
public void test4_4_2() throws Exception
|
||||||
|
@ -303,8 +336,8 @@ public class PartialRFC2616Test
|
||||||
@Test
|
@Test
|
||||||
public void test4_4_3() throws Exception
|
public void test4_4_3() throws Exception
|
||||||
{
|
{
|
||||||
// _content length is ignored, as chunking is used. If it is
|
// Due to smuggling concerns, handling has been changed to
|
||||||
// not ignored, the second request wont be seen.
|
// treat content length and chunking as a bad request.
|
||||||
int offset=0;
|
int offset=0;
|
||||||
String response;
|
String response;
|
||||||
LocalEndPoint endp=connector.executeRequest(
|
LocalEndPoint endp=connector.executeRequest(
|
||||||
|
@ -328,16 +361,9 @@ public class PartialRFC2616Test
|
||||||
"Content-Length: 6\n" +
|
"Content-Length: 6\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"abcdef");
|
"abcdef");
|
||||||
offset=0;
|
|
||||||
response = endp.getResponse();
|
response = endp.getResponse();
|
||||||
offset=checkContains(response,offset,"HTTP/1.1 200 OK","3. ignore c-l")+1;
|
offset=checkContains(response,offset,"HTTP/1.1 400 Bad","3. ignore c-l")+1;
|
||||||
offset=checkContains(response,offset,"/R1","3. ignore c-l")+1;
|
checkNotContained(response,offset,"/R2","3. _content-length");
|
||||||
offset=checkContains(response,offset,"123456","3. ignore c-l")+1;
|
|
||||||
offset=0;
|
|
||||||
response = endp.getResponse();
|
|
||||||
offset=checkContains(response,offset,"HTTP/1.1 200 OK","3. ignore c-l")+1;
|
|
||||||
offset=checkContains(response,offset,"/R2","3. _content-length")+1;
|
|
||||||
offset=checkContains(response,offset,"abcdef","3. _content-length")+1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -18,12 +18,12 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.test.rfcs;
|
package org.eclipse.jetty.test.rfcs;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -384,7 +384,7 @@ public abstract class RFC2616BaseTest
|
||||||
// 4.4.3 -
|
// 4.4.3 -
|
||||||
// Client - do not send 'Content-Length' if entity-length
|
// Client - do not send 'Content-Length' if entity-length
|
||||||
// and the transfer-length are different.
|
// and the transfer-length are different.
|
||||||
// Server - ignore 'Content-Length' if 'Transfer-Encoding' is provided.
|
// Server - bad message to avoid smuggling concerns
|
||||||
|
|
||||||
StringBuffer req2 = new StringBuffer();
|
StringBuffer req2 = new StringBuffer();
|
||||||
req2.append("GET /echo/R1 HTTP/1.1\n");
|
req2.append("GET /echo/R1 HTTP/1.1\n");
|
||||||
|
@ -409,14 +409,10 @@ public abstract class RFC2616BaseTest
|
||||||
req2.append("7890AB");
|
req2.append("7890AB");
|
||||||
|
|
||||||
responses = http.requests(req2);
|
responses = http.requests(req2);
|
||||||
Assert.assertEquals("Response Count",2,responses.size());
|
Assert.assertEquals("Response Count",1,responses.size());
|
||||||
|
|
||||||
response = responses.get(0); // response 1
|
response = responses.get(0); // response 1
|
||||||
assertEquals("4.4.3 Ignore Content-Length / Response Code", HttpStatus.OK_200, response.getStatus());
|
assertEquals("4.4.3 Ignore Content-Length / Response Code", HttpStatus.BAD_REQUEST_400, response.getStatus());
|
||||||
assertTrue("4.4.3 Ignore Content-Length / Body", response.getContent().contains("123456\n"));
|
|
||||||
response = responses.get(1); // response 2
|
|
||||||
assertEquals("4.4.3 Ignore Content-Length / Response Code", HttpStatus.OK_200, response.getStatus());
|
|
||||||
assertTrue("4.4.3 Ignore Content-Length / Body", response.getContent().contains("7890AB\n"));
|
|
||||||
|
|
||||||
// 4.4 - Server can request valid Content-Length from client if client
|
// 4.4 - Server can request valid Content-Length from client if client
|
||||||
// fails to provide a Content-Length.
|
// fails to provide a Content-Length.
|
||||||
|
@ -535,7 +531,6 @@ public abstract class RFC2616BaseTest
|
||||||
req4.append("\n"); // no virtual host
|
req4.append("\n"); // no virtual host
|
||||||
|
|
||||||
HttpTester.Response response = http.request(req4);
|
HttpTester.Response response = http.request(req4);
|
||||||
System.err.println(response);
|
|
||||||
|
|
||||||
assertEquals("5.2 No Host",HttpStatus.BAD_REQUEST_400,response.getStatus());
|
assertEquals("5.2 No Host",HttpStatus.BAD_REQUEST_400,response.getStatus());
|
||||||
}
|
}
|
||||||
|
@ -623,7 +618,6 @@ public abstract class RFC2616BaseTest
|
||||||
HttpTester.Response response = http.request(req7);
|
HttpTester.Response response = http.request(req7);
|
||||||
|
|
||||||
assertEquals("5.2 Virtual Host as AbsoluteURI (and Host header)", HttpStatus.OK_200, response.getStatus());
|
assertEquals("5.2 Virtual Host as AbsoluteURI (and Host header)", HttpStatus.OK_200, response.getStatus());
|
||||||
// System.err.println(response.getContent());
|
|
||||||
assertThat("5.2 Virtual Host as AbsoluteURI (and Host header)",response.getContent(),Matchers.containsString("VirtualHost DOCRoot"));
|
assertThat("5.2 Virtual Host as AbsoluteURI (and Host header)",response.getContent(),Matchers.containsString("VirtualHost DOCRoot"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,11 +751,8 @@ public abstract class RFC2616BaseTest
|
||||||
req3.append("87654321"); // Body
|
req3.append("87654321"); // Body
|
||||||
|
|
||||||
List<HttpTester.Response> responses = http.requests(req3);
|
List<HttpTester.Response> responses = http.requests(req3);
|
||||||
|
|
||||||
// System.err.println(responses);
|
|
||||||
|
|
||||||
HttpTester.Response response=responses.get(0);
|
HttpTester.Response response=responses.get(0);
|
||||||
// System.err.println(response);
|
|
||||||
|
|
||||||
assertEquals("8.2.3 ignored no 100",302, response.getStatus());
|
assertEquals("8.2.3 ignored no 100",302, response.getStatus());
|
||||||
assertEquals("close",response.get("Connection"));
|
assertEquals("close",response.get("Connection"));
|
||||||
|
@ -1017,8 +1008,6 @@ public abstract class RFC2616BaseTest
|
||||||
|
|
||||||
response = http.request(req2);
|
response = http.request(req2);
|
||||||
|
|
||||||
// System.err.println(response);
|
|
||||||
|
|
||||||
assertEquals("10.2.7 Partial Content",HttpStatus.PARTIAL_CONTENT_206, response.getStatus());
|
assertEquals("10.2.7 Partial Content",HttpStatus.PARTIAL_CONTENT_206, response.getStatus());
|
||||||
|
|
||||||
// (point 1) A 206 response MUST contain either a Content-Range header
|
// (point 1) A 206 response MUST contain either a Content-Range header
|
||||||
|
@ -1599,7 +1588,6 @@ public abstract class RFC2616BaseTest
|
||||||
req1.append("\n");
|
req1.append("\n");
|
||||||
|
|
||||||
HttpTester.Response response = http.request(req1);
|
HttpTester.Response response = http.request(req1);
|
||||||
// System.err.println(response+response.getContent());
|
|
||||||
|
|
||||||
String msg = "Partial (Byte) Range: '" + rangedef + "'";
|
String msg = "Partial (Byte) Range: '" + rangedef + "'";
|
||||||
assertEquals(msg,HttpStatus.PARTIAL_CONTENT_206,response.getStatus());
|
assertEquals(msg,HttpStatus.PARTIAL_CONTENT_206,response.getStatus());
|
||||||
|
|
Loading…
Reference in New Issue