Skip to content

Commit 02ca61c

Browse files
committed
Deprecates _search request with trailing tokens
This change validates that the _search request does not have trailing tokens after the main object and prints a deprecation message otherwise. Relates #29428
1 parent 1690178 commit 02ca61c

File tree

11 files changed

+62
-14
lines changed

11 files changed

+62
-14
lines changed

client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,7 @@ public void testMultiSearch() throws IOException {
11571157

11581158
List<SearchRequest> requests = new ArrayList<>();
11591159
CheckedBiConsumer<SearchRequest, XContentParser, IOException> consumer = (searchRequest, p) -> {
1160-
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.fromXContent(p);
1160+
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.fromXContent(p, false);
11611161
if (searchSourceBuilder.equals(new SearchSourceBuilder()) == false) {
11621162
searchRequest.source(searchSourceBuilder);
11631163
}

docs/reference/migration/migrate_6_0/search.asciidoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,10 @@ as each additional term demands extra processing and memory.
201201
To safeguard against this, the maximum number of terms that can be used in a
202202
Terms Query request has been limited to 65536. This default maximum can be changed
203203
for a particular index with the index setting `index.max_terms_count`.
204+
205+
==== Invalid `_search` request body
206+
207+
For 6.x and starting in 6.3 a deprecation warning will be printed to warn
208+
against search requests that contain extra tokens after the main object.
209+
These extra tokens were ignored by the query parser before 6.3 but the next
210+
major version will not accept invalid body anymore.

modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/TransportSearchTemplateAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static SearchRequest convert(SearchTemplateRequest searchTemplateRequest, Search
112112
try (XContentParser parser = XContentFactory.xContent(XContentType.JSON)
113113
.createParser(xContentRegistry, LoggingDeprecationHandler.INSTANCE, source)) {
114114
SearchSourceBuilder builder = SearchSourceBuilder.searchSource();
115-
builder.parseXContent(parser);
115+
builder.parseXContent(parser, false);
116116
builder.explain(searchTemplateRequest.isExplain());
117117
builder.profile(searchTemplateRequest.isProfile());
118118
searchRequest.source(builder);

modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RatedRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ public void addSummaryFields(List<String> summaryFields) {
223223
return RatedDocument.fromXContent(p);
224224
}, RATINGS_FIELD);
225225
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) ->
226-
SearchSourceBuilder.fromXContent(p), REQUEST_FIELD);
226+
SearchSourceBuilder.fromXContent(p, false), REQUEST_FIELD);
227227
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.map(), PARAMS_FIELD);
228228
PARSER.declareStringArray(RatedRequest::addSummaryFields, FIELDS_FIELD);
229229
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), TEMPLATE_ID_FIELD);

modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/TransportRankEvalAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ protected void doExecute(RankEvalRequest request, ActionListener<RankEvalRespons
107107
String resolvedRequest = templateScript.newInstance(params).execute();
108108
try (XContentParser subParser = createParser(namedXContentRegistry,
109109
LoggingDeprecationHandler.INSTANCE, new BytesArray(resolvedRequest), XContentType.JSON)) {
110-
ratedSearchSource = SearchSourceBuilder.fromXContent(subParser);
110+
ratedSearchSource = SearchSourceBuilder.fromXContent(subParser, false);
111111
} catch (IOException e) {
112112
// if we fail parsing, put the exception into the errors map and continue
113113
errors.put(ratedRequest.getId(), e);

modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestReindexAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public class RestReindexAction extends AbstractBaseReindexRestHandler<ReindexReq
7777
try (InputStream stream = BytesReference.bytes(builder).streamInput();
7878
XContentParser innerParser = parser.contentType().xContent()
7979
.createParser(parser.getXContentRegistry(), parser.getDeprecationHandler(), stream)) {
80-
request.getSearchRequest().source().parseXContent(innerParser);
80+
request.getSearchRequest().source().parseXContent(innerParser, false);
8181
}
8282
};
8383

server/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public static MultiSearchRequest parseRequest(RestRequest restRequest, boolean a
9494

9595

9696
parseMultiLineRequest(restRequest, multiRequest.indicesOptions(), allowExplicitIndex, (searchRequest, parser) -> {
97-
searchRequest.source(SearchSourceBuilder.fromXContent(parser));
97+
searchRequest.source(SearchSourceBuilder.fromXContent(parser, false));
9898
multiRequest.add(searchRequest);
9999
});
100100
List<SearchRequest> requests = multiRequest.requests();

server/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.rest.action.search;
2121

22+
import org.apache.lucene.util.BytesRef;
2223
import org.elasticsearch.action.search.SearchRequest;
2324
import org.elasticsearch.action.support.IndicesOptions;
2425
import org.elasticsearch.client.node.NodeClient;
@@ -109,7 +110,7 @@ public static void parseSearchRequest(SearchRequest searchRequest, RestRequest r
109110
}
110111
searchRequest.indices(Strings.splitStringByCommaToArray(request.param("index")));
111112
if (requestContentParser != null) {
112-
searchRequest.source().parseXContent(requestContentParser);
113+
searchRequest.source().parseXContent(requestContentParser, true);
113114
}
114115

115116
final int batchedReduceSize = request.paramAsInt("batched_reduce_size", searchRequest.getBatchedReduceSize());
@@ -128,7 +129,7 @@ public static void parseSearchRequest(SearchRequest searchRequest, RestRequest r
128129
// only set if we have the parameter passed to override the cluster-level default
129130
searchRequest.allowPartialSearchResults(request.paramAsBoolean("allow_partial_search_results", null));
130131
}
131-
132+
132133
// do not allow 'query_and_fetch' or 'dfs_query_and_fetch' search types
133134
// from the REST layer. these modes are an internal optimization and should
134135
// not be specified explicitly by the user.

server/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package org.elasticsearch.search.builder;
2121

22+
import com.fasterxml.jackson.core.JsonParseException;
23+
import org.apache.lucene.util.BytesRef;
2224
import org.elasticsearch.ElasticsearchException;
2325
import org.elasticsearch.Version;
2426
import org.elasticsearch.common.Nullable;
@@ -111,8 +113,12 @@ public final class SearchSourceBuilder implements Writeable, ToXContentObject, R
111113
public static final ParseField ALL_FIELDS_FIELDS = new ParseField("all_fields");
112114

113115
public static SearchSourceBuilder fromXContent(XContentParser parser) throws IOException {
116+
return fromXContent(parser, true);
117+
}
118+
119+
public static SearchSourceBuilder fromXContent(XContentParser parser, boolean checkTrailingTokens) throws IOException {
114120
SearchSourceBuilder builder = new SearchSourceBuilder();
115-
builder.parseXContent(parser);
121+
builder.parseXContent(parser, checkTrailingTokens);
116122
return builder;
117123
}
118124

@@ -951,12 +957,19 @@ private SearchSourceBuilder shallowCopy(QueryBuilder queryBuilder, QueryBuilder
951957
return rewrittenBuilder;
952958
}
953959

960+
public void parseXContent(XContentParser parser) throws IOException {
961+
parseXContent(parser, true);
962+
}
963+
954964
/**
955965
* Parse some xContent into this SearchSourceBuilder, overwriting any values specified in the xContent. Use this if you need to set up
956-
* different defaults than a regular SearchSourceBuilder would have and use
957-
* {@link #fromXContent(XContentParser)} if you have normal defaults.
966+
* different defaults than a regular SearchSourceBuilder would have and use {@link #fromXContent(XContentParser, boolean)} if you have
967+
* normal defaults.
968+
*
969+
* @param parser The xContent parser.
970+
* @param checkTrailingTokens If true throws a parsing exception when extra tokens are found after the main object.
958971
*/
959-
public void parseXContent(XContentParser parser) throws IOException {
972+
public void parseXContent(XContentParser parser, boolean checkTrailingTokens) throws IOException {
960973
XContentParser.Token token = parser.currentToken();
961974
String currentFieldName = null;
962975
if (token != XContentParser.Token.START_OBJECT && (token = parser.nextToken()) != XContentParser.Token.START_OBJECT) {
@@ -1106,6 +1119,19 @@ public void parseXContent(XContentParser parser) throws IOException {
11061119
parser.getTokenLocation());
11071120
}
11081121
}
1122+
if (checkTrailingTokens) {
1123+
boolean success;
1124+
try {
1125+
token = parser.nextToken();
1126+
success = token == null;
1127+
} catch (JsonParseException exc) {
1128+
success = false;
1129+
}
1130+
if (success == false) {
1131+
DEPRECATION_LOGGER.deprecated("Found extra tokens after the _search request body, " +
1132+
"an error will be thrown in the next major version");
1133+
}
1134+
}
11091135
}
11101136

11111137
@Override

server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ public void testMultiLineSerialization() throws IOException {
222222
byte[] originalBytes = MultiSearchRequest.writeMultiLineFormat(originalRequest, xContentType.xContent());
223223
MultiSearchRequest parsedRequest = new MultiSearchRequest();
224224
CheckedBiConsumer<SearchRequest, XContentParser, IOException> consumer = (r, p) -> {
225-
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.fromXContent(p);
225+
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.fromXContent(p, false);
226226
if (searchSourceBuilder.equals(new SearchSourceBuilder()) == false) {
227227
r.source(searchSourceBuilder);
228228
}
@@ -270,7 +270,7 @@ private static MultiSearchRequest createMultiSearchRequest() throws IOException
270270
if (randomBoolean()) {
271271
searchRequest.allowPartialSearchResults(true);
272272
}
273-
273+
274274
// scroll is not supported in the current msearch api, so unset it:
275275
searchRequest.scroll((Scroll) null);
276276

server/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,20 @@ public void testFromXContent() throws IOException {
6767
assertParseSearchSource(testSearchSourceBuilder, createParser(builder));
6868
}
6969

70+
public void testFromXContentInvalid() throws IOException {
71+
try (XContentParser parser = createParser(JsonXContent.jsonXContent, "{}}")) {
72+
SearchSourceBuilder.fromXContent(parser);
73+
assertWarnings("Found extra tokens after the _search request body, " +
74+
"an error will be thrown in the next major version");
75+
}
76+
77+
try (XContentParser parser = createParser(JsonXContent.jsonXContent, "{}{}")) {
78+
SearchSourceBuilder.fromXContent(parser);
79+
assertWarnings("Found extra tokens after the _search request body, " +
80+
"an error will be thrown in the next major version");
81+
}
82+
}
83+
7084
private static void assertParseSearchSource(SearchSourceBuilder testBuilder, XContentParser parser) throws IOException {
7185
if (randomBoolean()) {
7286
parser.nextToken(); // sometimes we move it on the START_OBJECT to

0 commit comments

Comments
 (0)