diff --git a/CHANGELOG.md b/CHANGELOG.md index 356bc0f8cd93d..7ef924141fd9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Lazy init stored field reader in SourceLookup ([#20827](https://github.com/opensearch-project/OpenSearch/pull/20827)) * Improved error message when trying to open an index originally created with Elasticsearch on OpenSearch ([#20512](https://github.com/opensearch-project/OpenSearch/pull/20512)) - Updated MMapDirectory to use ReadAdviseByContext rather than default readadvise of Lucene([#21031](https://github.com/opensearch-project/OpenSearch/pull/21031)) +- Relax validation for field-level `meta` ([#19884](https://github.com/opensearch-project/OpenSearch/issues/19884)) ### Fixed - Relax index template pattern overlap check to use minimum-string heuristic, allowing distinguishable multi-wildcard patterns at the same priority ([#20702](https://github.com/opensearch-project/OpenSearch/pull/20702)) diff --git a/server/src/main/java/org/opensearch/index/mapper/TypeParsers.java b/server/src/main/java/org/opensearch/index/mapper/TypeParsers.java index 30fcba0ae61d3..884ba81933b24 100644 --- a/server/src/main/java/org/opensearch/index/mapper/TypeParsers.java +++ b/server/src/main/java/org/opensearch/index/mapper/TypeParsers.java @@ -64,6 +64,9 @@ public class TypeParsers { public static final String INDEX_OPTIONS_FREQS = "freqs"; public static final String INDEX_OPTIONS_POSITIONS = "positions"; public static final String INDEX_OPTIONS_OFFSETS = "offsets"; + public static final int META_MAX_ENTRIES = 100; + public static final int META_MAX_KEY_LENGTH = 255; + public static final int META_MAX_VALUE_LENGTH = 10_000; public static void checkNull(String propName, Object propNode) { if (false == propName.equals("null_value") && propNode == null) { @@ -86,26 +89,35 @@ public static Map parseMeta(String name, Object metaObject) { } @SuppressWarnings("unchecked") Map meta = (Map) metaObject; - if (meta.size() > 5) { - throw new MapperParsingException("[meta] can't have more than 5 entries, but got " + meta.size() + " on field [" + name + "]"); + if (meta.size() > META_MAX_ENTRIES) { + throw new MapperParsingException( + "[meta] can't have more than " + META_MAX_ENTRIES + " entries, but got " + meta.size() + " on field [" + name + "]" + ); } - for (String key : meta.keySet()) { - if (key.codePointCount(0, key.length()) > 20) { + for (Map.Entry entry : meta.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (key.codePointCount(0, key.length()) > META_MAX_KEY_LENGTH) { throw new MapperParsingException( - "[meta] keys can't be longer than 20 chars, but got [" + key + "] for field [" + name + "]" + "[meta] keys can't be longer than " + META_MAX_KEY_LENGTH + " chars, but got [" + key + "] for field [" + name + "]" ); } - } - for (Object value : meta.values()) { - if (value instanceof String) { - String sValue = (String) value; - if (sValue.codePointCount(0, sValue.length()) > 50) { + + if (value == null) { + throw new MapperParsingException("[meta] values can't be null (field [" + name + "])"); + } + if (value instanceof String sValue) { + if (sValue.codePointCount(0, sValue.length()) > META_MAX_VALUE_LENGTH) { throw new MapperParsingException( - "[meta] values can't be longer than 50 chars, but got [" + value + "] for field [" + name + "]" + "[meta] values can't be longer than " + + META_MAX_VALUE_LENGTH + + " chars, but got [" + + value + + "] for field [" + + name + + "]" ); } - } else if (value == null) { - throw new MapperParsingException("[meta] values can't be null (field [" + name + "])"); } else { throw new MapperParsingException( "[meta] values can only be strings, but got " diff --git a/server/src/test/java/org/opensearch/index/mapper/TypeParsersTests.java b/server/src/test/java/org/opensearch/index/mapper/TypeParsersTests.java index 5187242f5fdac..1bb4300b1b9e3 100644 --- a/server/src/test/java/org/opensearch/index/mapper/TypeParsersTests.java +++ b/server/src/test/java/org/opensearch/index/mapper/TypeParsersTests.java @@ -117,23 +117,35 @@ public void testParseMeta() { } { + String longKeyString = IntStream.range(0, TypeParsers.META_MAX_KEY_LENGTH + 1) + .mapToObj(Integer::toString) + .collect(Collectors.joining()); MapperParsingException e = expectThrows( MapperParsingException.class, - () -> TypeParsers.parseMeta("foo", Collections.singletonMap("veryloooooooooooongkey", 3L)) + () -> TypeParsers.parseMeta("foo", Collections.singletonMap(longKeyString, 3L)) + ); + assertEquals( + "[meta] keys can't be longer than " + + TypeParsers.META_MAX_KEY_LENGTH + + " chars, but got [" + + longKeyString + + "] for field [foo]", + e.getMessage() ); - assertEquals("[meta] keys can't be longer than 20 chars, but got [veryloooooooooooongkey] for field [foo]", e.getMessage()); } { Map meta = new HashMap<>(); - meta.put("foo1", "3"); - meta.put("foo2", "3"); - meta.put("foo3", "3"); - meta.put("foo4", "3"); - meta.put("foo5", "3"); - meta.put("foo6", "3"); + for (int i = 0; i < TypeParsers.META_MAX_ENTRIES; i++) { + meta.put("foo" + i, "someValue"); + } + meta.put("extraKey", "someValue"); + assertTrue(TypeParsers.META_MAX_ENTRIES < meta.size()); MapperParsingException e = expectThrows(MapperParsingException.class, () -> TypeParsers.parseMeta("foo", meta)); - assertEquals("[meta] can't have more than 5 entries, but got 6 on field [foo]", e.getMessage()); + assertEquals( + "[meta] can't have more than " + TypeParsers.META_MAX_ENTRIES + " entries, but got " + meta.size() + " on field [foo]", + e.getMessage() + ); } { @@ -158,12 +170,17 @@ public void testParseMeta() { } { - String longString = IntStream.range(0, 51).mapToObj(Integer::toString).collect(Collectors.joining()); + String longString = IntStream.range(0, TypeParsers.META_MAX_VALUE_LENGTH + 1) + .mapToObj(Integer::toString) + .collect(Collectors.joining()); MapperParsingException e = expectThrows( MapperParsingException.class, () -> TypeParsers.parseMeta("foo", Collections.singletonMap("foo", longString)) ); - assertThat(e.getMessage(), Matchers.startsWith("[meta] values can't be longer than 50 chars")); + assertThat( + e.getMessage(), + Matchers.startsWith("[meta] values can't be longer than " + TypeParsers.META_MAX_VALUE_LENGTH + " chars") + ); } } }