diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/AbstractLongScriptFieldScript.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/AbstractLongScriptFieldScript.java index d7b261a4fae78..93c6ad382d265 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/AbstractLongScriptFieldScript.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/AbstractLongScriptFieldScript.java @@ -19,8 +19,8 @@ public abstract class AbstractLongScriptFieldScript extends AbstractScriptFieldS private long[] values = new long[1]; private int count; - public AbstractLongScriptFieldScript(Map params, SearchLookup searchLookup, LeafReaderContext ctx) { - super(params, searchLookup, ctx); + public AbstractLongScriptFieldScript(String fieldName, Map params, SearchLookup searchLookup, LeafReaderContext ctx) { + super(fieldName, params, searchLookup, ctx); } /** @@ -50,6 +50,7 @@ public final int count() { } protected final void emitValue(long v) { + checkMaxSize(count); if (values.length < count + 1) { values = ArrayUtil.grow(values, count + 1); } diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/AbstractScriptFieldScript.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/AbstractScriptFieldScript.java index 5fe3d296b3ab7..27d3527666bb4 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/AbstractScriptFieldScript.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/AbstractScriptFieldScript.java @@ -17,6 +17,7 @@ import org.elasticsearch.search.lookup.SourceLookup; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.function.Function; @@ -27,6 +28,11 @@ * {@link AggregationScript} but hopefully with less historical baggage. */ public abstract class AbstractScriptFieldScript { + /** + * The maximum number of values a script should be allowed to emit. + */ + static final int MAX_VALUES = 100; + public static ScriptContext newContext(String name, Class factoryClass) { return new ScriptContext( name + "_script_field", @@ -54,10 +60,12 @@ public static ScriptContext newContext(String name, Class factoryClass value -> ((SourceLookup) value).loadSourceIfNeeded() ); + protected final String fieldName; private final Map params; private final LeafSearchLookup leafSearchLookup; - public AbstractScriptFieldScript(Map params, SearchLookup searchLookup, LeafReaderContext ctx) { + public AbstractScriptFieldScript(String fieldName, Map params, SearchLookup searchLookup, LeafReaderContext ctx) { + this.fieldName = fieldName; this.leafSearchLookup = searchLookup.getLeafSearchLookup(ctx); params = new HashMap<>(params); params.put("_source", leafSearchLookup.source()); @@ -94,5 +102,23 @@ public final Map> getDoc() { return leafSearchLookup.doc(); } + /** + * Check if the we can add another value to the list of values. + * @param currentSize the current size of the list + */ + protected final void checkMaxSize(int currentSize) { + if (currentSize >= MAX_VALUES) { + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "Runtime field [%s] is emitting [%s] values while the maximum number of values allowed is [%s]", + fieldName, + currentSize + 1, + MAX_VALUES + ) + ); + } + } + public abstract void execute(); } diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/BooleanScriptFieldScript.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/BooleanScriptFieldScript.java index 3e4ef9ce11e06..d0e3fd4b0380b 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/BooleanScriptFieldScript.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/BooleanScriptFieldScript.java @@ -31,7 +31,7 @@ static List whitelist() { public static final String[] PARAMETERS = {}; public interface Factory extends ScriptFactory { - LeafFactory newFactory(Map params, SearchLookup searchLookup); + LeafFactory newFactory(String fieldName, Map params, SearchLookup searchLookup); } public interface LeafFactory { @@ -41,8 +41,8 @@ public interface LeafFactory { private int trues; private int falses; - public BooleanScriptFieldScript(Map params, SearchLookup searchLookup, LeafReaderContext ctx) { - super(params, searchLookup, ctx); + public BooleanScriptFieldScript(String fieldName, Map params, SearchLookup searchLookup, LeafReaderContext ctx) { + super(fieldName, params, searchLookup, ctx); } /** diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/DateScriptFieldScript.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/DateScriptFieldScript.java index 9b9ff47cd6871..b169b034f064a 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/DateScriptFieldScript.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/DateScriptFieldScript.java @@ -31,7 +31,7 @@ static List whitelist() { public static final String[] PARAMETERS = {}; public interface Factory extends ScriptFactory { - LeafFactory newFactory(Map params, SearchLookup searchLookup, DateFormatter formatter); + LeafFactory newFactory(String fieldName, Map params, SearchLookup searchLookup, DateFormatter formatter); } public interface LeafFactory { @@ -40,8 +40,14 @@ public interface LeafFactory { private final DateFormatter formatter; - public DateScriptFieldScript(Map params, SearchLookup searchLookup, DateFormatter formatter, LeafReaderContext ctx) { - super(params, searchLookup, ctx); + public DateScriptFieldScript( + String fieldName, + Map params, + SearchLookup searchLookup, + DateFormatter formatter, + LeafReaderContext ctx + ) { + super(fieldName, params, searchLookup, ctx); this.formatter = formatter; } diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/DoubleScriptFieldScript.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/DoubleScriptFieldScript.java index a4fc32542067e..840f5395aadff 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/DoubleScriptFieldScript.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/DoubleScriptFieldScript.java @@ -31,7 +31,7 @@ static List whitelist() { public static final String[] PARAMETERS = {}; public interface Factory extends ScriptFactory { - LeafFactory newFactory(Map params, SearchLookup searchLookup); + LeafFactory newFactory(String fieldName, Map params, SearchLookup searchLookup); } public interface LeafFactory { @@ -41,8 +41,8 @@ public interface LeafFactory { private double[] values = new double[1]; private int count; - public DoubleScriptFieldScript(Map params, SearchLookup searchLookup, LeafReaderContext ctx) { - super(params, searchLookup, ctx); + public DoubleScriptFieldScript(String fieldName, Map params, SearchLookup searchLookup, LeafReaderContext ctx) { + super(fieldName, params, searchLookup, ctx); } /** @@ -72,6 +72,7 @@ public final int count() { } protected final void emitValue(double v) { + checkMaxSize(count); if (values.length < count + 1) { values = ArrayUtil.grow(values, count + 1); } diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/IpScriptFieldScript.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/IpScriptFieldScript.java index e99ebb4513da9..fe20c572476f9 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/IpScriptFieldScript.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/IpScriptFieldScript.java @@ -50,7 +50,7 @@ static List whitelist() { public static final String[] PARAMETERS = {}; public interface Factory extends ScriptFactory { - LeafFactory newFactory(Map params, SearchLookup searchLookup); + LeafFactory newFactory(String fieldName, Map params, SearchLookup searchLookup); } public interface LeafFactory { @@ -60,8 +60,8 @@ public interface LeafFactory { private BytesRef[] values = new BytesRef[1]; private int count; - public IpScriptFieldScript(Map params, SearchLookup searchLookup, LeafReaderContext ctx) { - super(params, searchLookup, ctx); + public IpScriptFieldScript(String fieldName, Map params, SearchLookup searchLookup, LeafReaderContext ctx) { + super(fieldName, params, searchLookup, ctx); } /** @@ -94,6 +94,7 @@ public final int count() { } protected final void emitValue(String v) { + checkMaxSize(count); if (values.length < count + 1) { values = ArrayUtil.grow(values, count + 1); } diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/LongScriptFieldScript.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/LongScriptFieldScript.java index e50ccee619f05..cf9852563a365 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/LongScriptFieldScript.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/LongScriptFieldScript.java @@ -28,15 +28,15 @@ static List whitelist() { public static final String[] PARAMETERS = {}; public interface Factory extends ScriptFactory { - LeafFactory newFactory(Map params, SearchLookup searchLookup); + LeafFactory newFactory(String fieldName, Map params, SearchLookup searchLookup); } public interface LeafFactory { LongScriptFieldScript newInstance(LeafReaderContext ctx) throws IOException; } - public LongScriptFieldScript(Map params, SearchLookup searchLookup, LeafReaderContext ctx) { - super(params, searchLookup, ctx); + public LongScriptFieldScript(String fieldName, Map params, SearchLookup searchLookup, LeafReaderContext ctx) { + super(fieldName, params, searchLookup, ctx); } public static class EmitValue { diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/StringScriptFieldScript.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/StringScriptFieldScript.java index 7faf8fbffc897..9b89e6714bb4a 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/StringScriptFieldScript.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/StringScriptFieldScript.java @@ -17,9 +17,15 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; public abstract class StringScriptFieldScript extends AbstractScriptFieldScript { + /** + * The maximum number of chars a script should be allowed to emit. + */ + public static final long MAX_CHARS = 1024 * 1024; + public static final ScriptContext CONTEXT = newContext("string_script_field", Factory.class); static List whitelist() { @@ -31,7 +37,7 @@ static List whitelist() { public static final String[] PARAMETERS = {}; public interface Factory extends ScriptFactory { - LeafFactory newFactory(Map params, SearchLookup searchLookup); + LeafFactory newFactory(String fieldName, Map params, SearchLookup searchLookup); } public interface LeafFactory { @@ -39,9 +45,10 @@ public interface LeafFactory { } private final List results = new ArrayList<>(); + private long chars; - public StringScriptFieldScript(Map params, SearchLookup searchLookup, LeafReaderContext ctx) { - super(params, searchLookup, ctx); + public StringScriptFieldScript(String fieldName, Map params, SearchLookup searchLookup, LeafReaderContext ctx) { + super(fieldName, params, searchLookup, ctx); } /** @@ -52,12 +59,26 @@ public StringScriptFieldScript(Map params, SearchLookup searchLo */ public final List resultsForDoc(int docId) { results.clear(); + chars = 0; setDocument(docId); execute(); return results; } protected final void emitValue(String v) { + checkMaxSize(results.size()); + chars += v.length(); + if (chars > MAX_CHARS) { + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "Runtime field [%s] is emitting [%s] characters while the maximum number of values allowed is [%s]", + fieldName, + chars, + MAX_CHARS + ) + ); + } results.add(v); } diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptBooleanMappedFieldType.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptBooleanMappedFieldType.java index 8af187f543567..98b5820078233 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptBooleanMappedFieldType.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptBooleanMappedFieldType.java @@ -72,7 +72,7 @@ public ScriptBooleanFieldData.Builder fielddataBuilder(String fullyQualifiedInde } private BooleanScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) { - return scriptFactory.newFactory(script.getParams(), searchLookup); + return scriptFactory.newFactory(name(), script.getParams(), searchLookup); } @Override diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDateMappedFieldType.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDateMappedFieldType.java index 904a35ca3f827..8395508e91675 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDateMappedFieldType.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDateMappedFieldType.java @@ -85,7 +85,7 @@ public ScriptDateFieldData.Builder fielddataBuilder(String fullyQualifiedIndexNa } private DateScriptFieldScript.LeafFactory leafFactory(SearchLookup lookup) { - return scriptFactory.newFactory(script.getParams(), lookup, dateTimeFormatter); + return scriptFactory.newFactory(name(), script.getParams(), lookup, dateTimeFormatter); } @Override diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDoubleMappedFieldType.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDoubleMappedFieldType.java index e835d45f861f2..bc898bbfa23f3 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDoubleMappedFieldType.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDoubleMappedFieldType.java @@ -64,7 +64,7 @@ public ScriptDoubleFieldData.Builder fielddataBuilder(String fullyQualifiedIndex } private DoubleScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) { - return scriptFactory.newFactory(script.getParams(), searchLookup); + return scriptFactory.newFactory(name(), script.getParams(), searchLookup); } @Override diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptIpMappedFieldType.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptIpMappedFieldType.java index 762c134a0e09e..0257fa116c2dd 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptIpMappedFieldType.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptIpMappedFieldType.java @@ -80,7 +80,7 @@ public ScriptIpFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName } private IpScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) { - return scriptFactory.newFactory(script.getParams(), searchLookup); + return scriptFactory.newFactory(name(), script.getParams(), searchLookup); } @Override diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptKeywordMappedFieldType.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptKeywordMappedFieldType.java index f41c053f7d580..3341f7c4ed00c 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptKeywordMappedFieldType.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptKeywordMappedFieldType.java @@ -68,7 +68,7 @@ public ScriptStringFieldData.Builder fielddataBuilder(String fullyQualifiedIndex } private StringScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) { - return scriptFactory.newFactory(script.getParams(), searchLookup); + return scriptFactory.newFactory(name(), script.getParams(), searchLookup); } @Override diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptLongMappedFieldType.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptLongMappedFieldType.java index 24ecde240c3f1..0568ee4e9e7ba 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptLongMappedFieldType.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptLongMappedFieldType.java @@ -64,7 +64,7 @@ public ScriptLongFieldData.Builder fielddataBuilder(String fullyQualifiedIndexNa } private LongScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) { - return scriptFactory.newFactory(script.getParams(), searchLookup); + return scriptFactory.newFactory(name(), script.getParams(), searchLookup); } @Override diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/BooleanScriptFieldScriptTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/BooleanScriptFieldScriptTests.java index 0f55db05b996b..4ed0db9e3edce 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/BooleanScriptFieldScriptTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/BooleanScriptFieldScriptTests.java @@ -6,10 +6,22 @@ package org.elasticsearch.xpack.runtimefields; +import org.apache.lucene.document.StoredField; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.search.lookup.SearchLookup; + +import java.io.IOException; + +import static org.mockito.Mockito.mock; public class BooleanScriptFieldScriptTests extends ScriptFieldScriptTestCase { - public static final BooleanScriptFieldScript.Factory DUMMY = (params, lookup) -> ctx -> new BooleanScriptFieldScript( + public static final BooleanScriptFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new BooleanScriptFieldScript( + fieldName, params, lookup, ctx @@ -29,4 +41,27 @@ protected ScriptContext context() { protected BooleanScriptFieldScript.Factory dummyScript() { return DUMMY; } + + public void testTooManyValues() throws IOException { + try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) { + iw.addDocument(org.elasticsearch.common.collect.List.of(new StoredField("_source", new BytesRef("{}")))); + try (DirectoryReader reader = iw.getReader()) { + BooleanScriptFieldScript script = new BooleanScriptFieldScript( + "test", + org.elasticsearch.common.collect.Map.of(), + new SearchLookup(mock(MapperService.class), (ft, lookup) -> null, null), + reader.leaves().get(0) + ) { + @Override + public void execute() { + for (int i = 0; i <= AbstractScriptFieldScript.MAX_VALUES * 1000; i++) { + emitValue(i % 2 == 0); + } + } + }; + // There isn't a limit to the number of values so this won't throw + script.execute(); + } + } + } } diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/DateScriptFieldScriptTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/DateScriptFieldScriptTests.java index 768f22347f48f..547b2aa9ad59d 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/DateScriptFieldScriptTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/DateScriptFieldScriptTests.java @@ -6,10 +6,24 @@ package org.elasticsearch.xpack.runtimefields; +import org.apache.lucene.document.StoredField; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.common.time.DateFormatter; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.search.lookup.SearchLookup; + +import java.io.IOException; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; public class DateScriptFieldScriptTests extends ScriptFieldScriptTestCase { - public static final DateScriptFieldScript.Factory DUMMY = (params, lookup, formatter) -> ctx -> new DateScriptFieldScript( + public static final DateScriptFieldScript.Factory DUMMY = (fieldName, params, lookup, formatter) -> ctx -> new DateScriptFieldScript( + fieldName, params, lookup, formatter, @@ -30,4 +44,31 @@ protected ScriptContext context() { protected DateScriptFieldScript.Factory dummyScript() { return DUMMY; } + + public void testTooManyValues() throws IOException { + try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) { + iw.addDocument(org.elasticsearch.common.collect.List.of(new StoredField("_source", new BytesRef("{}")))); + try (DirectoryReader reader = iw.getReader()) { + DateScriptFieldScript script = new DateScriptFieldScript( + "test", + org.elasticsearch.common.collect.Map.of(), + new SearchLookup(mock(MapperService.class), (ft, lookup) -> null, null), + DateFormatter.forPattern(randomDateFormatterPattern()).withLocale(randomLocale(random())), + reader.leaves().get(0) + ) { + @Override + public void execute() { + for (int i = 0; i <= AbstractScriptFieldScript.MAX_VALUES; i++) { + emitValue(0); + } + } + }; + Exception e = expectThrows(IllegalArgumentException.class, script::execute); + assertThat( + e.getMessage(), + equalTo("Runtime field [test] is emitting [101] values while the maximum number of values allowed is [100]") + ); + } + } + } } diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/DoubleScriptFieldScriptTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/DoubleScriptFieldScriptTests.java index 4cf222c12eb75..82b7ae74c2329 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/DoubleScriptFieldScriptTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/DoubleScriptFieldScriptTests.java @@ -6,10 +6,23 @@ package org.elasticsearch.xpack.runtimefields; +import org.apache.lucene.document.StoredField; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.search.lookup.SearchLookup; + +import java.io.IOException; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; public class DoubleScriptFieldScriptTests extends ScriptFieldScriptTestCase { - public static final DoubleScriptFieldScript.Factory DUMMY = (params, lookup) -> ctx -> new DoubleScriptFieldScript( + public static final DoubleScriptFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new DoubleScriptFieldScript( + fieldName, params, lookup, ctx @@ -29,4 +42,30 @@ protected ScriptContext context() { protected DoubleScriptFieldScript.Factory dummyScript() { return DUMMY; } + + public void testTooManyValues() throws IOException { + try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) { + iw.addDocument(org.elasticsearch.common.collect.List.of(new StoredField("_source", new BytesRef("{}")))); + try (DirectoryReader reader = iw.getReader()) { + DoubleScriptFieldScript script = new DoubleScriptFieldScript( + "test", + org.elasticsearch.common.collect.Map.of(), + new SearchLookup(mock(MapperService.class), (ft, lookup) -> null, null), + reader.leaves().get(0) + ) { + @Override + public void execute() { + for (int i = 0; i <= AbstractScriptFieldScript.MAX_VALUES; i++) { + emitValue(1.0); + } + } + }; + Exception e = expectThrows(IllegalArgumentException.class, script::execute); + assertThat( + e.getMessage(), + equalTo("Runtime field [test] is emitting [101] values while the maximum number of values allowed is [100]") + ); + } + } + } } diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/IpScriptFieldScriptTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/IpScriptFieldScriptTests.java index 15d47c6ce39a3..c9cccfad1b435 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/IpScriptFieldScriptTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/IpScriptFieldScriptTests.java @@ -6,10 +6,27 @@ package org.elasticsearch.xpack.runtimefields; +import org.apache.lucene.document.StoredField; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.search.lookup.SearchLookup; + +import java.io.IOException; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; public class IpScriptFieldScriptTests extends ScriptFieldScriptTestCase { - public static final IpScriptFieldScript.Factory DUMMY = (params, lookup) -> ctx -> new IpScriptFieldScript(params, lookup, ctx) { + public static final IpScriptFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new IpScriptFieldScript( + fieldName, + params, + lookup, + ctx + ) { @Override public void execute() { emitValue("192.168.0.1"); @@ -25,4 +42,30 @@ protected ScriptContext context() { protected IpScriptFieldScript.Factory dummyScript() { return DUMMY; } + + public void testTooManyValues() throws IOException { + try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) { + iw.addDocument(org.elasticsearch.common.collect.List.of(new StoredField("_source", new BytesRef("{}")))); + try (DirectoryReader reader = iw.getReader()) { + IpScriptFieldScript script = new IpScriptFieldScript( + "test", + org.elasticsearch.common.collect.Map.of(), + new SearchLookup(mock(MapperService.class), (ft, lookup) -> null, null), + reader.leaves().get(0) + ) { + @Override + public void execute() { + for (int i = 0; i <= AbstractScriptFieldScript.MAX_VALUES; i++) { + emitValue("192.168.0.1"); + } + } + }; + Exception e = expectThrows(IllegalArgumentException.class, script::execute); + assertThat( + e.getMessage(), + equalTo("Runtime field [test] is emitting [101] values while the maximum number of values allowed is [100]") + ); + } + } + } } diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/LongScriptFieldScriptTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/LongScriptFieldScriptTests.java index 4dd408e92fe85..1df9cc6d4c125 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/LongScriptFieldScriptTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/LongScriptFieldScriptTests.java @@ -6,10 +6,27 @@ package org.elasticsearch.xpack.runtimefields; +import org.apache.lucene.document.StoredField; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.search.lookup.SearchLookup; + +import java.io.IOException; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; public class LongScriptFieldScriptTests extends ScriptFieldScriptTestCase { - public static final LongScriptFieldScript.Factory DUMMY = (params, lookup) -> ctx -> new LongScriptFieldScript(params, lookup, ctx) { + public static final LongScriptFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new LongScriptFieldScript( + fieldName, + params, + lookup, + ctx + ) { @Override public void execute() { emitValue(1); @@ -25,4 +42,30 @@ protected ScriptContext context() { protected LongScriptFieldScript.Factory dummyScript() { return DUMMY; } + + public void testTooManyValues() throws IOException { + try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) { + iw.addDocument(org.elasticsearch.common.collect.List.of(new StoredField("_source", new BytesRef("{}")))); + try (DirectoryReader reader = iw.getReader()) { + LongScriptFieldScript script = new LongScriptFieldScript( + "test", + org.elasticsearch.common.collect.Map.of(), + new SearchLookup(mock(MapperService.class), (ft, lookup) -> null, null), + reader.leaves().get(0) + ) { + @Override + public void execute() { + for (int i = 0; i <= AbstractScriptFieldScript.MAX_VALUES; i++) { + emitValue(0); + } + } + }; + Exception e = expectThrows(IllegalArgumentException.class, script::execute); + assertThat( + e.getMessage(), + equalTo("Runtime field [test] is emitting [101] values while the maximum number of values allowed is [100]") + ); + } + } + } } diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/StringScriptFieldScriptTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/StringScriptFieldScriptTests.java index 7b500f6406eb1..7f375371bb60f 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/StringScriptFieldScriptTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/StringScriptFieldScriptTests.java @@ -6,10 +6,23 @@ package org.elasticsearch.xpack.runtimefields; +import org.apache.lucene.document.StoredField; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.search.lookup.SearchLookup; + +import java.io.IOException; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; public class StringScriptFieldScriptTests extends ScriptFieldScriptTestCase { - public static final StringScriptFieldScript.Factory DUMMY = (params, lookup) -> ctx -> new StringScriptFieldScript( + public static final StringScriptFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new StringScriptFieldScript( + fieldName, params, lookup, ctx @@ -29,4 +42,61 @@ protected ScriptContext context() { protected StringScriptFieldScript.Factory dummyScript() { return DUMMY; } + + public void testTooManyValues() throws IOException { + try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) { + iw.addDocument(org.elasticsearch.common.collect.List.of(new StoredField("_source", new BytesRef("{}")))); + try (DirectoryReader reader = iw.getReader()) { + StringScriptFieldScript script = new StringScriptFieldScript( + "test", + org.elasticsearch.common.collect.Map.of(), + new SearchLookup(mock(MapperService.class), (ft, lookup) -> null, null), + reader.leaves().get(0) + ) { + @Override + public void execute() { + for (int i = 0; i <= AbstractScriptFieldScript.MAX_VALUES; i++) { + emitValue("test"); + } + } + }; + Exception e = expectThrows(IllegalArgumentException.class, script::execute); + assertThat( + e.getMessage(), + equalTo("Runtime field [test] is emitting [101] values while the maximum number of values allowed is [100]") + ); + } + } + } + + public void testTooManyChars() throws IOException { + try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) { + iw.addDocument(org.elasticsearch.common.collect.List.of(new StoredField("_source", new BytesRef("{}")))); + try (DirectoryReader reader = iw.getReader()) { + StringScriptFieldScript script = new StringScriptFieldScript( + "test", + org.elasticsearch.common.collect.Map.of(), + new SearchLookup(mock(MapperService.class), (ft, lookup) -> null, null), + reader.leaves().get(0) + ) { + @Override + public void execute() { + StringBuilder big = new StringBuilder(); + while (big.length() < StringScriptFieldScript.MAX_CHARS / 4) { + big.append("test"); + } + String bigString = big.toString(); + for (int i = 0; i <= 4; i++) { + emitValue(bigString); + } + } + }; + Exception e = expectThrows(IllegalArgumentException.class, script::execute); + assertThat( + e.getMessage(), + equalTo("Runtime field [test] is emitting [1310720] characters while the maximum number of values allowed is [1048576]") + ); + } + } + } } diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptBooleanMappedFieldTypeTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptBooleanMappedFieldTypeTests.java index 2d67638f40017..f8b765b78749b 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptBooleanMappedFieldTypeTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptBooleanMappedFieldTypeTests.java @@ -458,7 +458,12 @@ public FactoryType compile( private BooleanScriptFieldScript.Factory factory(String code) { switch (code) { case "read_foo": - return (params, lookup) -> (ctx) -> new BooleanScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> (ctx) -> new BooleanScriptFieldScript( + fieldName, + params, + lookup, + ctx + ) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { @@ -467,7 +472,12 @@ public void execute() { } }; case "xor_param": - return (params, lookup) -> (ctx) -> new BooleanScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> (ctx) -> new BooleanScriptFieldScript( + fieldName, + params, + lookup, + ctx + ) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDateMappedFieldTypeTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDateMappedFieldTypeTests.java index b2896c343ca90..757448e67288e 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDateMappedFieldTypeTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDateMappedFieldTypeTests.java @@ -504,7 +504,13 @@ public FactoryType compile( private DateScriptFieldScript.Factory factory(String code) { switch (code) { case "read_timestamp": - return (params, lookup, formatter) -> ctx -> new DateScriptFieldScript(params, lookup, formatter, ctx) { + return (fieldName, params, lookup, formatter) -> ctx -> new DateScriptFieldScript( + fieldName, + params, + lookup, + formatter, + ctx + ) { @Override public void execute() { for (Object timestamp : (List) getSource().get("timestamp")) { @@ -514,7 +520,13 @@ public void execute() { } }; case "add_days": - return (params, lookup, formatter) -> ctx -> new DateScriptFieldScript(params, lookup, formatter, ctx) { + return (fieldName, params, lookup, formatter) -> ctx -> new DateScriptFieldScript( + fieldName, + params, + lookup, + formatter, + ctx + ) { @Override public void execute() { for (Object timestamp : (List) getSource().get("timestamp")) { diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDoubleMappedFieldTypeTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDoubleMappedFieldTypeTests.java index 05d33c4d54a28..6626562fdbdb0 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDoubleMappedFieldTypeTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptDoubleMappedFieldTypeTests.java @@ -295,7 +295,7 @@ public FactoryType compile( private DoubleScriptFieldScript.Factory factory(String code) { switch (code) { case "read_foo": - return (params, lookup) -> (ctx) -> new DoubleScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> (ctx) -> new DoubleScriptFieldScript(fieldName, params, lookup, ctx) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { @@ -304,7 +304,7 @@ public void execute() { } }; case "add_param": - return (params, lookup) -> (ctx) -> new DoubleScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> (ctx) -> new DoubleScriptFieldScript(fieldName, params, lookup, ctx) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptIpMappedFieldTypeTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptIpMappedFieldTypeTests.java index a52e6761bc18b..2ca12fb6d001a 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptIpMappedFieldTypeTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptIpMappedFieldTypeTests.java @@ -338,7 +338,7 @@ public FactoryType compile( private IpScriptFieldScript.Factory factory(String code) { switch (code) { case "read_foo": - return (params, lookup) -> (ctx) -> new IpScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> (ctx) -> new IpScriptFieldScript(fieldName, params, lookup, ctx) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { @@ -347,7 +347,7 @@ public void execute() { } }; case "append_param": - return (params, lookup) -> (ctx) -> new IpScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> (ctx) -> new IpScriptFieldScript(fieldName, params, lookup, ctx) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptKeywordMappedFieldTypeTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptKeywordMappedFieldTypeTests.java index 5b85749390752..71cd4b1d0bc0d 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptKeywordMappedFieldTypeTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptKeywordMappedFieldTypeTests.java @@ -379,7 +379,7 @@ public FactoryType compile( private StringScriptFieldScript.Factory factory(String code) { switch (code) { case "read_foo": - return (params, lookup) -> (ctx) -> new StringScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> ctx -> new StringScriptFieldScript(fieldName, params, lookup, ctx) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { @@ -388,7 +388,7 @@ public void execute() { } }; case "append_param": - return (params, lookup) -> (ctx) -> new StringScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> ctx -> new StringScriptFieldScript(fieldName, params, lookup, ctx) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptLongMappedFieldTypeTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptLongMappedFieldTypeTests.java index 0599bd3a6adde..33c9c1a98ecdf 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptLongMappedFieldTypeTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/ScriptLongMappedFieldTypeTests.java @@ -324,7 +324,7 @@ public FactoryType compile( private LongScriptFieldScript.Factory factory(String code) { switch (code) { case "read_foo": - return (params, lookup) -> (ctx) -> new LongScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> (ctx) -> new LongScriptFieldScript(fieldName, params, lookup, ctx) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { @@ -333,7 +333,7 @@ public void execute() { } }; case "add_param": - return (params, lookup) -> (ctx) -> new LongScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> (ctx) -> new LongScriptFieldScript(fieldName, params, lookup, ctx) { @Override public void execute() { for (Object foo : (List) getSource().get("foo")) { @@ -344,7 +344,7 @@ public void execute() { case "millis_ago": // Painless actually call System.currentTimeMillis. We could mock the time but this works fine too. long now = System.currentTimeMillis(); - return (params, lookup) -> (ctx) -> new LongScriptFieldScript(params, lookup, ctx) { + return (fieldName, params, lookup) -> (ctx) -> new LongScriptFieldScript(fieldName, params, lookup, ctx) { @Override public void execute() { for (Object timestamp : (List) getSource().get("timestamp")) { diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/query/LongScriptFieldDistanceFeatureQueryTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/query/LongScriptFieldDistanceFeatureQueryTests.java index 8cbe71595fecf..bc1c51adee643 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/query/LongScriptFieldDistanceFeatureQueryTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/query/LongScriptFieldDistanceFeatureQueryTests.java @@ -91,7 +91,7 @@ public void testMatches() throws IOException { try (DirectoryReader reader = iw.getReader()) { IndexSearcher searcher = newSearcher(reader); CheckedFunction leafFactory = - ctx -> new DateScriptFieldScript(Collections.emptyMap(), new SearchLookup(null, null, null), null, ctx) { + ctx -> new DateScriptFieldScript("test", Collections.emptyMap(), new SearchLookup(null, null, null), null, ctx) { @Override public void execute() { for (Object timestamp : (List) getSource().get("timestamp")) {