OLINGO-1046: allowing bad white space where OData specificationa allows during the URL parsing

This commit is contained in:
Ramesh Reddy 2017-04-20 11:07:26 -05:00
parent 7e262c8d07
commit 2751c130e2
6 changed files with 58 additions and 2 deletions

View File

@ -251,6 +251,7 @@ public class ExpandParser {
} else if (tokenizer.next(TokenKind.SEARCH)) {
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
ParserHelper.bws(tokenizer);
systemQueryOption = new SearchParser().parse(tokenizer);
} else if (!forRef && !forCount && tokenizer.next(TokenKind.SELECT)) {

View File

@ -254,12 +254,15 @@ public class ExpressionParser {
// The TokenKind 'IsOfMethod' consumes also the opening parenthesis.
// The first parameter could be an expression or a type literal.
List<Expression> parameters = new ArrayList<Expression>();
ParserHelper.bws(tokenizer);
parameters.add(parseExpression());
if (!(parameters.get(0) instanceof TypeLiteral)) {
// The first parameter is not a type literal, so there must be a second parameter.
ParserHelper.bws(tokenizer);
ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
ParserHelper.bws(tokenizer);
parameters.add(parseExpression());
ParserHelper.bws(tokenizer);
// The second parameter must be a type literal.
if (!(parameters.get(1) instanceof TypeLiteral)) {
throw new UriParserSemanticException("Type literal expected.",
@ -335,7 +338,9 @@ public class ExpressionParser {
private Expression parseExprValue() throws UriParserException, UriValidationException {
if (tokenizer.next(TokenKind.OPEN)) {
ParserHelper.bws(tokenizer);
final Expression expression = parseExpression();
ParserHelper.bws(tokenizer);
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return expression;
}
@ -441,6 +446,7 @@ public class ExpressionParser {
case NOW:
case MAXDATETIME:
case MINDATETIME:
ParserHelper.bws(tokenizer);
break;
// Must have one parameter.
@ -448,7 +454,9 @@ public class ExpressionParser {
case TOLOWER:
case TOUPPER:
case TRIM:
ParserHelper.bws(tokenizer);
final Expression stringParameter = parseExpression();
ParserHelper.bws(tokenizer);
checkType(stringParameter, EdmPrimitiveTypeKind.String);
checkNoCollection(stringParameter);
parameters.add(stringParameter);
@ -456,7 +464,9 @@ public class ExpressionParser {
case YEAR:
case MONTH:
case DAY:
ParserHelper.bws(tokenizer);
final Expression dateParameter = parseExpression();
ParserHelper.bws(tokenizer);
checkType(dateParameter, EdmPrimitiveTypeKind.Date, EdmPrimitiveTypeKind.DateTimeOffset);
checkNoCollection(dateParameter);
parameters.add(dateParameter);
@ -465,7 +475,9 @@ public class ExpressionParser {
case MINUTE:
case SECOND:
case FRACTIONALSECONDS:
ParserHelper.bws(tokenizer);
final Expression timeParameter = parseExpression();
ParserHelper.bws(tokenizer);
checkType(timeParameter, EdmPrimitiveTypeKind.TimeOfDay, EdmPrimitiveTypeKind.DateTimeOffset);
checkNoCollection(timeParameter);
parameters.add(timeParameter);
@ -473,13 +485,17 @@ public class ExpressionParser {
case DATE:
case TIME:
case TOTALOFFSETMINUTES:
ParserHelper.bws(tokenizer);
final Expression dateTimeParameter = parseExpression();
ParserHelper.bws(tokenizer);
checkType(dateTimeParameter, EdmPrimitiveTypeKind.DateTimeOffset);
checkNoCollection(dateTimeParameter);
parameters.add(dateTimeParameter);
break;
case TOTALSECONDS:
ParserHelper.bws(tokenizer);
final Expression durationParameter = parseExpression();
ParserHelper.bws(tokenizer);
checkType(durationParameter, EdmPrimitiveTypeKind.Duration);
checkNoCollection(durationParameter);
parameters.add(durationParameter);
@ -487,14 +503,18 @@ public class ExpressionParser {
case ROUND:
case FLOOR:
case CEILING:
ParserHelper.bws(tokenizer);
final Expression decimalParameter = parseExpression();
ParserHelper.bws(tokenizer);
checkType(decimalParameter,
EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double);
checkNoCollection(decimalParameter);
parameters.add(decimalParameter);
break;
case GEOLENGTH:
ParserHelper.bws(tokenizer);
final Expression geoParameter = parseExpression();
ParserHelper.bws(tokenizer);
checkType(geoParameter,
EdmPrimitiveTypeKind.GeographyLineString, EdmPrimitiveTypeKind.GeometryLineString);
checkNoCollection(geoParameter);
@ -507,35 +527,47 @@ public class ExpressionParser {
case STARTSWITH:
case INDEXOF:
case CONCAT:
ParserHelper.bws(tokenizer);
final Expression stringParameter1 = parseExpression();
checkType(stringParameter1, EdmPrimitiveTypeKind.String);
checkNoCollection(stringParameter1);
parameters.add(stringParameter1);
ParserHelper.bws(tokenizer);
ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
ParserHelper.bws(tokenizer);
final Expression stringParameter2 = parseExpression();
ParserHelper.bws(tokenizer);
checkType(stringParameter2, EdmPrimitiveTypeKind.String);
checkNoCollection(stringParameter2);
parameters.add(stringParameter2);
break;
case GEODISTANCE:
ParserHelper.bws(tokenizer);
final Expression geoParameter1 = parseExpression();
checkType(geoParameter1, EdmPrimitiveTypeKind.GeographyPoint, EdmPrimitiveTypeKind.GeometryPoint);
checkNoCollection(geoParameter1);
parameters.add(geoParameter1);
ParserHelper.bws(tokenizer);
ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
ParserHelper.bws(tokenizer);
final Expression geoParameter2 = parseExpression();
ParserHelper.bws(tokenizer);
checkType(geoParameter2, EdmPrimitiveTypeKind.GeographyPoint, EdmPrimitiveTypeKind.GeometryPoint);
checkNoCollection(geoParameter2);
parameters.add(geoParameter2);
break;
case GEOINTERSECTS:
ParserHelper.bws(tokenizer);
final Expression geoPointParameter = parseExpression();
checkType(geoPointParameter,
EdmPrimitiveTypeKind.GeographyPoint, EdmPrimitiveTypeKind.GeometryPoint);
checkNoCollection(geoPointParameter);
parameters.add(geoPointParameter);
ParserHelper.bws(tokenizer);
ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
ParserHelper.bws(tokenizer);
final Expression geoPolygonParameter = parseExpression();
ParserHelper.bws(tokenizer);
checkType(geoPolygonParameter,
EdmPrimitiveTypeKind.GeographyPolygon, EdmPrimitiveTypeKind.GeometryPolygon);
checkNoCollection(geoPolygonParameter);
@ -544,16 +576,23 @@ public class ExpressionParser {
// Can have two or three parameters.
case SUBSTRING:
ParserHelper.bws(tokenizer);
final Expression parameterFirst = parseExpression();
checkType(parameterFirst, EdmPrimitiveTypeKind.String);
checkNoCollection(parameterFirst);
parameters.add(parameterFirst);
ParserHelper.bws(tokenizer);
ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
ParserHelper.bws(tokenizer);
final Expression parameterSecond = parseExpression();
ParserHelper.bws(tokenizer);
checkIntegerType(parameterSecond);
parameters.add(parameterSecond);
ParserHelper.bws(tokenizer);
if (tokenizer.next(TokenKind.COMMA)) {
ParserHelper.bws(tokenizer);
final Expression parameterThird = parseExpression();
ParserHelper.bws(tokenizer);
checkIntegerType(parameterThird);
parameters.add(parameterThird);
}

View File

@ -108,6 +108,10 @@ public class ParserHelper {
requireNext(tokenizer, TokenKind.EOF);
}
protected static boolean bws(UriTokenizer tokenizer) {
return tokenizer.nextWhitespace();
}
protected static TokenKind next(UriTokenizer tokenizer, final TokenKind... kinds) {
for (final TokenKind kind : kinds) {
if (tokenizer.next(kind)) {

View File

@ -71,7 +71,9 @@ public class SearchParser {
private SearchExpression processTerm(UriTokenizer tokenizer) throws SearchParserException {
if (tokenizer.next(TokenKind.OPEN)) {
ParserHelper.bws(tokenizer);
final SearchExpression expr = processExprOr(tokenizer);
ParserHelper.bws(tokenizer);
if (!tokenizer.next(TokenKind.CLOSE)) {
throw new SearchParserException("Missing close parenthesis after open parenthesis.",
SearchParserException.MessageKeys.MISSING_CLOSE);

View File

@ -801,7 +801,7 @@ public class UriTokenizer {
* otherwise leaves the index unchanged.
* @return whether whitespace characters have been found at the current index
*/
private boolean nextWhitespace() {
boolean nextWhitespace() {
int count = 0;
while (nextCharacter(' ') || nextCharacter('\t')) {
count++;

View File

@ -149,6 +149,10 @@ public class ExpressionParserTest {
expression = parseExpression("-(5 add 5)");
assertEquals("{MINUS {5 ADD 5}}", expression.toString());
expression = parseExpression("-( 5 add 5\t)");
assertEquals("{MINUS {5 ADD 5}}", expression.toString());
}
@Test
@ -191,6 +195,8 @@ public class ExpressionParserTest {
wrongExpression("trim()");
wrongExpression("trim(1)");
wrongExpression("ceiling('1.2')");
assertEquals("{trim ['abc']}", parseExpression("trim( 'abc' )").toString());
}
@Test
@ -209,6 +215,8 @@ public class ExpressionParserTest {
wrongExpression("concat('a')");
wrongExpression("endswith('a',1)");
assertEquals("{concat ['a', 'b']}", parseExpression("concat( 'a' ,\t'b' )").toString());
}
@Test
@ -227,6 +235,8 @@ public class ExpressionParserTest {
wrongExpression("substring(1,2)");
wrongExpression("cast(1,2)");
wrongExpression("isof(Edm.Int16,2)");
assertEquals("{cast [42, Edm.SByte]}", parseExpression("cast( 42\t, Edm.SByte )").toString());
}
private void parseMethod(TokenKind kind, String... parameters) throws UriParserException, UriValidationException {