Skip to content

Commit e4791a9

Browse files
Geo Point parse error fix
When geo point parsing threw a parse exception, it did not consume remaining tokens from the parser. This in turn meant that indexing documents with malformed geo points into mappings with ignore_malformed=true would fail in some cases, since DocumentParser expects geo_point parsing to end on the END_OBJECT token. Related to #17617
1 parent fd192dc commit e4791a9

File tree

2 files changed

+18
-34
lines changed

2 files changed

+18
-34
lines changed

libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContentSubParser.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,8 @@ public class XContentSubParser implements XContentParser {
3939

4040
public XContentSubParser(XContentParser parser) {
4141
this.parser = parser;
42-
if (parser.currentToken() != Token.START_OBJECT) {
43-
throw new IllegalStateException("The sub parser has to be created on the start of an object");
44-
}
45-
level = 1;
42+
// we allow a non-object, non-array with semantics that it is the single item only.
43+
this.level = parser.currentToken() == Token.START_OBJECT || parser.currentToken() == Token.START_ARRAY ? 1 : 0;
4644
}
4745

4846
@Override

server/src/main/java/org/elasticsearch/common/geo/GeoUtils.java

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.elasticsearch.common.xcontent.XContentBuilder;
3232
import org.elasticsearch.common.xcontent.XContentParser;
3333
import org.elasticsearch.common.xcontent.XContentParser.Token;
34+
import org.elasticsearch.common.xcontent.XContentSubParser;
3435
import org.elasticsearch.common.xcontent.json.JsonXContent;
3536
import org.elasticsearch.common.xcontent.support.XContentMapValues;
3637
import org.elasticsearch.index.fielddata.FieldData;
@@ -429,11 +430,18 @@ public static GeoPoint parseGeoPoint(XContentParser parser, GeoPoint point, fina
429430
*/
430431
public static GeoPoint parseGeoPoint(XContentParser parser, GeoPoint point, final boolean ignoreZValue, EffectivePoint effectivePoint)
431432
throws IOException, ElasticsearchParseException {
433+
try (XContentSubParser subParser = new XContentSubParser(parser)) {
434+
return parseGeoPointUnsafe(subParser, point, ignoreZValue, effectivePoint);
435+
}
436+
}
437+
438+
private static GeoPoint parseGeoPointUnsafe(XContentParser parser, GeoPoint point, final boolean ignoreZValue,
439+
EffectivePoint effectivePoint)
440+
throws IOException, ElasticsearchParseException {
432441
double lat = Double.NaN;
433442
double lon = Double.NaN;
434443
String geohash = null;
435444
NumberFormatException numberFormatException = null;
436-
ParseExceptionConsumer exceptionConsumer = new ParseExceptionConsumer();
437445

438446
if(parser.currentToken() == Token.START_OBJECT) {
439447
while(parser.nextToken() != Token.END_OBJECT) {
@@ -451,7 +459,7 @@ public static GeoPoint parseGeoPoint(XContentParser parser, GeoPoint point, fina
451459
}
452460
break;
453461
default:
454-
exceptionConsumer.consume(new ElasticsearchParseException("latitude must be a number"));
462+
throw new ElasticsearchParseException("latitude must be a number");
455463
}
456464
} else if (LONGITUDE.equals(field)) {
457465
parser.nextToken();
@@ -465,25 +473,22 @@ public static GeoPoint parseGeoPoint(XContentParser parser, GeoPoint point, fina
465473
}
466474
break;
467475
default:
468-
exceptionConsumer.consume(new ElasticsearchParseException("longitude must be a number"));
476+
throw new ElasticsearchParseException("longitude must be a number");
469477
}
470478
} else if (GEOHASH.equals(field)) {
471479
if(parser.nextToken() == Token.VALUE_STRING) {
472480
geohash = parser.text();
473481
} else {
474-
exceptionConsumer.consume(new ElasticsearchParseException("geohash must be a string"));
482+
throw new ElasticsearchParseException("geohash must be a string");
475483
}
476484
} else {
477-
exceptionConsumer.consume(new ElasticsearchParseException("field must be either [{}], [{}] or [{}]",
478-
LATITUDE, LONGITUDE, GEOHASH));
485+
throw new ElasticsearchParseException("field must be either [{}], [{}] or [{}]", LATITUDE, LONGITUDE, GEOHASH);
479486
}
480487
} else {
481-
exceptionConsumer.consume(new ElasticsearchParseException("token [{}] not allowed", parser.currentToken()));
488+
throw new ElasticsearchParseException("token [{}] not allowed", parser.currentToken());
482489
}
483490
}
484491

485-
exceptionConsumer.doThrow();
486-
487492
if (geohash != null) {
488493
if(!Double.isNaN(lat) || !Double.isNaN(lon)) {
489494
throw new ElasticsearchParseException("field must be either lat/lon or geohash");
@@ -511,17 +516,12 @@ public static GeoPoint parseGeoPoint(XContentParser parser, GeoPoint point, fina
511516
} else if(element == 2) {
512517
lat = parser.doubleValue();
513518
} else {
514-
try {
515-
GeoPoint.assertZValue(ignoreZValue, parser.doubleValue());
516-
} catch (ElasticsearchParseException e) {
517-
exceptionConsumer.consume(e);
518-
}
519+
GeoPoint.assertZValue(ignoreZValue, parser.doubleValue());
519520
}
520521
} else {
521-
exceptionConsumer.consume(new ElasticsearchParseException("numeric value expected"));
522+
throw new ElasticsearchParseException("numeric value expected");
522523
}
523524
}
524-
exceptionConsumer.doThrow();
525525
return point.reset(lat, lon);
526526
} else if(parser.currentToken() == Token.VALUE_STRING) {
527527
String val = parser.text();
@@ -704,20 +704,6 @@ public boolean advanceExact(int target) throws IOException {
704704
}
705705
}
706706

707-
private static class ParseExceptionConsumer {
708-
private ElasticsearchParseException exception;
709-
710-
public void consume(ElasticsearchParseException e) {
711-
if (exception == null)
712-
exception = e;
713-
}
714-
715-
public void doThrow() {
716-
if (exception != null)
717-
throw exception;
718-
}
719-
}
720-
721707
private GeoUtils() {
722708
}
723709
}

0 commit comments

Comments
 (0)