Merge remote-tracking branch 'origin/jetty-11.0.x' into jetty-12.0.x
# Conflicts: # jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java # jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
This commit is contained in:
commit
13cf2dade7
|
@ -512,7 +512,7 @@ public class HttpParser
|
||||||
/* Quick lookahead for the start state looking for a request method or an HTTP version,
|
/* Quick lookahead for the start state looking for a request method or an HTTP version,
|
||||||
* otherwise skip white space until something else to parse.
|
* otherwise skip white space until something else to parse.
|
||||||
*/
|
*/
|
||||||
private boolean quickStart(ByteBuffer buffer)
|
private void quickStart(ByteBuffer buffer)
|
||||||
{
|
{
|
||||||
int position = buffer.position();
|
int position = buffer.position();
|
||||||
if (_requestHandler != null)
|
if (_requestHandler != null)
|
||||||
|
@ -526,7 +526,7 @@ public class HttpParser
|
||||||
buffer.position(position + _methodString.length() + 1);
|
buffer.position(position + _methodString.length() + 1);
|
||||||
|
|
||||||
setState(State.SPACE1);
|
setState(State.SPACE1);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_responseHandler != null && buffer.remaining() >= (HTTP_VERSION_LEN + 1) && buffer.getInt(position) == HTTP_AS_INT)
|
else if (_responseHandler != null && buffer.remaining() >= (HTTP_VERSION_LEN + 1) && buffer.getInt(position) == HTTP_AS_INT)
|
||||||
|
@ -537,7 +537,7 @@ public class HttpParser
|
||||||
{
|
{
|
||||||
buffer.position(position + HTTP_VERSION_LEN + 1);
|
buffer.position(position + HTTP_VERSION_LEN + 1);
|
||||||
setState(State.SPACE1);
|
setState(State.SPACE1);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ public class HttpParser
|
||||||
_string.setLength(0);
|
_string.setLength(0);
|
||||||
_string.append(t.getChar());
|
_string.append(t.getChar());
|
||||||
setState(_requestHandler != null ? State.METHOD : State.RESPONSE_VERSION);
|
setState(_requestHandler != null ? State.METHOD : State.RESPONSE_VERSION);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
case OTEXT:
|
case OTEXT:
|
||||||
case SPACE:
|
case SPACE:
|
||||||
|
@ -576,7 +576,6 @@ public class HttpParser
|
||||||
throw new BadMessageException(HttpStatus.BAD_REQUEST_400);
|
throw new BadMessageException(HttpStatus.BAD_REQUEST_400);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setString(String s)
|
private void setString(String s)
|
||||||
|
@ -993,21 +992,18 @@ public class HttpParser
|
||||||
case CONTENT_LENGTH:
|
case CONTENT_LENGTH:
|
||||||
if (_hasTransferEncoding)
|
if (_hasTransferEncoding)
|
||||||
checkViolation(TRANSFER_ENCODING_WITH_CONTENT_LENGTH);
|
checkViolation(TRANSFER_ENCODING_WITH_CONTENT_LENGTH);
|
||||||
|
long contentLength = convertContentLength(_valueString);
|
||||||
if (_hasContentLength)
|
if (_hasContentLength)
|
||||||
{
|
{
|
||||||
checkViolation(MULTIPLE_CONTENT_LENGTHS);
|
checkViolation(MULTIPLE_CONTENT_LENGTHS);
|
||||||
if (convertContentLength(_valueString) != _contentLength)
|
if (contentLength != _contentLength)
|
||||||
throw new BadMessageException(MULTIPLE_CONTENT_LENGTHS.getDescription());
|
throw new BadMessageException(MULTIPLE_CONTENT_LENGTHS.getDescription());
|
||||||
}
|
}
|
||||||
_hasContentLength = true;
|
_hasContentLength = true;
|
||||||
|
|
||||||
if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
|
if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
|
||||||
{
|
{
|
||||||
_contentLength = convertContentLength(_valueString);
|
_contentLength = contentLength;
|
||||||
if (_contentLength <= 0)
|
|
||||||
_endOfContent = EndOfContent.NO_CONTENT;
|
|
||||||
else
|
|
||||||
_endOfContent = EndOfContent.CONTENT_LENGTH;
|
_endOfContent = EndOfContent.CONTENT_LENGTH;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1062,7 +1058,6 @@ public class HttpParser
|
||||||
_parsedHost = _valueString;
|
_parsedHost = _valueString;
|
||||||
if (!(_field instanceof HostPortHttpField) && _valueString != null && !_valueString.isEmpty())
|
if (!(_field instanceof HostPortHttpField) && _valueString != null && !_valueString.isEmpty())
|
||||||
{
|
{
|
||||||
HostPort hostPort;
|
|
||||||
if (UNSAFE_HOST_HEADER.isAllowedBy(_complianceMode))
|
if (UNSAFE_HOST_HEADER.isAllowedBy(_complianceMode))
|
||||||
{
|
{
|
||||||
_field = new HostPortHttpField(_header,
|
_field = new HostPortHttpField(_header,
|
||||||
|
@ -1134,15 +1129,21 @@ public class HttpParser
|
||||||
|
|
||||||
private long convertContentLength(String valueString)
|
private long convertContentLength(String valueString)
|
||||||
{
|
{
|
||||||
try
|
if (valueString == null || valueString.length() == 0)
|
||||||
|
throw new BadMessageException("Invalid Content-Length Value", new NumberFormatException());
|
||||||
|
|
||||||
|
long value = 0;
|
||||||
|
int length = valueString.length();
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
return Long.parseLong(valueString);
|
char c = valueString.charAt(i);
|
||||||
}
|
if (c < '0' || c > '9')
|
||||||
catch (NumberFormatException e)
|
throw new BadMessageException("Invalid Content-Length Value", new NumberFormatException());
|
||||||
{
|
|
||||||
LOG.trace("IGNORED", e);
|
value = Math.addExact(Math.multiplyExact(value, 10), c - '0');
|
||||||
throw new BadMessageException("Invalid Content-Length Value", e);
|
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1528,8 +1529,7 @@ public class HttpParser
|
||||||
_header = null;
|
_header = null;
|
||||||
if (buffer.hasRemaining())
|
if (buffer.hasRemaining())
|
||||||
_beginNanoTime = NanoTime.now(); // TODO #9900 check beginNanoTime's accuracy
|
_beginNanoTime = NanoTime.now(); // TODO #9900 check beginNanoTime's accuracy
|
||||||
if (quickStart(buffer))
|
quickStart(buffer);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request/response line
|
// Request/response line
|
||||||
|
@ -2056,7 +2056,6 @@ public class HttpParser
|
||||||
void startResponse(HttpVersion version, int status, String reason);
|
void startResponse(HttpVersion version, int status, String reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
private static class IllegalCharacterException extends BadMessageException
|
private static class IllegalCharacterException extends BadMessageException
|
||||||
{
|
{
|
||||||
private IllegalCharacterException(State state, HttpTokens.Token token, ByteBuffer buffer)
|
private IllegalCharacterException(State state, HttpTokens.Token token, ByteBuffer buffer)
|
||||||
|
|
|
@ -42,6 +42,7 @@ import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
@ -1946,67 +1947,30 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(strings = {"\r\n", "\n"})
|
@ValueSource(strings = {
|
||||||
public void testBadContentLength0(String eoln)
|
"abc",
|
||||||
|
"1.5",
|
||||||
|
"9999999999999999999999999999999999999999999999",
|
||||||
|
"-10",
|
||||||
|
"+10",
|
||||||
|
"1.0",
|
||||||
|
"1,0",
|
||||||
|
"10,"
|
||||||
|
})
|
||||||
|
public void testBadContentLengths(String contentLength)
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0" + eoln +
|
"GET /test HTTP/1.1\r\n" +
|
||||||
"Content-Length: abc" + eoln +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close" + eoln +
|
"Content-Length: " + contentLength + "\r\n" +
|
||||||
eoln);
|
"\r\n" +
|
||||||
|
"1234567890\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);
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
assertThat(_bad, notNullValue());
|
||||||
assertEquals("GET", _methodOrVersion);
|
|
||||||
assertEquals("Invalid Content-Length Value", _bad);
|
|
||||||
assertFalse(buffer.hasRemaining());
|
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
|
||||||
parser.atEOF();
|
|
||||||
parser.parseNext(BufferUtil.EMPTY_BUFFER);
|
|
||||||
assertEquals(HttpParser.State.CLOSED, parser.getState());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@ValueSource(strings = {"\r\n", "\n"})
|
|
||||||
public void testBadContentLength1(String eoln)
|
|
||||||
{
|
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
|
||||||
"GET / HTTP/1.0" + eoln +
|
|
||||||
"Content-Length: 9999999999999999999999999999999999999999999999" + eoln +
|
|
||||||
"Connection: close" + eoln +
|
|
||||||
eoln);
|
|
||||||
|
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
|
||||||
HttpParser parser = new HttpParser(handler);
|
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
|
||||||
assertEquals("GET", _methodOrVersion);
|
|
||||||
assertEquals("Invalid Content-Length Value", _bad);
|
|
||||||
assertFalse(buffer.hasRemaining());
|
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
|
||||||
parser.atEOF();
|
|
||||||
parser.parseNext(BufferUtil.EMPTY_BUFFER);
|
|
||||||
assertEquals(HttpParser.State.CLOSED, parser.getState());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@ValueSource(strings = {"\r\n", "\n"})
|
|
||||||
public void testBadContentLength2(String eoln)
|
|
||||||
{
|
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
|
||||||
"GET / HTTP/1.0" + eoln +
|
|
||||||
"Content-Length: 1.5" + eoln +
|
|
||||||
"Connection: close" + eoln +
|
|
||||||
eoln);
|
|
||||||
|
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
|
||||||
HttpParser parser = new HttpParser(handler);
|
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
|
||||||
assertEquals("GET", _methodOrVersion);
|
|
||||||
assertEquals("Invalid Content-Length Value", _bad);
|
|
||||||
assertFalse(buffer.hasRemaining());
|
assertFalse(buffer.hasRemaining());
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
parser.atEOF();
|
parser.atEOF();
|
||||||
|
@ -2262,7 +2226,7 @@ public class HttpParserTest
|
||||||
|
|
||||||
public static Stream<String> badHostHeaderSource()
|
public static Stream<String> badHostHeaderSource()
|
||||||
{
|
{
|
||||||
return List.of(
|
return Stream.of(
|
||||||
":80", // no host, port only
|
":80", // no host, port only
|
||||||
"host:", // no port
|
"host:", // no port
|
||||||
"127.0.0.1:", // no port
|
"127.0.0.1:", // no port
|
||||||
|
@ -2297,7 +2261,7 @@ public class HttpParserTest
|
||||||
"' *; host xyz.hacking.pro; '",
|
"' *; host xyz.hacking.pro; '",
|
||||||
"'/**/OR/**/1/**/=/**/1",
|
"'/**/OR/**/1/**/=/**/1",
|
||||||
"AND (SELECT 1 FROM(SELECT COUNT(*),CONCAT('x',(SELECT (ELT(1=1,1))),'x',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)"
|
"AND (SELECT 1 FROM(SELECT COUNT(*),CONCAT('x',(SELECT (ELT(1=1,1))),'x',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)"
|
||||||
).stream();
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
|
|
Loading…
Reference in New Issue