From e9e1f358b0ee920d2cce83aab7beef88a7665e8a Mon Sep 17 00:00:00 2001 From: pgomulka Date: Fri, 30 Jul 2021 13:51:08 +0200 Subject: [PATCH] [Rest Api Compatibility] Allow first empty line for msearch The support for this buggy behaviour was removed in #41011 however since this is a change that affects a request shape it should still be available to use it in rest api compatibility relates #51816 --- .../action/search/MultiSearchRequest.java | 11 ++- .../search/MultiSearchRequestTests.java | 73 ++++++++++++++++++- .../search/msearch-empty-first-line1.json | 9 +++ .../search/msearch-empty-first-line2.json | 10 +++ 4 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 server/src/test/resources/org/elasticsearch/action/search/msearch-empty-first-line1.json create mode 100644 server/src/test/resources/org/elasticsearch/action/search/msearch-empty-first-line2.json diff --git a/server/src/main/java/org/elasticsearch/action/search/MultiSearchRequest.java b/server/src/main/java/org/elasticsearch/action/search/MultiSearchRequest.java index 96d4d1199a8ab..448384d7bfee7 100644 --- a/server/src/main/java/org/elasticsearch/action/search/MultiSearchRequest.java +++ b/server/src/main/java/org/elasticsearch/action/search/MultiSearchRequest.java @@ -53,7 +53,9 @@ public class MultiSearchRequest extends ActionRequest implements CompositeIndice private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(RestSearchAction.class); public static final String TYPES_DEPRECATION_MESSAGE = "[types removal]" + " Specifying types in search requests is deprecated."; - + public static final String FIRST_LINE_EMPTY_DEPRECATION_MESSAGE = + "support for empty first line before any action metadata in msearch API is deprecated " + + "and will be removed in the next major version"; public static final int MAX_CONCURRENT_SEARCH_REQUESTS_DEFAULT = 0; private int maxConcurrentSearchRequests = 0; @@ -185,6 +187,13 @@ public static void readMultiLineFormat(BytesReference data, if (nextMarker == -1) { break; } + // support first line with \n + if (restApiVersion == RestApiVersion.V_7 && nextMarker == 0) { + deprecationLogger.compatibleApiWarning("msearch_first_line_empty", FIRST_LINE_EMPTY_DEPRECATION_MESSAGE); + from = nextMarker + 1; + continue; + } + SearchRequest searchRequest = new SearchRequest(); if (indices != null) { searchRequest.indices(indices); diff --git a/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java b/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java index 964777b03a92a..8bc96be821798 100644 --- a/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java @@ -209,10 +209,15 @@ public void testMsearchTerminatedByNewline() throws Exception { assertEquals(3, msearchRequest.requests().size()); } + private MultiSearchRequest parseMultiSearchRequestFromString(String request, RestApiVersion restApiVersion) throws IOException { + return parseMultiSearchRequest(createRestRequest(request.getBytes(StandardCharsets.UTF_8), restApiVersion)); + } + private MultiSearchRequest parseMultiSearchRequest(String sample) throws IOException { - byte[] data = StreamsUtils.copyToBytesFromClasspath(sample); - RestRequest restRequest = new FakeRestRequest.Builder(xContentRegistry()) - .withContent(new BytesArray(data), XContentType.JSON).build(); + return parseMultiSearchRequest(createRestRequest(sample, null)); + } + + private MultiSearchRequest parseMultiSearchRequest(RestRequest restRequest) throws IOException { MultiSearchRequest request = new MultiSearchRequest(); RestMultiSearchAction.parseMultiLineRequest(restRequest, SearchRequest.DEFAULT_INDICES_OPTIONS, true, @@ -223,6 +228,26 @@ private MultiSearchRequest parseMultiSearchRequest(String sample) throws IOExcep return request; } + private RestRequest createRestRequest(String sample, RestApiVersion restApiVersion) throws IOException { + byte[] data = StreamsUtils.copyToBytesFromClasspath(sample); + return createRestRequest(data, restApiVersion); + } + + private FakeRestRequest createRestRequest(byte[] data, RestApiVersion restApiVersion) { + if (restApiVersion != null) { + final List contentTypeHeader = + Collections.singletonList(compatibleMediaType(XContentType.VND_JSON, RestApiVersion.V_7)); + return new FakeRestRequest.Builder(xContentRegistry()) + .withHeaders(Map.of("Content-Type", contentTypeHeader, "Accept", contentTypeHeader)) + .withContent(new BytesArray(data), null) + .build(); + } else { + return new FakeRestRequest.Builder(xContentRegistry()) + .withContent(new BytesArray(data), XContentType.JSON).build(); + } + } + + @Override protected NamedXContentRegistry xContentRegistry() { return new NamedXContentRegistry(singletonList(new NamedXContentRegistry.Entry(QueryBuilder.class, @@ -271,6 +296,48 @@ public void testWritingExpandWildcards() throws IOException { randomBoolean(), randomBoolean(), randomBoolean()), "none"); } + public void testEmptyFirstLine1() throws Exception { + MultiSearchRequest request = parseMultiSearchRequestFromString( + "\n" + + "\n" + + "{ \"query\": {\"match_all\": {}}}\n" + + "{}\n" + + "{ \"query\": {\"match_all\": {}}}\n" + + "\n" + + "{ \"query\": {\"match_all\": {}}}\n" + + "{}\n" + + "{ \"query\": {\"match_all\": {}}}\n", + RestApiVersion.V_7); + assertThat(request.requests().size(), equalTo(4)); + for (SearchRequest searchRequest : request.requests()) { + assertThat(searchRequest.indices().length, equalTo(0)); + assertThat(searchRequest.source().query(), instanceOf(MatchAllQueryBuilder.class)); + } + assertWarnings("support for empty first line before any action metadata in msearch API is deprecated and will be removed " + + "in the next major version"); + } + + public void testEmptyFirstLine2() throws Exception { + MultiSearchRequest request = parseMultiSearchRequestFromString( + "\n" + + "{}\n" + + "{ \"query\": {\"match_all\": {}}}\n" + + "\n" + + "{ \"query\": {\"match_all\": {}}}\n" + + "{}\n" + + "{ \"query\": {\"match_all\": {}}}\n" + + "\n" + + "{ \"query\": {\"match_all\": {}}}\n", + RestApiVersion.V_7); + assertThat(request.requests().size(), equalTo(4)); + for (SearchRequest searchRequest : request.requests()) { + assertThat(searchRequest.indices().length, equalTo(0)); + assertThat(searchRequest.source().query(), instanceOf(MatchAllQueryBuilder.class)); + } + assertWarnings("support for empty first line before any action metadata in msearch API is deprecated and will be removed " + + "in the next major version"); + } + private void assertExpandWildcardsValue(IndicesOptions options, String expectedValue) throws IOException { SearchRequest request = new SearchRequest(); request.indicesOptions(options); diff --git a/server/src/test/resources/org/elasticsearch/action/search/msearch-empty-first-line1.json b/server/src/test/resources/org/elasticsearch/action/search/msearch-empty-first-line1.json new file mode 100644 index 0000000000000..b417d3adc9b53 --- /dev/null +++ b/server/src/test/resources/org/elasticsearch/action/search/msearch-empty-first-line1.json @@ -0,0 +1,9 @@ + + +{ "query": {"match_all": {}}} +{} +{ "query": {"match_all": {}}} + +{ "query": {"match_all": {}}} +{} +{ "query": {"match_all": {}}} diff --git a/server/src/test/resources/org/elasticsearch/action/search/msearch-empty-first-line2.json b/server/src/test/resources/org/elasticsearch/action/search/msearch-empty-first-line2.json new file mode 100644 index 0000000000000..713bbada69c6a --- /dev/null +++ b/server/src/test/resources/org/elasticsearch/action/search/msearch-empty-first-line2.json @@ -0,0 +1,10 @@ + + +{} +{ "query": {"match_all": {}}} + +{ "query": {"match_all": {}}} +{} +{ "query": {"match_all": {}}} + +{ "query": {"match_all": {}}}