Ensure we protect Collections obtained from scripts from self-referencing (#28335)
Self referencing maps can cause SOE if they are iterated ie. in their toString methods. This chance adds some protected to the usage of those collections.
This commit is contained in:
parent
b2ce994be7
commit
4d3f7a7695
|
@ -20,6 +20,7 @@
|
||||||
package org.elasticsearch.script.mustache;
|
package org.elasticsearch.script.mustache;
|
||||||
|
|
||||||
import com.github.mustachejava.reflect.ReflectionObjectHandler;
|
import com.github.mustachejava.reflect.ReflectionObjectHandler;
|
||||||
|
import org.elasticsearch.common.util.CollectionUtils;
|
||||||
import org.elasticsearch.common.util.iterable.Iterables;
|
import org.elasticsearch.common.util.iterable.Iterables;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
|
@ -154,4 +155,9 @@ final class CustomReflectionObjectHandler extends ReflectionObjectHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String stringify(Object object) {
|
||||||
|
CollectionUtils.ensureNoSelfReferences(object);
|
||||||
|
return super.stringify(object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,4 +137,4 @@
|
||||||
|
|
||||||
- match: { error.root_cause.0.type: "remote_transport_exception" }
|
- match: { error.root_cause.0.type: "remote_transport_exception" }
|
||||||
- match: { error.type: "illegal_argument_exception" }
|
- match: { error.type: "illegal_argument_exception" }
|
||||||
- match: { error.reason: "Object has already been built and is self-referencing itself" }
|
- match: { error.reason: "Iterable object is self-referencing itself" }
|
||||||
|
|
|
@ -406,3 +406,39 @@
|
||||||
- match: { hits.hits.0._score: 1.0 }
|
- match: { hits.hits.0._score: 1.0 }
|
||||||
- match: { aggregations.value_agg.buckets.0.key: 2 }
|
- match: { aggregations.value_agg.buckets.0.key: 2 }
|
||||||
- match: { aggregations.value_agg.buckets.0.doc_count: 1 }
|
- match: { aggregations.value_agg.buckets.0.doc_count: 1 }
|
||||||
|
|
||||||
|
---
|
||||||
|
"Return self-referencing map":
|
||||||
|
- do:
|
||||||
|
indices.create:
|
||||||
|
index: test
|
||||||
|
body:
|
||||||
|
settings:
|
||||||
|
number_of_shards: "1"
|
||||||
|
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: test
|
||||||
|
type: test
|
||||||
|
id: 1
|
||||||
|
body: { "genre": 1 }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
indices.refresh: {}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
catch: bad_request
|
||||||
|
index: test
|
||||||
|
search:
|
||||||
|
body:
|
||||||
|
aggs:
|
||||||
|
genre:
|
||||||
|
terms:
|
||||||
|
script:
|
||||||
|
lang: painless
|
||||||
|
source: "def x = [:] ; def y = [:] ; x.a = y ; y.a = x ; return x"
|
||||||
|
|
||||||
|
- match: { error.root_cause.0.type: "illegal_argument_exception" }
|
||||||
|
- match: { error.root_cause.0.reason: "Iterable object is self-referencing itself" }
|
||||||
|
- match: { error.type: "search_phase_execution_exception" }
|
||||||
|
- match: { error.reason: "all shards failed" }
|
||||||
|
|
|
@ -19,16 +19,20 @@
|
||||||
|
|
||||||
package org.elasticsearch.common.util;
|
package org.elasticsearch.common.util;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.RandomAccess;
|
import java.util.RandomAccess;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.carrotsearch.hppc.ObjectArrayList;
|
import com.carrotsearch.hppc.ObjectArrayList;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
@ -221,6 +225,40 @@ public class CollectionUtils {
|
||||||
return ints.stream().mapToInt(s -> s).toArray();
|
return ints.stream().mapToInt(s -> s).toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ensureNoSelfReferences(Object value) {
|
||||||
|
Iterable<?> it = convert(value);
|
||||||
|
if (it != null) {
|
||||||
|
ensureNoSelfReferences(it, value, Collections.newSetFromMap(new IdentityHashMap<>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Iterable<?> convert(Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (value instanceof Map) {
|
||||||
|
return ((Map<?,?>) value).values();
|
||||||
|
} else if ((value instanceof Iterable) && (value instanceof Path == false)) {
|
||||||
|
return (Iterable<?>) value;
|
||||||
|
} else if (value instanceof Object[]) {
|
||||||
|
return Arrays.asList((Object[]) value);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureNoSelfReferences(final Iterable<?> value, Object originalReference, final Set<Object> ancestors) {
|
||||||
|
if (value != null) {
|
||||||
|
if (ancestors.add(originalReference) == false) {
|
||||||
|
throw new IllegalArgumentException("Iterable object is self-referencing itself");
|
||||||
|
}
|
||||||
|
for (Object o : value) {
|
||||||
|
ensureNoSelfReferences(convert(o), o, ancestors);
|
||||||
|
}
|
||||||
|
ancestors.remove(originalReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class RotatedList<T> extends AbstractList<T> implements RandomAccess {
|
private static class RotatedList<T> extends AbstractList<T> implements RandomAccess {
|
||||||
|
|
||||||
private final List<T> in;
|
private final List<T> in;
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.elasticsearch.common.lease.Releasable;
|
||||||
import org.elasticsearch.common.text.Text;
|
import org.elasticsearch.common.text.Text;
|
||||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.common.util.CollectionUtils;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
import org.joda.time.ReadableInstant;
|
import org.joda.time.ReadableInstant;
|
||||||
import org.joda.time.format.DateTimeFormatter;
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
|
@ -43,7 +44,6 @@ import java.util.Calendar;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.IdentityHashMap;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -780,7 +780,6 @@ public final class XContentBuilder implements Releasable, Flushable {
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
return nullValue();
|
return nullValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
return value(Arrays.asList(values), ensureNoSelfReferences);
|
return value(Arrays.asList(values), ensureNoSelfReferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,7 +864,7 @@ public final class XContentBuilder implements Releasable, Flushable {
|
||||||
// checks that the map does not contain references to itself because
|
// checks that the map does not contain references to itself because
|
||||||
// iterating over map entries will cause a stackoverflow error
|
// iterating over map entries will cause a stackoverflow error
|
||||||
if (ensureNoSelfReferences) {
|
if (ensureNoSelfReferences) {
|
||||||
ensureNoSelfReferences(values);
|
CollectionUtils.ensureNoSelfReferences(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
startObject();
|
startObject();
|
||||||
|
@ -894,9 +893,8 @@ public final class XContentBuilder implements Releasable, Flushable {
|
||||||
// checks that the iterable does not contain references to itself because
|
// checks that the iterable does not contain references to itself because
|
||||||
// iterating over entries will cause a stackoverflow error
|
// iterating over entries will cause a stackoverflow error
|
||||||
if (ensureNoSelfReferences) {
|
if (ensureNoSelfReferences) {
|
||||||
ensureNoSelfReferences(values);
|
CollectionUtils.ensureNoSelfReferences(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
startArray();
|
startArray();
|
||||||
for (Object value : values) {
|
for (Object value : values) {
|
||||||
// pass ensureNoSelfReferences=false as we already performed the check at a higher level
|
// pass ensureNoSelfReferences=false as we already performed the check at a higher level
|
||||||
|
@ -1067,32 +1065,4 @@ public final class XContentBuilder implements Releasable, Flushable {
|
||||||
throw new IllegalArgumentException(message);
|
throw new IllegalArgumentException(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ensureNoSelfReferences(Object value) {
|
|
||||||
ensureNoSelfReferences(value, Collections.newSetFromMap(new IdentityHashMap<>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ensureNoSelfReferences(final Object value, final Set<Object> ancestors) {
|
|
||||||
if (value != null) {
|
|
||||||
|
|
||||||
Iterable<?> it;
|
|
||||||
if (value instanceof Map) {
|
|
||||||
it = ((Map<?,?>) value).values();
|
|
||||||
} else if ((value instanceof Iterable) && (value instanceof Path == false)) {
|
|
||||||
it = (Iterable<?>) value;
|
|
||||||
} else if (value instanceof Object[]) {
|
|
||||||
it = Arrays.asList((Object[]) value);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ancestors.add(value) == false) {
|
|
||||||
throw new IllegalArgumentException("Object has already been built and is self-referencing itself");
|
|
||||||
}
|
|
||||||
for (Object o : it) {
|
|
||||||
ensureNoSelfReferences(o, ancestors);
|
|
||||||
}
|
|
||||||
ancestors.remove(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package org.elasticsearch.search.aggregations.metrics.scripted;
|
package org.elasticsearch.search.aggregations.metrics.scripted;
|
||||||
|
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
|
import org.elasticsearch.common.util.CollectionUtils;
|
||||||
import org.elasticsearch.script.ExecutableScript;
|
import org.elasticsearch.script.ExecutableScript;
|
||||||
import org.elasticsearch.script.Script;
|
import org.elasticsearch.script.Script;
|
||||||
import org.elasticsearch.script.SearchScript;
|
import org.elasticsearch.script.SearchScript;
|
||||||
|
@ -77,6 +78,7 @@ public class ScriptedMetricAggregator extends MetricsAggregator {
|
||||||
Object aggregation;
|
Object aggregation;
|
||||||
if (combineScript != null) {
|
if (combineScript != null) {
|
||||||
aggregation = combineScript.run();
|
aggregation = combineScript.run();
|
||||||
|
CollectionUtils.ensureNoSelfReferences(aggregation);
|
||||||
} else {
|
} else {
|
||||||
aggregation = params.get("_agg");
|
aggregation = params.get("_agg");
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,10 +112,11 @@ public class BucketScriptPipelineAggregator extends PipelineAggregator {
|
||||||
} else {
|
} else {
|
||||||
ExecutableScript executableScript = factory.newInstance(vars);
|
ExecutableScript executableScript = factory.newInstance(vars);
|
||||||
Object returned = executableScript.run();
|
Object returned = executableScript.run();
|
||||||
|
// no need to check for self references since only numbers are valid
|
||||||
if (returned == null) {
|
if (returned == null) {
|
||||||
newBuckets.add(bucket);
|
newBuckets.add(bucket);
|
||||||
} else {
|
} else {
|
||||||
if (!(returned instanceof Number)) {
|
if ((returned instanceof Number) == false) {
|
||||||
throw new AggregationExecutionException("series_arithmetic script for reducer [" + name()
|
throw new AggregationExecutionException("series_arithmetic script for reducer [" + name()
|
||||||
+ "] must return a Number");
|
+ "] must return a Number");
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.apache.lucene.search.Scorer;
|
||||||
import org.apache.lucene.util.Bits;
|
import org.apache.lucene.util.Bits;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.common.lucene.ScorerAware;
|
import org.elasticsearch.common.lucene.ScorerAware;
|
||||||
|
import org.elasticsearch.common.util.CollectionUtils;
|
||||||
import org.elasticsearch.index.fielddata.AbstractSortingNumericDocValues;
|
import org.elasticsearch.index.fielddata.AbstractSortingNumericDocValues;
|
||||||
import org.elasticsearch.index.fielddata.AtomicOrdinalsFieldData;
|
import org.elasticsearch.index.fielddata.AtomicOrdinalsFieldData;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
|
@ -460,7 +461,9 @@ public abstract class ValuesSource {
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
final BytesRef value = bytesValues.nextValue();
|
final BytesRef value = bytesValues.nextValue();
|
||||||
script.setNextAggregationValue(value.utf8ToString());
|
script.setNextAggregationValue(value.utf8ToString());
|
||||||
values[i].copyChars(script.run().toString());
|
Object run = script.run();
|
||||||
|
CollectionUtils.ensureNoSelfReferences(run);
|
||||||
|
values[i].copyChars(run.toString());
|
||||||
}
|
}
|
||||||
sort();
|
sort();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.elasticsearch.search.aggregations.support.values;
|
||||||
|
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
import org.elasticsearch.common.lucene.ScorerAware;
|
import org.elasticsearch.common.lucene.ScorerAware;
|
||||||
|
import org.elasticsearch.common.util.CollectionUtils;
|
||||||
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
||||||
import org.elasticsearch.index.fielddata.SortingBinaryDocValues;
|
import org.elasticsearch.index.fielddata.SortingBinaryDocValues;
|
||||||
import org.elasticsearch.script.SearchScript;
|
import org.elasticsearch.script.SearchScript;
|
||||||
|
@ -44,6 +45,7 @@ public class ScriptBytesValues extends SortingBinaryDocValues implements ScorerA
|
||||||
if (o == null) {
|
if (o == null) {
|
||||||
values[i].clear();
|
values[i].clear();
|
||||||
} else {
|
} else {
|
||||||
|
CollectionUtils.ensureNoSelfReferences(o);
|
||||||
values[i].copyChars(o.toString());
|
values[i].copyChars(o.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.apache.lucene.index.IndexReader;
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.ReaderUtil;
|
import org.apache.lucene.index.ReaderUtil;
|
||||||
import org.elasticsearch.common.document.DocumentField;
|
import org.elasticsearch.common.document.DocumentField;
|
||||||
|
import org.elasticsearch.common.util.CollectionUtils;
|
||||||
import org.elasticsearch.script.SearchScript;
|
import org.elasticsearch.script.SearchScript;
|
||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
import org.elasticsearch.search.fetch.FetchSubPhase;
|
import org.elasticsearch.search.fetch.FetchSubPhase;
|
||||||
|
@ -64,6 +65,7 @@ public final class ScriptFieldsFetchSubPhase implements FetchSubPhase {
|
||||||
final Object value;
|
final Object value;
|
||||||
try {
|
try {
|
||||||
value = leafScripts[i].run();
|
value = leafScripts[i].run();
|
||||||
|
CollectionUtils.ensureNoSelfReferences(value);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
if (scriptFields.get(i).ignoreException()) {
|
if (scriptFields.get(i).ignoreException()) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.logging.DeprecationLogger;
|
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||||
import org.elasticsearch.common.logging.Loggers;
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
|
import org.elasticsearch.common.util.CollectionUtils;
|
||||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
|
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
@ -341,7 +342,9 @@ public class ScriptSortBuilder extends SortBuilder<ScriptSortBuilder> {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public BytesRef binaryValue() {
|
public BytesRef binaryValue() {
|
||||||
spare.copyChars(leafScript.run().toString());
|
final Object run = leafScript.run();
|
||||||
|
CollectionUtils.ensureNoSelfReferences(run);
|
||||||
|
spare.copyChars(run.toString());
|
||||||
return spare.get();
|
return spare.get();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,16 +25,21 @@ import org.apache.lucene.util.BytesRefBuilder;
|
||||||
import org.apache.lucene.util.Counter;
|
import org.apache.lucene.util.Counter;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyMap;
|
||||||
import static org.elasticsearch.common.util.CollectionUtils.eagerPartition;
|
import static org.elasticsearch.common.util.CollectionUtils.eagerPartition;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
@ -176,4 +181,15 @@ public class CollectionUtilsTests extends ESTestCase {
|
||||||
eagerPartition(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 6)
|
eagerPartition(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 6)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testEnsureNoSelfReferences() {
|
||||||
|
CollectionUtils.ensureNoSelfReferences(emptyMap());
|
||||||
|
CollectionUtils.ensureNoSelfReferences(null);
|
||||||
|
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put("field", map);
|
||||||
|
|
||||||
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> CollectionUtils.ensureNoSelfReferences(map));
|
||||||
|
assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.elasticsearch.common.geo.GeoPoint;
|
||||||
import org.elasticsearch.common.io.PathUtils;
|
import org.elasticsearch.common.io.PathUtils;
|
||||||
import org.elasticsearch.common.text.Text;
|
import org.elasticsearch.common.text.Text;
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
|
import org.elasticsearch.common.util.CollectionUtils;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser.Token;
|
import org.elasticsearch.common.xcontent.XContentParser.Token;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
|
@ -854,19 +855,19 @@ public abstract class BaseXContentTestCase extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEnsureNoSelfReferences() throws IOException {
|
public void testEnsureNoSelfReferences() throws IOException {
|
||||||
XContentBuilder.ensureNoSelfReferences(emptyMap());
|
CollectionUtils.ensureNoSelfReferences(emptyMap());
|
||||||
XContentBuilder.ensureNoSelfReferences(null);
|
CollectionUtils.ensureNoSelfReferences(null);
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
map.put("field", map);
|
map.put("field", map);
|
||||||
|
|
||||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map));
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map));
|
||||||
assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself"));
|
assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that the same map written multiple times do not trigger the self-reference check in
|
* Test that the same map written multiple times do not trigger the self-reference check in
|
||||||
* {@link XContentBuilder#ensureNoSelfReferences(Object)}
|
* {@link CollectionUtils#ensureNoSelfReferences(Object)}
|
||||||
*/
|
*/
|
||||||
public void testRepeatedMapsAndNoSelfReferences() throws Exception {
|
public void testRepeatedMapsAndNoSelfReferences() throws Exception {
|
||||||
Map<String, Object> mapB = singletonMap("b", "B");
|
Map<String, Object> mapB = singletonMap("b", "B");
|
||||||
|
@ -899,7 +900,7 @@ public abstract class BaseXContentTestCase extends ESTestCase {
|
||||||
map1.put("map0", map0); // map 1 -> map 0 loop
|
map1.put("map0", map0); // map 1 -> map 0 loop
|
||||||
|
|
||||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0));
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0));
|
||||||
assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself"));
|
assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSelfReferencingMapsTwoLevels() throws IOException {
|
public void testSelfReferencingMapsTwoLevels() throws IOException {
|
||||||
|
@ -917,7 +918,7 @@ public abstract class BaseXContentTestCase extends ESTestCase {
|
||||||
map2.put("map0", map0); // map 2 -> map 0 loop
|
map2.put("map0", map0); // map 2 -> map 0 loop
|
||||||
|
|
||||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0));
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0));
|
||||||
assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself"));
|
assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSelfReferencingObjectsArray() throws IOException {
|
public void testSelfReferencingObjectsArray() throws IOException {
|
||||||
|
@ -930,13 +931,13 @@ public abstract class BaseXContentTestCase extends ESTestCase {
|
||||||
.startObject()
|
.startObject()
|
||||||
.field("field", values)
|
.field("field", values)
|
||||||
.endObject());
|
.endObject());
|
||||||
assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself"));
|
assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself"));
|
||||||
|
|
||||||
e = expectThrows(IllegalArgumentException.class, () -> builder()
|
e = expectThrows(IllegalArgumentException.class, () -> builder()
|
||||||
.startObject()
|
.startObject()
|
||||||
.array("field", values)
|
.array("field", values)
|
||||||
.endObject());
|
.endObject());
|
||||||
assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself"));
|
assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSelfReferencingIterable() throws IOException {
|
public void testSelfReferencingIterable() throws IOException {
|
||||||
|
@ -949,7 +950,7 @@ public abstract class BaseXContentTestCase extends ESTestCase {
|
||||||
.startObject()
|
.startObject()
|
||||||
.field("field", (Iterable) values)
|
.field("field", (Iterable) values)
|
||||||
.endObject());
|
.endObject());
|
||||||
assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself"));
|
assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSelfReferencingIterableOneLevel() throws IOException {
|
public void testSelfReferencingIterableOneLevel() throws IOException {
|
||||||
|
@ -964,7 +965,7 @@ public abstract class BaseXContentTestCase extends ESTestCase {
|
||||||
.startObject()
|
.startObject()
|
||||||
.field("field", (Iterable) values)
|
.field("field", (Iterable) values)
|
||||||
.endObject());
|
.endObject());
|
||||||
assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself"));
|
assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSelfReferencingIterableTwoLevels() throws IOException {
|
public void testSelfReferencingIterableTwoLevels() throws IOException {
|
||||||
|
@ -984,7 +985,7 @@ public abstract class BaseXContentTestCase extends ESTestCase {
|
||||||
map2.put("map0", map0); // map 2 -> map 0 loop
|
map2.put("map0", map0); // map 2 -> map 0 loop
|
||||||
|
|
||||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0));
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0));
|
||||||
assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself"));
|
assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testChecksForDuplicates() throws Exception {
|
public void testChecksForDuplicates() throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue