diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c7d7aa9bf780..354a2b3549cfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fix constraint bug which allows more primary shards than average primary shards per index ([#14908](https://github.com/opensearch-project/OpenSearch/pull/14908)) - Fix missing value of FieldSort for unsigned_long ([#14963](https://github.com/opensearch-project/OpenSearch/pull/14963)) - Fix delete index template failed when the index template matches a data stream but is unused ([#15080](https://github.com/opensearch-project/OpenSearch/pull/15080)) +- Fix array_index_out_of_bounds_exception when indexing documents with field name containing only dot ### Security diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/index/120_field_name.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/index/120_field_name.yml new file mode 100644 index 0000000000000..181a5589ffb02 --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/index/120_field_name.yml @@ -0,0 +1,38 @@ +--- +"Index documents with field name containing only dot fail with an IllegalArgumentException": + - skip: + version: " - 2.99.99" + reason: "introduced in 3.0.0" + + - do: + indices.create: + index: test_1 + + - do: + catch: /field name cannot contain only dot/ + index: + index: test_1 + id: 1 + body: { + .: bar + } + + - do: + catch: /field name cannot contain only dot/ + index: + index: test_1 + id: 1 + body: { + ..: bar + } + + - do: + catch: /field name cannot contain only dot/ + index: + index: test_1 + id: 1 + body: { + foo: { + .: bar + } + } diff --git a/server/src/main/java/org/opensearch/index/mapper/DocumentParser.java b/server/src/main/java/org/opensearch/index/mapper/DocumentParser.java index c6815ebe8d91a..8dfa8ff4996ba 100644 --- a/server/src/main/java/org/opensearch/index/mapper/DocumentParser.java +++ b/server/src/main/java/org/opensearch/index/mapper/DocumentParser.java @@ -206,6 +206,9 @@ private static MapperParsingException wrapInMapperParsingException(SourceToParse private static String[] splitAndValidatePath(String fullFieldPath) { if (fullFieldPath.contains(".")) { String[] parts = fullFieldPath.split("\\."); + if (parts.length == 0) { + throw new IllegalArgumentException("field name cannot contain only dot"); + } for (String part : parts) { if (Strings.hasText(part) == false) { // check if the field name contains only whitespace diff --git a/server/src/test/java/org/opensearch/index/mapper/DocumentParserTests.java b/server/src/test/java/org/opensearch/index/mapper/DocumentParserTests.java index 15e2b6649b0be..e183885416c3a 100644 --- a/server/src/test/java/org/opensearch/index/mapper/DocumentParserTests.java +++ b/server/src/test/java/org/opensearch/index/mapper/DocumentParserTests.java @@ -1700,6 +1700,38 @@ public void testDynamicFieldsStartingAndEndingWithDot() throws Exception { ); } + public void testDynamicFieldsWithOnlyDot() throws Exception { + DocumentMapper mapper = createDocumentMapper(mapping(b -> {})); + + MapperParsingException e = expectThrows(MapperParsingException.class, () -> mapper.parse(source(b -> { + b.startArray("top"); + { + b.startObject(); + { + b.startObject("inner").field(".", 2).endObject(); + } + b.endObject(); + } + b.endArray(); + }))); + + assertThat(e.getCause(), notNullValue()); + assertThat(e.getCause().getMessage(), containsString("field name cannot contain only dot")); + + e = expectThrows( + MapperParsingException.class, + () -> mapper.parse(source(b -> { b.startObject("..").field("foo", 2).endObject(); })) + ); + + assertThat(e.getCause(), notNullValue()); + assertThat(e.getCause().getMessage(), containsString("field name cannot contain only dot")); + + e = expectThrows(MapperParsingException.class, () -> mapper.parse(source(b -> b.field(".", "1234")))); + + assertThat(e.getCause(), notNullValue()); + assertThat(e.getCause().getMessage(), containsString("field name cannot contain only dot")); + } + public void testDynamicFieldsEmptyName() throws Exception { DocumentMapper mapper = createDocumentMapper(mapping(b -> {}));