mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-22 12:56:53 +00:00
Fixed NPEs caused by requests without content. (#23497)
REST handlers that require a body will throw an an ElasticsearchParseException "request body required". REST handlers that require a body OR source param will throw an ElasticsearchParseException "request body or source param required". Replaced asserts in BulkRequest parsing code with a more descriptive IllegalArgumentException if the line contains an empty object. Updated bulk REST test to verify an empty action line is rejected properly. Updated BulkRequestTests with randomized testing for an empty action line. Used try-with-resouces for XContentParser in AbstractBulkByQueryRestHandler.
This commit is contained in:
parent
73307a2144
commit
5463294ec4
@ -78,8 +78,8 @@ public class RestNoopBulkAction extends BaseRestHandler {
|
||||
}
|
||||
bulkRequest.timeout(request.paramAsTime("timeout", BulkShardRequest.DEFAULT_TIMEOUT));
|
||||
bulkRequest.setRefreshPolicy(request.param("refresh"));
|
||||
bulkRequest.add(request.content(), defaultIndex, defaultType, defaultRouting, defaultFields, null, defaultPipeline, null, true,
|
||||
request.getXContentType());
|
||||
bulkRequest.add(request.requiredContent(), defaultIndex, defaultType, defaultRouting, defaultFields,
|
||||
null, defaultPipeline, null, true, request.getXContentType());
|
||||
|
||||
// short circuit the call to the transport layer
|
||||
return channel -> {
|
||||
|
@ -41,7 +41,6 @@ import org.elasticsearch.common.lucene.uid.Versions;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.common.xcontent.XContent;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.index.VersionType;
|
||||
@ -300,10 +299,16 @@ public class BulkRequest extends ActionRequest implements CompositeIndicesReques
|
||||
if (token == null) {
|
||||
continue;
|
||||
}
|
||||
assert token == XContentParser.Token.START_OBJECT;
|
||||
if (token != XContentParser.Token.START_OBJECT) {
|
||||
throw new IllegalArgumentException("Malformed action/metadata line [" + line + "], expected "
|
||||
+ XContentParser.Token.START_OBJECT + " but found [" + token + "]");
|
||||
}
|
||||
// Move to FIELD_NAME, that's the action
|
||||
token = parser.nextToken();
|
||||
assert token == XContentParser.Token.FIELD_NAME;
|
||||
if (token != XContentParser.Token.FIELD_NAME) {
|
||||
throw new IllegalArgumentException("Malformed action/metadata line [" + line + "], expected "
|
||||
+ XContentParser.Token.FIELD_NAME + " but found [" + token + "]");
|
||||
}
|
||||
String action = parser.currentName();
|
||||
|
||||
String index = defaultIndex;
|
||||
|
@ -136,6 +136,18 @@ public abstract class RestRequest implements ToXContent.Params {
|
||||
|
||||
public abstract BytesReference content();
|
||||
|
||||
/**
|
||||
* @return content of the request body or throw an exception if the body or content type is missing
|
||||
*/
|
||||
public final BytesReference requiredContent() {
|
||||
if (hasContent() == false) {
|
||||
throw new ElasticsearchParseException("request body is required");
|
||||
} else if (xContentType.get() == null) {
|
||||
throw new IllegalStateException("unknown content type");
|
||||
}
|
||||
return content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the header or {@code null} if not found. This method only retrieves the first header value if multiple values are
|
||||
* sent. Use of {@link #getAllHeaderValues(String)} should be preferred
|
||||
@ -329,12 +341,7 @@ public abstract class RestRequest implements ToXContent.Params {
|
||||
* {@link #contentOrSourceParamParser()} for requests that support specifying the request body in the {@code source} param.
|
||||
*/
|
||||
public final XContentParser contentParser() throws IOException {
|
||||
BytesReference content = content();
|
||||
if (content.length() == 0) {
|
||||
throw new ElasticsearchParseException("Body required");
|
||||
} else if (xContentType.get() == null) {
|
||||
throw new IllegalStateException("unknown content type");
|
||||
}
|
||||
BytesReference content = requiredContent(); // will throw exception if body or content type missing
|
||||
return xContentType.get().xContent().createParser(xContentRegistry, content);
|
||||
}
|
||||
|
||||
@ -364,11 +371,7 @@ public abstract class RestRequest implements ToXContent.Params {
|
||||
*/
|
||||
public final XContentParser contentOrSourceParamParser() throws IOException {
|
||||
Tuple<XContentType, BytesReference> tuple = contentOrSourceParam();
|
||||
BytesReference content = tuple.v2();
|
||||
if (content.length() == 0) {
|
||||
throw new ElasticsearchParseException("Body required");
|
||||
}
|
||||
return tuple.v1().xContent().createParser(xContentRegistry, content);
|
||||
return tuple.v1().xContent().createParser(xContentRegistry, tuple.v2());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -377,10 +380,10 @@ public abstract class RestRequest implements ToXContent.Params {
|
||||
* back to the user when there isn't request content.
|
||||
*/
|
||||
public final void withContentOrSourceParamParserOrNull(CheckedConsumer<XContentParser, IOException> withParser) throws IOException {
|
||||
Tuple<XContentType, BytesReference> tuple = contentOrSourceParam();
|
||||
BytesReference content = tuple.v2();
|
||||
XContentType xContentType = tuple.v1();
|
||||
if (content.length() > 0) {
|
||||
if (hasContentOrSourceParam()) {
|
||||
Tuple<XContentType, BytesReference> tuple = contentOrSourceParam();
|
||||
BytesReference content = tuple.v2();
|
||||
XContentType xContentType = tuple.v1();
|
||||
try (XContentParser parser = xContentType.xContent().createParser(xContentRegistry, content)) {
|
||||
withParser.accept(parser);
|
||||
}
|
||||
@ -390,28 +393,26 @@ public abstract class RestRequest implements ToXContent.Params {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content of the request or the contents of the {@code source} param. Prefer {@link #contentOrSourceParamParser()} or
|
||||
* {@link #withContentOrSourceParamParserOrNull(CheckedConsumer)} if you need a parser.
|
||||
* Get the content of the request or the contents of the {@code source} param or throw an exception if both are missing.
|
||||
* Prefer {@link #contentOrSourceParamParser()} or {@link #withContentOrSourceParamParserOrNull(CheckedConsumer)} if you need a parser.
|
||||
*/
|
||||
public final Tuple<XContentType, BytesReference> contentOrSourceParam() {
|
||||
if (hasContent()) {
|
||||
if (xContentType.get() == null) {
|
||||
throw new IllegalStateException("unknown content type");
|
||||
}
|
||||
return new Tuple<>(xContentType.get(), content());
|
||||
if (hasContentOrSourceParam() == false) {
|
||||
throw new ElasticsearchParseException("request body or source parameter is required");
|
||||
} else if (hasContent()) {
|
||||
return new Tuple<>(xContentType.get(), requiredContent());
|
||||
}
|
||||
|
||||
String source = param("source");
|
||||
String typeParam = param("source_content_type");
|
||||
if (source != null && typeParam != null) {
|
||||
BytesArray bytes = new BytesArray(source);
|
||||
final XContentType xContentType = parseContentType(Collections.singletonList(typeParam));
|
||||
if (xContentType == null) {
|
||||
throw new IllegalStateException("Unknown value for source_content_type [" + typeParam + "]");
|
||||
}
|
||||
return new Tuple<>(xContentType, bytes);
|
||||
if (source == null || typeParam == null) {
|
||||
throw new IllegalStateException("source and source_content_type parameters are required");
|
||||
}
|
||||
return new Tuple<>(XContentType.JSON, BytesArray.EMPTY);
|
||||
BytesArray bytes = new BytesArray(source);
|
||||
final XContentType xContentType = parseContentType(Collections.singletonList(typeParam));
|
||||
if (xContentType == null) {
|
||||
throw new IllegalStateException("Unknown value for source_content_type [" + typeParam + "]");
|
||||
}
|
||||
return new Tuple<>(xContentType, bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,7 +64,7 @@ public class RestPutStoredScriptAction extends BaseRestHandler {
|
||||
lang = null;
|
||||
}
|
||||
|
||||
BytesReference content = request.content();
|
||||
BytesReference content = request.requiredContent();
|
||||
|
||||
if (lang != null) {
|
||||
deprecationLogger.deprecated(
|
||||
|
@ -62,7 +62,7 @@ public class RestPutIndexTemplateAction extends BaseRestHandler {
|
||||
putRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putRequest.masterNodeTimeout()));
|
||||
putRequest.create(request.paramAsBoolean("create", false));
|
||||
putRequest.cause(request.param("cause", ""));
|
||||
putRequest.source(request.content(), request.getXContentType());
|
||||
putRequest.source(request.requiredContent(), request.getXContentType());
|
||||
return channel -> client.admin().indices().putTemplate(putRequest, new AcknowledgedRestListener<>(channel));
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class RestPutMappingAction extends BaseRestHandler {
|
||||
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
|
||||
PutMappingRequest putMappingRequest = putMappingRequest(Strings.splitStringByCommaToArray(request.param("index")));
|
||||
putMappingRequest.type(request.param("type"));
|
||||
putMappingRequest.source(request.content(), request.getXContentType());
|
||||
putMappingRequest.source(request.requiredContent(), request.getXContentType());
|
||||
putMappingRequest.updateAllTypes(request.paramAsBoolean("update_all_types", false));
|
||||
putMappingRequest.timeout(request.paramAsTime("timeout", putMappingRequest.timeout()));
|
||||
putMappingRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putMappingRequest.masterNodeTimeout()));
|
||||
|
@ -59,18 +59,16 @@ public class RestUpdateSettingsAction extends BaseRestHandler {
|
||||
updateSettingsRequest.indicesOptions(IndicesOptions.fromRequest(request, updateSettingsRequest.indicesOptions()));
|
||||
|
||||
Map<String, Object> settings = new HashMap<>();
|
||||
if (request.hasContent()) {
|
||||
try (XContentParser parser = request.contentParser()) {
|
||||
Map<String, Object> bodySettings = parser.map();
|
||||
Object innerBodySettings = bodySettings.get("settings");
|
||||
// clean up in case the body is wrapped with "settings" : { ... }
|
||||
if (innerBodySettings instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> innerBodySettingsMap = (Map<String, Object>) innerBodySettings;
|
||||
settings.putAll(innerBodySettingsMap);
|
||||
} else {
|
||||
settings.putAll(bodySettings);
|
||||
}
|
||||
try (XContentParser parser = request.contentParser()) {
|
||||
Map<String, Object> bodySettings = parser.map();
|
||||
Object innerBodySettings = bodySettings.get("settings");
|
||||
// clean up in case the body is wrapped with "settings" : { ... }
|
||||
if (innerBodySettings instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> innerBodySettingsMap = (Map<String, Object>) innerBodySettings;
|
||||
settings.putAll(innerBodySettingsMap);
|
||||
} else {
|
||||
settings.putAll(bodySettings);
|
||||
}
|
||||
}
|
||||
updateSettingsRequest.settings(settings);
|
||||
|
@ -91,7 +91,7 @@ public class RestBulkAction extends BaseRestHandler {
|
||||
}
|
||||
bulkRequest.timeout(request.paramAsTime("timeout", BulkShardRequest.DEFAULT_TIMEOUT));
|
||||
bulkRequest.setRefreshPolicy(request.param("refresh"));
|
||||
bulkRequest.add(request.content(), defaultIndex, defaultType, defaultRouting, defaultFields,
|
||||
bulkRequest.add(request.requiredContent(), defaultIndex, defaultType, defaultRouting, defaultFields,
|
||||
defaultFetchSourceContext, defaultPipeline, null, allowExplicitIndex, request.getXContentType());
|
||||
|
||||
return channel -> client.bulk(bulkRequest, new RestStatusToXContentListener<>(channel));
|
||||
|
@ -74,7 +74,7 @@ public class RestIndexAction extends BaseRestHandler {
|
||||
indexRequest.routing(request.param("routing"));
|
||||
indexRequest.parent(request.param("parent"));
|
||||
indexRequest.setPipeline(request.param("pipeline"));
|
||||
indexRequest.source(request.content(), request.getXContentType());
|
||||
indexRequest.source(request.requiredContent(), request.getXContentType());
|
||||
indexRequest.timeout(request.paramAsTime("timeout", IndexRequest.DEFAULT_TIMEOUT));
|
||||
indexRequest.setRefreshPolicy(request.param("refresh"));
|
||||
indexRequest.version(RestActions.parseVersion(request));
|
||||
|
@ -177,6 +177,31 @@ public class BulkRequestTests extends ESTestCase {
|
||||
assertThat(bulkRequest.numberOfActions(), equalTo(9));
|
||||
}
|
||||
|
||||
public void testBulkEmptyObject() throws Exception {
|
||||
String bulkIndexAction = "{ \"index\":{\"_index\":\"test\",\"_type\":\"type1\",\"_id\":\"1\"} }\r\n";
|
||||
String bulkIndexSource = "{ \"field1\" : \"value1\" }\r\n";
|
||||
String emptyObject = "{}\r\n";
|
||||
StringBuilder bulk = new StringBuilder();
|
||||
int emptyLine;
|
||||
if (randomBoolean()) {
|
||||
bulk.append(emptyObject);
|
||||
emptyLine = 1;
|
||||
} else {
|
||||
int actions = randomIntBetween(1, 10);
|
||||
int emptyAction = randomIntBetween(1, actions);
|
||||
emptyLine = emptyAction * 2 - 1;
|
||||
for (int i = 1; i <= actions; i++) {
|
||||
bulk.append(i == emptyAction ? emptyObject : bulkIndexAction);
|
||||
bulk.append(randomBoolean() ? emptyObject : bulkIndexSource);
|
||||
}
|
||||
}
|
||||
String bulkAction = bulk.toString();
|
||||
BulkRequest bulkRequest = new BulkRequest();
|
||||
IllegalArgumentException exc = expectThrows(IllegalArgumentException.class,
|
||||
() -> bulkRequest.add(bulkAction.getBytes(StandardCharsets.UTF_8), 0, bulkAction.length(), null, null, XContentType.JSON));
|
||||
assertThat(exc.getMessage(), containsString("Malformed action/metadata line [" + emptyLine + "], expected FIELD_NAME but found [END_OBJECT]"));
|
||||
}
|
||||
|
||||
// issue 7361
|
||||
public void testBulkRequestWithRefresh() throws Exception {
|
||||
BulkRequest bulkRequest = new BulkRequest();
|
||||
|
@ -43,11 +43,14 @@ public class RestRequestTests extends ESTestCase {
|
||||
public void testContentParser() throws IOException {
|
||||
Exception e = expectThrows(ElasticsearchParseException.class, () ->
|
||||
new ContentRestRequest("", emptyMap()).contentParser());
|
||||
assertEquals("Body required", e.getMessage());
|
||||
assertEquals("request body is required", e.getMessage());
|
||||
e = expectThrows(ElasticsearchParseException.class, () ->
|
||||
new ContentRestRequest("", singletonMap("source", "{}")).contentParser());
|
||||
assertEquals("Body required", e.getMessage());
|
||||
assertEquals("request body is required", e.getMessage());
|
||||
assertEquals(emptyMap(), new ContentRestRequest("{}", emptyMap()).contentParser().map());
|
||||
e = expectThrows(ElasticsearchParseException.class, () ->
|
||||
new ContentRestRequest("", emptyMap(), emptyMap()).contentParser());
|
||||
assertEquals("request body is required", e.getMessage());
|
||||
}
|
||||
|
||||
public void testApplyContentParser() throws IOException {
|
||||
@ -59,7 +62,9 @@ public class RestRequestTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testContentOrSourceParam() throws IOException {
|
||||
assertEquals(BytesArray.EMPTY, new ContentRestRequest("", emptyMap()).contentOrSourceParam().v2());
|
||||
Exception e = expectThrows(ElasticsearchParseException.class, () ->
|
||||
new ContentRestRequest("", emptyMap()).contentOrSourceParam());
|
||||
assertEquals("request body or source parameter is required", e.getMessage());
|
||||
assertEquals(new BytesArray("stuff"), new ContentRestRequest("stuff", emptyMap()).contentOrSourceParam().v2());
|
||||
assertEquals(new BytesArray("stuff"),
|
||||
new ContentRestRequest("stuff", MapBuilder.<String, String>newMapBuilder()
|
||||
@ -68,6 +73,10 @@ public class RestRequestTests extends ESTestCase {
|
||||
new ContentRestRequest("", MapBuilder.<String, String>newMapBuilder()
|
||||
.put("source", "{\"foo\": \"stuff\"}").put("source_content_type", "application/json").immutableMap())
|
||||
.contentOrSourceParam().v2());
|
||||
e = expectThrows(IllegalStateException.class, () ->
|
||||
new ContentRestRequest("", MapBuilder.<String, String>newMapBuilder()
|
||||
.put("source", "stuff2").immutableMap()).contentOrSourceParam());
|
||||
assertEquals("source and source_content_type parameters are required", e.getMessage());
|
||||
}
|
||||
|
||||
public void testHasContentOrSourceParam() throws IOException {
|
||||
@ -80,7 +89,7 @@ public class RestRequestTests extends ESTestCase {
|
||||
public void testContentOrSourceParamParser() throws IOException {
|
||||
Exception e = expectThrows(ElasticsearchParseException.class, () ->
|
||||
new ContentRestRequest("", emptyMap()).contentOrSourceParamParser());
|
||||
assertEquals("Body required", e.getMessage());
|
||||
assertEquals("request body or source parameter is required", e.getMessage());
|
||||
assertEquals(emptyMap(), new ContentRestRequest("{}", emptyMap()).contentOrSourceParamParser().map());
|
||||
assertEquals(emptyMap(), new ContentRestRequest("{}", singletonMap("source", "stuff2")).contentOrSourceParamParser().map());
|
||||
assertEquals(emptyMap(), new ContentRestRequest("", MapBuilder.<String, String>newMapBuilder()
|
||||
@ -138,6 +147,24 @@ public class RestRequestTests extends ESTestCase {
|
||||
assertEquals("only one Content-Type header should be provided", e.getMessage());
|
||||
}
|
||||
|
||||
public void testRequiredContent() {
|
||||
Exception e = expectThrows(ElasticsearchParseException.class, () ->
|
||||
new ContentRestRequest("", emptyMap()).requiredContent());
|
||||
assertEquals("request body is required", e.getMessage());
|
||||
assertEquals(new BytesArray("stuff"), new ContentRestRequest("stuff", emptyMap()).requiredContent());
|
||||
assertEquals(new BytesArray("stuff"),
|
||||
new ContentRestRequest("stuff", MapBuilder.<String, String>newMapBuilder()
|
||||
.put("source", "stuff2").put("source_content_type", "application/json").immutableMap()).requiredContent());
|
||||
e = expectThrows(ElasticsearchParseException.class, () ->
|
||||
new ContentRestRequest("", MapBuilder.<String, String>newMapBuilder()
|
||||
.put("source", "{\"foo\": \"stuff\"}").put("source_content_type", "application/json").immutableMap())
|
||||
.requiredContent());
|
||||
assertEquals("request body is required", e.getMessage());
|
||||
e = expectThrows(IllegalStateException.class, () ->
|
||||
new ContentRestRequest("test", null, Collections.emptyMap()).requiredContent());
|
||||
assertEquals("unknown content type", e.getMessage());
|
||||
}
|
||||
|
||||
private static final class ContentRestRequest extends RestRequest {
|
||||
private final BytesArray content;
|
||||
|
||||
|
@ -203,3 +203,16 @@ teardown:
|
||||
catch: missing
|
||||
ingest.get_pipeline:
|
||||
id: "my_pipeline"
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body or source parameter is required/
|
||||
raw:
|
||||
method: PUT
|
||||
path: _ingest/pipeline/my_pipeline
|
||||
|
@ -605,3 +605,16 @@ teardown:
|
||||
- length: { docs.0.processor_results.1: 2 }
|
||||
- match: { docs.0.processor_results.1.tag: "rename-1" }
|
||||
- match: { docs.0.processor_results.1.doc._source.new_status: 200 }
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body or source parameter is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: _ingest/pipeline/my_pipeline/_simulate
|
||||
|
@ -62,10 +62,6 @@ public class RestMultiSearchTemplateAction extends BaseRestHandler {
|
||||
|
||||
@Override
|
||||
public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
if (request.hasContentOrSourceParam() == false) {
|
||||
throw new ElasticsearchException("request body is required");
|
||||
}
|
||||
|
||||
MultiSearchTemplateRequest multiRequest = parseRequest(request, allowExplicitIndex);
|
||||
return channel -> client.execute(MultiSearchTemplateAction.INSTANCE, multiRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class RestPutSearchTemplateAction extends BaseRestHandler {
|
||||
@Override
|
||||
public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
String id = request.param("id");
|
||||
BytesReference content = request.content();
|
||||
BytesReference content = request.requiredContent();
|
||||
|
||||
PutStoredScriptRequest put = new PutStoredScriptRequest(id, Script.DEFAULT_TEMPLATE_LANG, TemplateScript.CONTEXT.name,
|
||||
content, request.getXContentType());
|
||||
|
@ -92,10 +92,6 @@ public class RestSearchTemplateAction extends BaseRestHandler {
|
||||
|
||||
@Override
|
||||
public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
if (request.hasContentOrSourceParam() == false) {
|
||||
throw new ElasticsearchException("request body is required");
|
||||
}
|
||||
|
||||
// Creates the search request with all required params
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
RestSearchAction.parseSearchRequest(searchRequest, request, null);
|
||||
|
@ -58,3 +58,16 @@
|
||||
put_template:
|
||||
id: "1"
|
||||
body: { "template": { "query": { "match{{}}_all": {}}, "size": "{{my_size}}" } }
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: _search/template/1
|
||||
|
@ -122,3 +122,16 @@
|
||||
- match: { hits.total: 1 }
|
||||
- length: { hits.hits: 1 }
|
||||
- length: { profile: 1 }
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body or source parameter is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: _search/template
|
||||
|
@ -157,3 +157,15 @@ setup:
|
||||
- match: { responses.1.hits.total: 1 }
|
||||
- match: { responses.2.hits.total: 1 }
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body or source parameter is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: _msearch/template
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
package org.elasticsearch.index.reindex;
|
||||
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.elasticsearch.action.GenericAction;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
@ -55,18 +54,9 @@ public abstract class AbstractBulkByQueryRestHandler<
|
||||
int scrollSize = searchRequest.source().size();
|
||||
searchRequest.source().size(SIZE_ALL_MATCHES);
|
||||
|
||||
restRequest.withContentOrSourceParamParserOrNull(parser -> {
|
||||
XContentParser searchRequestParser = extractRequestSpecificFieldsAndReturnSearchCompatibleParser(parser, bodyConsumers);
|
||||
/* searchRequestParser might be parser or it might be a new parser built from parser's contents. If it is parser then
|
||||
* withContentOrSourceParamParserOrNull will close it for us but if it isn't then we should close it. Technically close on
|
||||
* the generated parser probably is a noop but we should do the accounting just in case. It doesn't hurt to close twice but it
|
||||
* really hurts not to close if by some miracle we have to. */
|
||||
try {
|
||||
RestSearchAction.parseSearchRequest(searchRequest, restRequest, searchRequestParser);
|
||||
} finally {
|
||||
IOUtils.close(searchRequestParser);
|
||||
}
|
||||
});
|
||||
try (XContentParser parser = extractRequestSpecificFields(restRequest, bodyConsumers)) {
|
||||
RestSearchAction.parseSearchRequest(searchRequest, restRequest, parser);
|
||||
}
|
||||
|
||||
internal.setSize(searchRequest.source().size());
|
||||
searchRequest.source().size(restRequest.paramAsInt("scroll_size", scrollSize));
|
||||
@ -89,12 +79,13 @@ public abstract class AbstractBulkByQueryRestHandler<
|
||||
* should get better when SearchRequest has full ObjectParser support
|
||||
* then we can delegate and stuff.
|
||||
*/
|
||||
private XContentParser extractRequestSpecificFieldsAndReturnSearchCompatibleParser(XContentParser parser,
|
||||
Map<String, Consumer<Object>> bodyConsumers) throws IOException {
|
||||
if (parser == null) {
|
||||
return parser;
|
||||
private XContentParser extractRequestSpecificFields(RestRequest restRequest,
|
||||
Map<String, Consumer<Object>> bodyConsumers) throws IOException {
|
||||
if (restRequest.hasContentOrSourceParam() == false) {
|
||||
return null; // body is optional
|
||||
}
|
||||
try {
|
||||
try (XContentParser parser = restRequest.contentOrSourceParamParser();
|
||||
XContentBuilder builder = XContentFactory.contentBuilder(parser.contentType())) {
|
||||
Map<String, Object> body = parser.map();
|
||||
|
||||
for (Map.Entry<String, Consumer<Object>> consumer : bodyConsumers.entrySet()) {
|
||||
@ -103,12 +94,7 @@ public abstract class AbstractBulkByQueryRestHandler<
|
||||
consumer.getValue().accept(value);
|
||||
}
|
||||
}
|
||||
|
||||
try (XContentBuilder builder = XContentFactory.contentBuilder(parser.contentType())) {
|
||||
return parser.contentType().xContent().createParser(parser.getXContentRegistry(), builder.map(body).bytes());
|
||||
}
|
||||
} finally {
|
||||
parser.close();
|
||||
return parser.contentType().xContent().createParser(parser.getXContentRegistry(), builder.map(body).bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,9 +52,6 @@ public class RestDeleteByQueryAction extends AbstractBulkByQueryRestHandler<Dele
|
||||
|
||||
@Override
|
||||
protected DeleteByQueryRequest buildRequest(RestRequest request) throws IOException {
|
||||
if (false == request.hasContent()) {
|
||||
throw new ElasticsearchException("_delete_by_query requires a request body");
|
||||
}
|
||||
/*
|
||||
* Passing the search request through DeleteByQueryRequest first allows
|
||||
* it to set its own defaults which differ from SearchRequest's
|
||||
|
@ -299,3 +299,16 @@
|
||||
index: source
|
||||
metric: search
|
||||
- match: {indices.source.total.search.open_contexts: 0}
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: _reindex
|
||||
|
@ -58,3 +58,33 @@
|
||||
index: test
|
||||
|
||||
- match: { count: 2 }
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: _bulk
|
||||
|
||||
---
|
||||
"empty action":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: confusing exception messaged caused by empty object fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /Malformed action\/metadata line \[3\], expected FIELD_NAME but found \[END_OBJECT\]/
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
bulk:
|
||||
body: |
|
||||
{"index": {"_index": "test_index", "_type": "test_type", "_id": "test_id"}}
|
||||
{"f1": "v1", "f2": 42}
|
||||
{}
|
||||
|
@ -0,0 +1,12 @@
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: _scripts/lang
|
@ -75,3 +75,15 @@
|
||||
|
||||
- match: {defaults.node.attr.testattr: "test"}
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body is required/
|
||||
raw:
|
||||
method: PUT
|
||||
path: _settings
|
||||
|
@ -32,3 +32,16 @@
|
||||
type: type
|
||||
id: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
body: { foo: bar }
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: idx/type/123
|
||||
|
@ -67,3 +67,16 @@
|
||||
properties:
|
||||
"":
|
||||
type: keyword
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: test_index/test_type/_mapping
|
||||
|
@ -210,3 +210,16 @@
|
||||
catch: missing
|
||||
indices.get_template:
|
||||
name: "my_template"
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body is required/
|
||||
raw:
|
||||
method: PUT
|
||||
path: _template/my_template
|
||||
|
@ -62,3 +62,15 @@ setup:
|
||||
- match: { responses.3.error.root_cause.0.index: index_3 }
|
||||
- match: { responses.4.hits.total: 4 }
|
||||
|
||||
---
|
||||
"missing body":
|
||||
|
||||
- skip:
|
||||
version: " - 5.99.99"
|
||||
reason: NPE caused by missing body fixed in 6.0.0
|
||||
|
||||
- do:
|
||||
catch: /request body or source parameter is required/
|
||||
raw:
|
||||
method: POST
|
||||
path: _msearch
|
||||
|
Loading…
x
Reference in New Issue
Block a user