diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 66a81038f0d..aa7374c2993 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -107,6 +107,7 @@ ones that the user is authorized to access in case field level security is enabl Fixed prerelease version of elasticsearch in the `deb` package to sort before GA versions ({pull}29000[#29000]) +Respect accept header on requests with no handler ({pull}30383[#30383]) Rollup:: * Validate timezone in range queries to ensure they match the selected job when searching ({pull}30338[#30338]) diff --git a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/NoHandlerIT.java b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/NoHandlerIT.java new file mode 100644 index 00000000000..0a2d7ed9b06 --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/NoHandlerIT.java @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.http; + +import org.apache.http.message.BasicHeader; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.Response; +import org.elasticsearch.client.ResponseException; + +import java.io.IOException; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +public class NoHandlerIT extends HttpSmokeTestCase { + + public void testNoHandlerRespectsAcceptHeader() throws IOException { + runTestNoHandlerRespectsAcceptHeader( + "application/json", + "application/json; charset=UTF-8", + "\"error\":\"no handler found for uri [/foo/bar/baz/qux/quux] and method [GET]\""); + runTestNoHandlerRespectsAcceptHeader( + "application/yaml", + "application/yaml", + "error: \"no handler found for uri [/foo/bar/baz/qux/quux] and method [GET]\""); + } + + private void runTestNoHandlerRespectsAcceptHeader( + final String accept, final String contentType, final String expect) throws IOException { + final ResponseException e = + expectThrows( + ResponseException.class, + () -> getRestClient().performRequest("GET", "/foo/bar/baz/qux/quux", new BasicHeader("Accept", accept))); + + final Response response = e.getResponse(); + assertThat(response.getHeader("Content-Type"), equalTo(contentType)); + assertThat(EntityUtils.toString(e.getResponse().getEntity()), containsString(expect)); + assertThat(response.getStatusLine().getStatusCode(), is(400)); + } + +} diff --git a/server/src/main/java/org/elasticsearch/rest/RestController.java b/server/src/main/java/org/elasticsearch/rest/RestController.java index 111663497d7..aae63f041fa 100644 --- a/server/src/main/java/org/elasticsearch/rest/RestController.java +++ b/server/src/main/java/org/elasticsearch/rest/RestController.java @@ -401,9 +401,15 @@ public class RestController extends AbstractComponent implements HttpServerTrans * Handle a requests with no candidate handlers (return a 400 Bad Request * error). */ - private void handleBadRequest(RestRequest request, RestChannel channel) { - channel.sendResponse(new BytesRestResponse(BAD_REQUEST, - "No handler found for uri [" + request.uri() + "] and method [" + request.method() + "]")); + private void handleBadRequest(RestRequest request, RestChannel channel) throws IOException { + try (XContentBuilder builder = channel.newErrorBuilder()) { + builder.startObject(); + { + builder.field("error", "no handler found for uri [" + request.uri() + "] and method [" + request.method() + "]"); + } + builder.endObject(); + channel.sendResponse(new BytesRestResponse(BAD_REQUEST, builder)); + } } /** diff --git a/x-pack/qa/ml-disabled/src/test/java/org/elasticsearch/xpack/ml/integration/MlPluginDisabledIT.java b/x-pack/qa/ml-disabled/src/test/java/org/elasticsearch/xpack/ml/integration/MlPluginDisabledIT.java index e7a0a6028d4..3bb9566e5bf 100644 --- a/x-pack/qa/ml-disabled/src/test/java/org/elasticsearch/xpack/ml/integration/MlPluginDisabledIT.java +++ b/x-pack/qa/ml-disabled/src/test/java/org/elasticsearch/xpack/ml/integration/MlPluginDisabledIT.java @@ -51,6 +51,6 @@ public class MlPluginDisabledIT extends ESRestTestCase { ResponseException exception = expectThrows(ResponseException.class, () -> client().performRequest("put", MachineLearning.BASE_PATH + "anomaly_detectors/foo", Collections.emptyMap(), new StringEntity(Strings.toString(xContentBuilder), ContentType.APPLICATION_JSON))); - assertThat(exception.getMessage(), containsString("No handler found for uri [/_xpack/ml/anomaly_detectors/foo] and method [PUT]")); + assertThat(exception.getMessage(), containsString("no handler found for uri [/_xpack/ml/anomaly_detectors/foo] and method [PUT]")); } }