Skip to content

Commit c7887f4

Browse files
committed
Internal: make sure ParseField is always used in combination with parse flags
Removed ParseField#match variant that accepts the field name only, without parse flags. Such a method is harmful as it defaults to empty parse flags, meaning that no deprecation exceptions will be thrown in strict mode, which defeats the purpose of using ParseField. Unfortunately such a method was used in a lot of places were the parse flags weren't easily accessible (outside of query parsing), and in a lot of other places just by mistake. Parse flags have been introduced now as part of SearchContext and mappers where needed. There are a few places (e.g. java api requests) where it is not possible to retrieve them as they depend on the index settings, in that case we explicitly pass in EMPTY_FLAGS for now, but this has to be seen as an exception. Closes #11859
1 parent 72d9914 commit c7887f4

File tree

97 files changed

+593
-608
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+593
-608
lines changed

core/src/main/java/org/elasticsearch/action/admin/indices/validate/query/TransportValidateQueryAction.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ protected ShardValidateQueryResponse shardOperation(ShardValidateQueryRequest re
168168
DefaultSearchContext searchContext = new DefaultSearchContext(0,
169169
new ShardSearchLocalRequest(request.types(), request.nowInMillis(), request.filteringAliases()),
170170
null, searcher, indexService, indexShard,
171-
scriptService, pageCacheRecycler, bigArrays, threadPool.estimatedTimeInMillisCounter()
171+
scriptService, pageCacheRecycler, bigArrays, threadPool.estimatedTimeInMillisCounter(), parseFieldMatcher
172172
);
173173
SearchContext.setCurrent(searchContext);
174174
try {
@@ -187,10 +187,7 @@ protected ShardValidateQueryResponse shardOperation(ShardValidateQueryRequest re
187187
} catch (QueryParsingException e) {
188188
valid = false;
189189
error = e.getDetailedMessage();
190-
} catch (AssertionError e) {
191-
valid = false;
192-
error = e.getMessage();
193-
} catch (IOException e) {
190+
} catch (AssertionError|IOException e) {
194191
valid = false;
195192
error = e.getMessage();
196193
} finally {

core/src/main/java/org/elasticsearch/action/exists/TransportExistsAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ protected ShardExistsResponse shardOperation(ShardExistsRequest request) {
151151
SearchContext context = new DefaultSearchContext(0,
152152
new ShardSearchLocalRequest(request.types(), request.nowInMillis(), request.filteringAliases()),
153153
shardTarget, indexShard.acquireSearcher("exists"), indexService, indexShard,
154-
scriptService, pageCacheRecycler, bigArrays, threadPool.estimatedTimeInMillisCounter());
154+
scriptService, pageCacheRecycler, bigArrays, threadPool.estimatedTimeInMillisCounter(), parseFieldMatcher);
155155
SearchContext.setCurrent(context);
156156

157157
try {

core/src/main/java/org/elasticsearch/action/explain/TransportExplainAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ protected ExplainResponse shardOperation(ExplainRequest request, ShardId shardId
113113
0, new ShardSearchLocalRequest(new String[]{request.type()}, request.nowInMillis, request.filteringAlias()),
114114
null, result.searcher(), indexService, indexShard,
115115
scriptService, pageCacheRecycler,
116-
bigArrays, threadPool.estimatedTimeInMillisCounter()
116+
bigArrays, threadPool.estimatedTimeInMillisCounter(), parseFieldMatcher
117117
);
118118
SearchContext.setCurrent(context);
119119

core/src/main/java/org/elasticsearch/action/search/SearchRequest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.elasticsearch.action.support.IndicesOptions;
2727
import org.elasticsearch.client.Requests;
2828
import org.elasticsearch.common.Nullable;
29+
import org.elasticsearch.common.ParseFieldMatcher;
2930
import org.elasticsearch.common.Strings;
3031
import org.elasticsearch.common.bytes.BytesArray;
3132
import org.elasticsearch.common.bytes.BytesReference;
@@ -239,7 +240,7 @@ public SearchRequest searchType(SearchType searchType) {
239240
* "query_then_fetch"/"queryThenFetch", and "query_and_fetch"/"queryAndFetch".
240241
*/
241242
public SearchRequest searchType(String searchType) {
242-
return searchType(SearchType.fromString(searchType));
243+
return searchType(SearchType.fromString(searchType, ParseFieldMatcher.EMPTY));
243244
}
244245

245246
/**

core/src/main/java/org/elasticsearch/action/search/SearchType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.action.search;
2121

2222
import org.elasticsearch.common.ParseField;
23+
import org.elasticsearch.common.ParseFieldMatcher;
2324

2425
/**
2526
* Search type represent the manner at which the search operation is executed.
@@ -108,7 +109,7 @@ public static SearchType fromId(byte id) {
108109
* one of "dfs_query_then_fetch"/"dfsQueryThenFetch", "dfs_query_and_fetch"/"dfsQueryAndFetch",
109110
* "query_then_fetch"/"queryThenFetch", "query_and_fetch"/"queryAndFetch", and "scan".
110111
*/
111-
public static SearchType fromString(String searchType) {
112+
public static SearchType fromString(String searchType, ParseFieldMatcher parseFieldMatcher) {
112113
if (searchType == null) {
113114
return SearchType.DEFAULT;
114115
}
@@ -122,7 +123,7 @@ public static SearchType fromString(String searchType) {
122123
return SearchType.QUERY_AND_FETCH;
123124
} else if ("scan".equals(searchType)) {
124125
return SearchType.SCAN;
125-
} else if (COUNT_VALUE.match(searchType)) {
126+
} else if (parseFieldMatcher.match(searchType, COUNT_VALUE)) {
126127
return SearchType.COUNT;
127128
} else {
128129
throw new IllegalArgumentException("No search type for [" + searchType + "]");

core/src/main/java/org/elasticsearch/action/support/TransportAction.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.action.support;
2121

2222
import org.elasticsearch.action.*;
23+
import org.elasticsearch.common.ParseFieldMatcher;
2324
import org.elasticsearch.common.component.AbstractComponent;
2425
import org.elasticsearch.common.logging.ESLogger;
2526
import org.elasticsearch.common.settings.Settings;
@@ -37,9 +38,11 @@ public abstract class TransportAction<Request extends ActionRequest, Response ex
3738
protected final ThreadPool threadPool;
3839
protected final String actionName;
3940
private final ActionFilter[] filters;
41+
protected final ParseFieldMatcher parseFieldMatcher;
4042

4143
protected TransportAction(Settings settings, String actionName, ThreadPool threadPool, ActionFilters actionFilters) {
4244
super(settings);
45+
this.parseFieldMatcher = new ParseFieldMatcher(settings);
4346
this.actionName = actionName;
4447
this.filters = actionFilters.filters();
4548
this.threadPool = threadPool;

core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.action.index.IndexRequest;
2626
import org.elasticsearch.action.support.single.instance.InstanceShardOperationRequest;
2727
import org.elasticsearch.common.Nullable;
28+
import org.elasticsearch.common.ParseFieldMatcher;
2829
import org.elasticsearch.common.bytes.BytesArray;
2930
import org.elasticsearch.common.bytes.BytesReference;
3031
import org.elasticsearch.common.io.stream.StreamInput;
@@ -291,13 +292,13 @@ public String scriptLang() {
291292
public UpdateRequest addScriptParam(String name, Object value) {
292293
Script script = script();
293294
if (script == null) {
294-
HashMap<String, Object> scriptParams = new HashMap<String, Object>();
295+
HashMap<String, Object> scriptParams = new HashMap<>();
295296
scriptParams.put(name, value);
296297
updateOrCreateScript(null, null, null, scriptParams);
297298
} else {
298299
Map<String, Object> scriptParams = script.getParams();
299300
if (scriptParams == null) {
300-
scriptParams = new HashMap<String, Object>();
301+
scriptParams = new HashMap<>();
301302
scriptParams.put(name, value);
302303
updateOrCreateScript(null, null, null, scriptParams);
303304
} else {
@@ -648,7 +649,8 @@ public UpdateRequest source(BytesReference source) throws Exception {
648649
if (token == XContentParser.Token.FIELD_NAME) {
649650
currentFieldName = parser.currentName();
650651
} else if ("script".equals(currentFieldName) && token == XContentParser.Token.START_OBJECT) {
651-
script = Script.parse(parser);
652+
//here we don't have settings available, unable to throw strict deprecation exceptions
653+
script = Script.parse(parser, ParseFieldMatcher.EMPTY);
652654
} else if ("params".equals(currentFieldName)) {
653655
scriptParams = parser.map();
654656
} else if ("scripted_upsert".equals(currentFieldName)) {
@@ -666,7 +668,8 @@ public UpdateRequest source(BytesReference source) throws Exception {
666668
} else if ("detect_noop".equals(currentFieldName)) {
667669
detectNoop(parser.booleanValue());
668670
} else {
669-
scriptParameterParser.token(currentFieldName, token, parser);
671+
//here we don't have settings available, unable to throw deprecation exceptions
672+
scriptParameterParser.token(currentFieldName, token, parser, ParseFieldMatcher.EMPTY);
670673
}
671674
}
672675
// Don't have a script using the new API so see if it is specified with the old API

core/src/main/java/org/elasticsearch/common/ParseField.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,18 @@
2323
import java.util.HashSet;
2424

2525
/**
26+
* Holds a field that can be found in a request while parsing and its different variants, which may be deprecated.
2627
*/
2728
public class ParseField {
2829
private final String camelCaseName;
2930
private final String underscoreName;
3031
private final String[] deprecatedNames;
3132
private String allReplacedWith = null;
3233

33-
public static final EnumSet<Flag> EMPTY_FLAGS = EnumSet.noneOf(Flag.class);
34+
static final EnumSet<Flag> EMPTY_FLAGS = EnumSet.noneOf(Flag.class);
35+
static final EnumSet<Flag> STRICT_FLAGS = EnumSet.of(Flag.STRICT);
3436

35-
public static enum Flag {
37+
enum Flag {
3638
STRICT
3739
}
3840

@@ -47,7 +49,7 @@ public ParseField(String value, String... deprecatedNames) {
4749
set.add(Strings.toCamelCase(depName));
4850
set.add(Strings.toUnderscoreCase(depName));
4951
}
50-
this.deprecatedNames = set.toArray(new String[0]);
52+
this.deprecatedNames = set.toArray(new String[set.size()]);
5153
}
5254
}
5355

@@ -78,11 +80,7 @@ public ParseField withAllDeprecated(String allReplacedWith) {
7880
return parseField;
7981
}
8082

81-
public boolean match(String currentFieldName) {
82-
return match(currentFieldName, EMPTY_FLAGS);
83-
}
84-
85-
public boolean match(String currentFieldName, EnumSet<Flag> flags) {
83+
boolean match(String currentFieldName, EnumSet<Flag> flags) {
8684
if (allReplacedWith == null && (currentFieldName.equals(camelCaseName) || currentFieldName.equals(underscoreName))) {
8785
return true;
8886
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.common;
21+
22+
import org.elasticsearch.common.settings.Settings;
23+
import org.elasticsearch.index.query.IndexQueryParserService;
24+
25+
import java.util.EnumSet;
26+
27+
/**
28+
* Matcher to use in combination with {@link ParseField} while parsing requests. Matches a {@link ParseField}
29+
* against a field name and throw deprecation exception depending on the current value of the {@link IndexQueryParserService#PARSE_STRICT} setting.
30+
*/
31+
public class ParseFieldMatcher {
32+
33+
public static final ParseFieldMatcher EMPTY = new ParseFieldMatcher(ParseField.EMPTY_FLAGS);
34+
public static final ParseFieldMatcher STRICT = new ParseFieldMatcher(ParseField.STRICT_FLAGS);
35+
36+
private final EnumSet<ParseField.Flag> parseFlags;
37+
38+
public ParseFieldMatcher(Settings settings) {
39+
if (settings.getAsBoolean(IndexQueryParserService.PARSE_STRICT, false)) {
40+
this.parseFlags = EnumSet.of(ParseField.Flag.STRICT);
41+
} else {
42+
this.parseFlags = ParseField.EMPTY_FLAGS;
43+
}
44+
}
45+
46+
public ParseFieldMatcher(EnumSet<ParseField.Flag> parseFlags) {
47+
this.parseFlags = parseFlags;
48+
}
49+
50+
/**
51+
* Matches a {@link ParseField} against a field name, and throws deprecation exception depending on the current
52+
* value of the {@link IndexQueryParserService#PARSE_STRICT} setting.
53+
* @param fieldName the field name found in the request while parsing
54+
* @param parseField the parse field that we are looking for
55+
* @throws IllegalArgumentException whenever we are in strict mode and the request contained a deprecated field
56+
* @return true whenever the parse field that we are looking for was found, false otherwise
57+
*/
58+
public boolean match(String fieldName, ParseField parseField) {
59+
return parseField.match(fieldName, parseFlags);
60+
}
61+
}

core/src/main/java/org/elasticsearch/index/mapper/DocumentMapperParser.java

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121

2222
import com.google.common.collect.ImmutableMap;
2323
import com.google.common.collect.Maps;
24-
2524
import org.elasticsearch.Version;
2625
import org.elasticsearch.common.Nullable;
26+
import org.elasticsearch.common.ParseFieldMatcher;
2727
import org.elasticsearch.common.Strings;
2828
import org.elasticsearch.common.collect.MapBuilder;
2929
import org.elasticsearch.common.collect.Tuple;
@@ -38,35 +38,10 @@
3838
import org.elasticsearch.index.AbstractIndexComponent;
3939
import org.elasticsearch.index.Index;
4040
import org.elasticsearch.index.analysis.AnalysisService;
41-
import org.elasticsearch.index.mapper.core.BinaryFieldMapper;
42-
import org.elasticsearch.index.mapper.core.BooleanFieldMapper;
43-
import org.elasticsearch.index.mapper.core.ByteFieldMapper;
44-
import org.elasticsearch.index.mapper.core.CompletionFieldMapper;
45-
import org.elasticsearch.index.mapper.core.DateFieldMapper;
46-
import org.elasticsearch.index.mapper.core.DoubleFieldMapper;
47-
import org.elasticsearch.index.mapper.core.FloatFieldMapper;
48-
import org.elasticsearch.index.mapper.core.IntegerFieldMapper;
49-
import org.elasticsearch.index.mapper.core.LongFieldMapper;
50-
import org.elasticsearch.index.mapper.core.Murmur3FieldMapper;
51-
import org.elasticsearch.index.mapper.core.ShortFieldMapper;
52-
import org.elasticsearch.index.mapper.core.StringFieldMapper;
53-
import org.elasticsearch.index.mapper.core.TokenCountFieldMapper;
54-
import org.elasticsearch.index.mapper.core.TypeParsers;
41+
import org.elasticsearch.index.mapper.core.*;
5542
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
5643
import org.elasticsearch.index.mapper.geo.GeoShapeFieldMapper;
57-
import org.elasticsearch.index.mapper.internal.AllFieldMapper;
58-
import org.elasticsearch.index.mapper.internal.FieldNamesFieldMapper;
59-
import org.elasticsearch.index.mapper.internal.IdFieldMapper;
60-
import org.elasticsearch.index.mapper.internal.IndexFieldMapper;
61-
import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
62-
import org.elasticsearch.index.mapper.internal.RoutingFieldMapper;
63-
import org.elasticsearch.index.mapper.internal.SizeFieldMapper;
64-
import org.elasticsearch.index.mapper.internal.SourceFieldMapper;
65-
import org.elasticsearch.index.mapper.internal.TTLFieldMapper;
66-
import org.elasticsearch.index.mapper.internal.TimestampFieldMapper;
67-
import org.elasticsearch.index.mapper.internal.TypeFieldMapper;
68-
import org.elasticsearch.index.mapper.internal.UidFieldMapper;
69-
import org.elasticsearch.index.mapper.internal.VersionFieldMapper;
44+
import org.elasticsearch.index.mapper.internal.*;
7045
import org.elasticsearch.index.mapper.ip.IpFieldMapper;
7146
import org.elasticsearch.index.mapper.object.ObjectMapper;
7247
import org.elasticsearch.index.mapper.object.RootObjectMapper;
@@ -96,13 +71,15 @@ public class DocumentMapperParser extends AbstractIndexComponent {
9671

9772
private final Object typeParsersMutex = new Object();
9873
private final Version indexVersionCreated;
74+
private final ParseFieldMatcher parseFieldMatcher;
9975

10076
private volatile ImmutableMap<String, Mapper.TypeParser> typeParsers;
10177
private volatile ImmutableMap<String, Mapper.TypeParser> rootTypeParsers;
10278

10379
public DocumentMapperParser(Index index, @IndexSettings Settings indexSettings, MapperService mapperService, AnalysisService analysisService,
10480
SimilarityLookupService similarityLookupService, ScriptService scriptService) {
10581
super(index, indexSettings);
82+
this.parseFieldMatcher = new ParseFieldMatcher(indexSettings);
10683
this.mapperService = mapperService;
10784
this.analysisService = analysisService;
10885
this.similarityLookupService = similarityLookupService;
@@ -168,7 +145,7 @@ public void putRootTypeParser(String type, Mapper.TypeParser typeParser) {
168145
}
169146

170147
public Mapper.TypeParser.ParserContext parserContext() {
171-
return new Mapper.TypeParser.ParserContext(analysisService, similarityLookupService, mapperService, typeParsers, indexVersionCreated);
148+
return new Mapper.TypeParser.ParserContext(analysisService, similarityLookupService, mapperService, typeParsers, indexVersionCreated, parseFieldMatcher);
172149
}
173150

174151
public DocumentMapper parse(String source) throws MapperParsingException {
@@ -296,7 +273,7 @@ private static String getRemainingFields(Map<String, ?> map) {
296273
}
297274

298275
private void parseTransform(DocumentMapper.Builder docBuilder, Map<String, Object> transformConfig, Version indexVersionCreated) {
299-
Script script = Script.parse(transformConfig, true);
276+
Script script = Script.parse(transformConfig, true, parseFieldMatcher);
300277
if (script != null) {
301278
docBuilder.transform(scriptService, script);
302279
}

core/src/main/java/org/elasticsearch/index/mapper/Mapper.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.common.collect.ImmutableMap;
2323
import org.elasticsearch.Version;
2424
import org.elasticsearch.common.Nullable;
25+
import org.elasticsearch.common.ParseFieldMatcher;
2526
import org.elasticsearch.common.Strings;
2627
import org.elasticsearch.common.settings.Settings;
2728
import org.elasticsearch.common.xcontent.ToXContent;
@@ -92,14 +93,17 @@ class ParserContext {
9293

9394
private final Version indexVersionCreated;
9495

96+
private final ParseFieldMatcher parseFieldMatcher;
97+
9598
public ParserContext(AnalysisService analysisService, SimilarityLookupService similarityLookupService,
96-
MapperService mapperService,
97-
ImmutableMap<String, TypeParser> typeParsers, Version indexVersionCreated) {
99+
MapperService mapperService, ImmutableMap<String, TypeParser> typeParsers,
100+
Version indexVersionCreated, ParseFieldMatcher parseFieldMatcher) {
98101
this.analysisService = analysisService;
99102
this.similarityLookupService = similarityLookupService;
100103
this.mapperService = mapperService;
101104
this.typeParsers = typeParsers;
102105
this.indexVersionCreated = indexVersionCreated;
106+
this.parseFieldMatcher = parseFieldMatcher;
103107
}
104108

105109
public AnalysisService analysisService() {
@@ -121,6 +125,10 @@ public TypeParser typeParser(String type) {
121125
public Version indexVersionCreated() {
122126
return indexVersionCreated;
123127
}
128+
129+
public ParseFieldMatcher parseFieldMatcher() {
130+
return parseFieldMatcher;
131+
}
124132
}
125133

126134
Mapper.Builder<?,?> parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException;

core/src/main/java/org/elasticsearch/index/mapper/core/BinaryFieldMapper.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121

2222
import com.carrotsearch.hppc.ObjectArrayList;
2323
import org.apache.lucene.document.Field;
24-
import org.apache.lucene.document.FieldType;
25-
import org.apache.lucene.index.DocValuesType;
2624
import org.apache.lucene.index.IndexOptions;
2725
import org.apache.lucene.store.ByteArrayDataOutput;
2826
import org.apache.lucene.util.BytesRef;
@@ -35,7 +33,6 @@
3533
import org.elasticsearch.common.bytes.BytesArray;
3634
import org.elasticsearch.common.bytes.BytesReference;
3735
import org.elasticsearch.common.compress.CompressorFactory;
38-
import org.elasticsearch.common.compress.NotXContentException;
3936
import org.elasticsearch.common.settings.Settings;
4037
import org.elasticsearch.common.util.CollectionUtils;
4138
import org.elasticsearch.common.xcontent.XContentParser;
@@ -98,7 +95,7 @@ public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext
9895
Map.Entry<String, Object> entry = iterator.next();
9996
String fieldName = entry.getKey();
10097
if (parserContext.indexVersionCreated().before(Version.V_2_0_0) &&
101-
(COMPRESS.match(fieldName) || COMPRESS_THRESHOLD.match(fieldName))) {
98+
(parserContext.parseFieldMatcher().match(fieldName, COMPRESS) || parserContext.parseFieldMatcher().match(fieldName, COMPRESS_THRESHOLD))) {
10299
iterator.remove();
103100
}
104101
}

0 commit comments

Comments
 (0)