From 3b827ab2f7324fc1d8de94c9914deaf490b2fc56 Mon Sep 17 00:00:00 2001 From: Tamara Braun Date: Sun, 10 Feb 2019 18:25:06 +0100 Subject: [PATCH] Enforce Completion Context Limit * Enforcing a maximum number of completion contexts as reqested in #32741 * Closes #32741 --- .../index/mapper/MapperService.java | 16 ++++++++++++++ .../index/mapper/MapperServiceTests.java | 21 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java b/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java index 398ce4cdd17ce..19c80c45aba45 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java @@ -108,6 +108,9 @@ public enum MergeReason { Setting.boolSetting("index.mapper.dynamic", INDEX_MAPPER_DYNAMIC_DEFAULT, Property.Dynamic, Property.IndexScope, Property.Deprecated); + // Maximum allowed number of completion contexts in a mapping + public static final int COMPLETION_CONTEXTS_LIMIT = 10; + //TODO this needs to be cleaned up: _timestamp and _ttl are not supported anymore, _field_names, _seq_no, _version and _source are //also missing, not sure if on purpose. See IndicesModule#getMetadataMappers private static final String[] SORTED_META_FIELDS = new String[]{ @@ -497,6 +500,7 @@ private synchronized Map internalMerge(@Nullable Documen ContextMapping.validateContextPaths(indexSettings.getIndexVersionCreated(), fieldMappers, fieldTypes::get); if (reason == MergeReason.MAPPING_UPDATE) { + checkCompletionContextsLimit(fieldMappers); // this check will only be performed on the master node when there is // a call to the update mapping API. For all other cases like // the master node restoring mappings from disk or data nodes @@ -557,6 +561,18 @@ private synchronized Map internalMerge(@Nullable Documen return results; } + private void checkCompletionContextsLimit(List fieldMappers) { + for (FieldMapper fieldMapper : fieldMappers) { + if (CompletionFieldMapper.CONTENT_TYPE.equals(fieldMapper.typeName())) { + CompletionFieldMapper.CompletionFieldType fieldType = ((CompletionFieldMapper) fieldMapper).fieldType(); + if (fieldType.hasContextMappings() && fieldType.getContextMappings().size() > COMPLETION_CONTEXTS_LIMIT) { + throw new IllegalArgumentException("Limit of contexts [" + COMPLETION_CONTEXTS_LIMIT + "] in index [" + + index().getName() + "] has been exceeded"); + } + } + } + } + private boolean assertMappersShareSameFieldType() { if (mapper != null) { List fieldMappers = new ArrayList<>(); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java b/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java index 2c1a75b40d4c0..cd5e383bc3998 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java @@ -323,4 +323,25 @@ public void testDefaultMappingIsRejectedOn7() throws IOException { + " that indices can have at most one type.", e.getMessage()); } + public void testLimitOfContextMappings() throws Throwable { + final String index = "test"; + XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().startObject().startObject("properties") + .startObject("suggest").field("type", "completion").startArray("contexts"); + for (int i = 0; i < MapperService.COMPLETION_CONTEXTS_LIMIT + 1; i++) { + mappingBuilder.startObject(); + mappingBuilder.field("name", Integer.toString(i)); + mappingBuilder.field("type", "category"); + mappingBuilder.endObject(); + } + + mappingBuilder.endArray().endObject().endObject().endObject(); + String mappings = Strings.toString(mappingBuilder); + + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> { + createIndex(index).mapperService().merge("type1", new CompressedXContent(mappings), MergeReason.MAPPING_UPDATE); + }); + assertTrue(e.getMessage(), + e.getMessage().contains("Limit of contexts [" + MapperService.COMPLETION_CONTEXTS_LIMIT + + "] in index [" + index + "] has been exceeded")); + } }