Skip to content

Commit 39789d0

Browse files
authored
GEO: More robust handling of ignore_malformed in geoshape parsing (#35603)
Adds an XContent sub parser class that can to wrap another XContent parser at the beginning of an object and allow skiping all children in case of the parsing failure. It also uses this subparser to ignore the rest of the GeoJson shape if the parsing fails and we need to ignore the geoshape due to the ignore_malformed flag. Supersedes #34498 Closes #34047
1 parent 1a5553d commit 39789d0

File tree

5 files changed

+479
-29
lines changed

5 files changed

+479
-29
lines changed
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.common.xcontent;
21+
22+
import java.io.IOException;
23+
import java.nio.CharBuffer;
24+
import java.util.List;
25+
import java.util.Map;
26+
27+
/**
28+
* Wrapper for a XContentParser that makes a single object to look like a complete document.
29+
*
30+
* The wrapper prevents the parsing logic to consume tokens outside of the wrapped object as well
31+
* as skipping to the end of the object in case of a parsing error. The wrapper is intended to be
32+
* used for parsing objects that should be ignored if they are malformed.
33+
*/
34+
public class XContentSubParser implements XContentParser {
35+
36+
private final XContentParser parser;
37+
private int level;
38+
private boolean closed;
39+
40+
public XContentSubParser(XContentParser parser) {
41+
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;
46+
}
47+
48+
@Override
49+
public XContentType contentType() {
50+
return parser.contentType();
51+
}
52+
53+
@Override
54+
public Token nextToken() throws IOException {
55+
if (level > 0) {
56+
Token token = parser.nextToken();
57+
if (token == Token.START_OBJECT || token == Token.START_ARRAY) {
58+
level++;
59+
} else if (token == Token.END_OBJECT || token == Token.END_ARRAY) {
60+
level--;
61+
}
62+
return token;
63+
} else {
64+
return null; // we have reached the end of the wrapped object
65+
}
66+
}
67+
68+
@Override
69+
public void skipChildren() throws IOException {
70+
Token token = parser.currentToken();
71+
if (token != Token.START_OBJECT && token != Token.START_ARRAY) {
72+
// skip if not starting on an object or an array
73+
return;
74+
}
75+
int backToLevel = level - 1;
76+
while (nextToken() != null) {
77+
if (level <= backToLevel) {
78+
return;
79+
}
80+
}
81+
}
82+
83+
@Override
84+
public Token currentToken() {
85+
return parser.currentToken();
86+
}
87+
88+
@Override
89+
public String currentName() throws IOException {
90+
return parser.currentName();
91+
}
92+
93+
@Override
94+
public Map<String, Object> map() throws IOException {
95+
return parser.map();
96+
}
97+
98+
@Override
99+
public Map<String, Object> mapOrdered() throws IOException {
100+
return parser.mapOrdered();
101+
}
102+
103+
@Override
104+
public Map<String, String> mapStrings() throws IOException {
105+
return parser.mapStrings();
106+
}
107+
108+
@Override
109+
public Map<String, String> mapStringsOrdered() throws IOException {
110+
return parser.mapStringsOrdered();
111+
}
112+
113+
@Override
114+
public List<Object> list() throws IOException {
115+
return parser.list();
116+
}
117+
118+
@Override
119+
public List<Object> listOrderedMap() throws IOException {
120+
return parser.listOrderedMap();
121+
}
122+
123+
@Override
124+
public String text() throws IOException {
125+
return parser.text();
126+
}
127+
128+
@Override
129+
public String textOrNull() throws IOException {
130+
return parser.textOrNull();
131+
}
132+
133+
@Override
134+
public CharBuffer charBufferOrNull() throws IOException {
135+
return parser.charBufferOrNull();
136+
}
137+
138+
@Override
139+
public CharBuffer charBuffer() throws IOException {
140+
return parser.charBuffer();
141+
}
142+
143+
@Override
144+
public Object objectText() throws IOException {
145+
return parser.objectText();
146+
}
147+
148+
@Override
149+
public Object objectBytes() throws IOException {
150+
return parser.objectBytes();
151+
}
152+
153+
@Override
154+
public boolean hasTextCharacters() {
155+
return parser.hasTextCharacters();
156+
}
157+
158+
@Override
159+
public char[] textCharacters() throws IOException {
160+
return parser.textCharacters();
161+
}
162+
163+
@Override
164+
public int textLength() throws IOException {
165+
return parser.textLength();
166+
}
167+
168+
@Override
169+
public int textOffset() throws IOException {
170+
return parser.textOffset();
171+
}
172+
173+
@Override
174+
public Number numberValue() throws IOException {
175+
return parser.numberValue();
176+
}
177+
178+
@Override
179+
public NumberType numberType() throws IOException {
180+
return parser.numberType();
181+
}
182+
183+
@Override
184+
public short shortValue(boolean coerce) throws IOException {
185+
return parser.shortValue(coerce);
186+
}
187+
188+
@Override
189+
public int intValue(boolean coerce) throws IOException {
190+
return parser.intValue(coerce);
191+
}
192+
193+
@Override
194+
public long longValue(boolean coerce) throws IOException {
195+
return parser.longValue(coerce);
196+
}
197+
198+
@Override
199+
public float floatValue(boolean coerce) throws IOException {
200+
return parser.floatValue(coerce);
201+
}
202+
203+
@Override
204+
public double doubleValue(boolean coerce) throws IOException {
205+
return parser.doubleValue();
206+
}
207+
208+
@Override
209+
public short shortValue() throws IOException {
210+
return parser.shortValue();
211+
}
212+
213+
@Override
214+
public int intValue() throws IOException {
215+
return parser.intValue();
216+
}
217+
218+
@Override
219+
public long longValue() throws IOException {
220+
return parser.longValue();
221+
}
222+
223+
@Override
224+
public float floatValue() throws IOException {
225+
return parser.floatValue();
226+
}
227+
228+
@Override
229+
public double doubleValue() throws IOException {
230+
return parser.doubleValue();
231+
}
232+
233+
@Override
234+
public boolean isBooleanValue() throws IOException {
235+
return parser.isBooleanValue();
236+
}
237+
238+
@Override
239+
public boolean booleanValue() throws IOException {
240+
return parser.booleanValue();
241+
}
242+
243+
@Override
244+
public byte[] binaryValue() throws IOException {
245+
return parser.binaryValue();
246+
}
247+
248+
@Override
249+
public XContentLocation getTokenLocation() {
250+
return parser.getTokenLocation();
251+
}
252+
253+
@Override
254+
public <T> T namedObject(Class<T> categoryClass, String name, Object context) throws IOException {
255+
return parser.namedObject(categoryClass, name, context);
256+
}
257+
258+
@Override
259+
public NamedXContentRegistry getXContentRegistry() {
260+
return parser.getXContentRegistry();
261+
}
262+
263+
@Override
264+
public boolean isClosed() {
265+
return closed;
266+
}
267+
268+
@Override
269+
public DeprecationHandler getDeprecationHandler() {
270+
return parser.getDeprecationHandler();
271+
}
272+
273+
@Override
274+
public void close() throws IOException {
275+
if (closed == false) {
276+
closed = true;
277+
while (true) {
278+
if (nextToken() == null) {
279+
return;
280+
}
281+
}
282+
}
283+
}
284+
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@
2222
import com.fasterxml.jackson.core.JsonLocation;
2323
import com.fasterxml.jackson.core.JsonParser;
2424
import com.fasterxml.jackson.core.JsonToken;
25-
26-
import org.elasticsearch.core.internal.io.IOUtils;
2725
import org.elasticsearch.common.xcontent.DeprecationHandler;
2826
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
2927
import org.elasticsearch.common.xcontent.XContentLocation;
3028
import org.elasticsearch.common.xcontent.XContentType;
3129
import org.elasticsearch.common.xcontent.support.AbstractXContentParser;
30+
import org.elasticsearch.core.internal.io.IOUtils;
3231

3332
import java.io.IOException;
3433
import java.nio.CharBuffer;

0 commit comments

Comments
 (0)