diff options
Diffstat (limited to 'core/src/test/java/org/elasticsearch/rest')
5 files changed, 155 insertions, 66 deletions
diff --git a/core/src/test/java/org/elasticsearch/rest/BytesRestResponseTests.java b/core/src/test/java/org/elasticsearch/rest/BytesRestResponseTests.java index 4e8d9b8600..431bc152bd 100644 --- a/core/src/test/java/org/elasticsearch/rest/BytesRestResponseTests.java +++ b/core/src/test/java/org/elasticsearch/rest/BytesRestResponseTests.java @@ -165,7 +165,7 @@ public class BytesRestResponseTests extends ESTestCase { public void testResponseWhenPathContainsEncodingError() throws IOException { final String path = "%a"; - final RestRequest request = new RestRequest(NamedXContentRegistry.EMPTY, Collections.emptyMap(), path) { + final RestRequest request = new RestRequest(NamedXContentRegistry.EMPTY, Collections.emptyMap(), path, Collections.emptyMap()) { @Override public Method method() { return null; @@ -185,16 +185,6 @@ public class BytesRestResponseTests extends ESTestCase { public BytesReference content() { return null; } - - @Override - public String header(String name) { - return null; - } - - @Override - public Iterable<Map.Entry<String, String>> headers() { - return null; - } }; final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> RestUtils.decodeComponent(request.rawPath())); final RestChannel channel = new DetailedExceptionRestChannel(request); diff --git a/core/src/test/java/org/elasticsearch/rest/RestControllerTests.java b/core/src/test/java/org/elasticsearch/rest/RestControllerTests.java index e706455490..79c6f6561e 100644 --- a/core/src/test/java/org/elasticsearch/rest/RestControllerTests.java +++ b/core/src/test/java/org/elasticsearch/rest/RestControllerTests.java @@ -23,6 +23,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -41,10 +42,11 @@ import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.http.HttpInfo; import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.http.HttpStats; -import org.elasticsearch.indices.breaker.CircuitBreakerService; +import org.elasticsearch.http.HttpTransportSettings; import org.elasticsearch.indices.breaker.HierarchyCircuitBreakerService; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.rest.FakeRestRequest; @@ -91,19 +93,17 @@ public class RestControllerTests extends ESTestCase { final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); Set<String> headers = new HashSet<>(Arrays.asList("header.1", "header.2")); final RestController restController = new RestController(Settings.EMPTY, headers, null, null, circuitBreakerService); - restController.registerHandler(RestRequest.Method.GET, "/", - (RestRequest request, RestChannel channel, NodeClient client) -> { + threadContext.putHeader("header.3", "true"); + Map<String, List<String>> restHeaders = new HashMap<>(); + restHeaders.put("header.1", Collections.singletonList("true")); + restHeaders.put("header.2", Collections.singletonList("true")); + restHeaders.put("header.3", Collections.singletonList("false")); + restController.dispatchRequest(new FakeRestRequest.Builder(xContentRegistry()).withHeaders(restHeaders).build(), null, null, + threadContext, (RestRequest request, RestChannel channel, NodeClient client) -> { assertEquals("true", threadContext.getHeader("header.1")); assertEquals("true", threadContext.getHeader("header.2")); assertNull(threadContext.getHeader("header.3")); }); - threadContext.putHeader("header.3", "true"); - Map<String, String> restHeaders = new HashMap<>(); - restHeaders.put("header.1", "true"); - restHeaders.put("header.2", "true"); - restHeaders.put("header.3", "false"); - restController.dispatchRequest(new FakeRestRequest.Builder(xContentRegistry()).withHeaders(restHeaders).build(), null, null, - threadContext); assertNull(threadContext.getHeader("header.1")); assertNull(threadContext.getHeader("header.2")); assertEquals("true", threadContext.getHeader("header.3")); @@ -172,9 +172,8 @@ public class RestControllerTests extends ESTestCase { }; final RestController restController = new RestController(Settings.EMPTY, Collections.emptySet(), wrapper, null, circuitBreakerService); - restController.registerHandler(RestRequest.Method.GET, "/", handler); final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - restController.dispatchRequest(new FakeRestRequest.Builder(xContentRegistry()).build(), null, null, threadContext); + restController.dispatchRequest(new FakeRestRequest.Builder(xContentRegistry()).build(), null, null, threadContext, handler); assertTrue(wrapperCalled.get()); assertFalse(handlerCalled.get()); } @@ -203,7 +202,7 @@ public class RestControllerTests extends ESTestCase { public void testDispatchRequestAddsAndFreesBytesOnSuccess() { int contentLength = BREAKER_LIMIT.bytesAsInt(); String content = randomAsciiOfLength(contentLength); - TestRestRequest request = new TestRestRequest("/", content); + TestRestRequest request = new TestRestRequest("/", content, XContentType.JSON); AssertingChannel channel = new AssertingChannel(request, true, RestStatus.OK); restController.dispatchRequest(request, channel, new ThreadContext(Settings.EMPTY)); @@ -215,7 +214,7 @@ public class RestControllerTests extends ESTestCase { public void testDispatchRequestAddsAndFreesBytesOnError() { int contentLength = BREAKER_LIMIT.bytesAsInt(); String content = randomAsciiOfLength(contentLength); - TestRestRequest request = new TestRestRequest("/error", content); + TestRestRequest request = new TestRestRequest("/error", content, XContentType.JSON); AssertingChannel channel = new AssertingChannel(request, true, RestStatus.BAD_REQUEST); restController.dispatchRequest(request, channel, new ThreadContext(Settings.EMPTY)); @@ -228,7 +227,7 @@ public class RestControllerTests extends ESTestCase { int contentLength = BREAKER_LIMIT.bytesAsInt(); String content = randomAsciiOfLength(contentLength); // we will produce an error in the rest handler and one more when sending the error response - TestRestRequest request = new TestRestRequest("/error", content); + TestRestRequest request = new TestRestRequest("/error", content, XContentType.JSON); ExceptionThrowingChannel channel = new ExceptionThrowingChannel(request, true); restController.dispatchRequest(request, channel, new ThreadContext(Settings.EMPTY)); @@ -240,7 +239,7 @@ public class RestControllerTests extends ESTestCase { public void testDispatchRequestLimitsBytes() { int contentLength = BREAKER_LIMIT.bytesAsInt() + 1; String content = randomAsciiOfLength(contentLength); - TestRestRequest request = new TestRestRequest("/", content); + TestRestRequest request = new TestRestRequest("/", content, XContentType.JSON); AssertingChannel channel = new AssertingChannel(request, true, RestStatus.SERVICE_UNAVAILABLE); restController.dispatchRequest(request, channel, new ThreadContext(Settings.EMPTY)); @@ -249,6 +248,67 @@ public class RestControllerTests extends ESTestCase { assertEquals(0, inFlightRequestsBreaker.getUsed()); } + public void testDispatchRequiresContentTypeForRequestsWithContent() { + String content = randomAsciiOfLengthBetween(1, BREAKER_LIMIT.bytesAsInt()); + TestRestRequest request = new TestRestRequest("/", content, null); + AssertingChannel channel = new AssertingChannel(request, true, RestStatus.NOT_ACCEPTABLE); + restController = new RestController( + Settings.builder().put(HttpTransportSettings.SETTING_HTTP_CONTENT_TYPE_REQUIRED.getKey(), true).build(), + Collections.emptySet(), null, null, circuitBreakerService); + restController.registerHandler(RestRequest.Method.GET, "/", + (r, c, client) -> c.sendResponse( + new BytesRestResponse(RestStatus.OK, BytesRestResponse.TEXT_CONTENT_TYPE, BytesArray.EMPTY))); + + assertFalse(channel.sendResponseCalled.get()); + restController.dispatchRequest(request, channel, new ThreadContext(Settings.EMPTY)); + assertTrue(channel.sendResponseCalled.get()); + } + + public void testDispatchDoesNotRequireContentTypeForRequestsWithoutContent() { + FakeRestRequest fakeRestRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY).build(); + AssertingChannel channel = new AssertingChannel(fakeRestRequest, true, RestStatus.OK); + + assertFalse(channel.sendResponseCalled.get()); + restController.dispatchRequest(fakeRestRequest, channel, new ThreadContext(Settings.EMPTY)); + assertTrue(channel.sendResponseCalled.get()); + } + + public void testDispatchWorksWithPlainText() { + String content = randomAsciiOfLengthBetween(1, BREAKER_LIMIT.bytesAsInt()); + FakeRestRequest fakeRestRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY) + .withContent(new BytesArray(content), null).withPath("/foo") + .withHeaders(Collections.singletonMap("Content-Type", Collections.singletonList("text/plain"))).build(); + AssertingChannel channel = new AssertingChannel(fakeRestRequest, true, RestStatus.OK); + restController.registerHandler(RestRequest.Method.GET, "/foo", new RestHandler() { + @Override + public void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception { + channel.sendResponse(new BytesRestResponse(RestStatus.OK, BytesRestResponse.TEXT_CONTENT_TYPE, BytesArray.EMPTY)); + } + + @Override + public boolean supportsPlainText() { + return true; + } + }); + + assertFalse(channel.sendResponseCalled.get()); + restController.dispatchRequest(fakeRestRequest, channel, new ThreadContext(Settings.EMPTY)); + assertTrue(channel.sendResponseCalled.get()); + assertWarnings("Plain text request bodies are deprecated. Use request parameters or body in a supported format."); + } + + public void testDispatchWorksWithAutoDetection() { + FakeRestRequest fakeRestRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY) + .withContent(new BytesArray("{}"), null).withPath("/") + .withHeaders(Collections.singletonMap("Content-Type", Collections.singletonList("application/x-www-form-urlencoded"))).build(); + AssertingChannel channel = new AssertingChannel(fakeRestRequest, true, RestStatus.OK); + + assertFalse(channel.sendResponseCalled.get()); + restController.dispatchRequest(fakeRestRequest, channel, new ThreadContext(Settings.EMPTY)); + assertTrue(channel.sendResponseCalled.get()); + assertWarnings("Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header."); + } + private static final class TestHttpServerTransport extends AbstractLifecycleComponent implements HttpServerTransport { @@ -287,6 +347,7 @@ public class RestControllerTests extends ESTestCase { private static final class AssertingChannel extends AbstractRestChannel { private final RestStatus expectedStatus; + private final AtomicBoolean sendResponseCalled = new AtomicBoolean(false); protected AssertingChannel(RestRequest request, boolean detailedErrorsEnabled, RestStatus expectedStatus) { super(request, detailedErrorsEnabled); @@ -296,6 +357,7 @@ public class RestControllerTests extends ESTestCase { @Override public void sendResponse(RestResponse response) { assertEquals(expectedStatus, response.status()); + sendResponseCalled.set(true); } } @@ -315,8 +377,9 @@ public class RestControllerTests extends ESTestCase { private final BytesReference content; - private TestRestRequest(String path, String content) { - super(NamedXContentRegistry.EMPTY, Collections.emptyMap(), path); + private TestRestRequest(String path, String content, XContentType xContentType) { + super(NamedXContentRegistry.EMPTY, Collections.emptyMap(), path, xContentType == null ? + Collections.emptyMap() : Collections.singletonMap("Content-Type", Collections.singletonList(xContentType.mediaType()))); this.content = new BytesArray(content); } @@ -340,15 +403,5 @@ public class RestControllerTests extends ESTestCase { return content; } - @Override - public String header(String name) { - return null; - } - - @Override - public Iterable<Map.Entry<String, String>> headers() { - return null; - } - } } diff --git a/core/src/test/java/org/elasticsearch/rest/RestRequestTests.java b/core/src/test/java/org/elasticsearch/rest/RestRequestTests.java index 7f0184e20c..bddcd39160 100644 --- a/core/src/test/java/org/elasticsearch/rest/RestRequestTests.java +++ b/core/src/test/java/org/elasticsearch/rest/RestRequestTests.java @@ -24,11 +24,15 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.ESTestCase; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicReference; import static java.util.Collections.emptyMap; @@ -54,10 +58,13 @@ public class RestRequestTests extends ESTestCase { } public void testContentOrSourceParam() throws IOException { - assertEquals(BytesArray.EMPTY, new ContentRestRequest("", emptyMap()).contentOrSourceParam()); - assertEquals(new BytesArray("stuff"), new ContentRestRequest("stuff", emptyMap()).contentOrSourceParam()); - assertEquals(new BytesArray("stuff"), new ContentRestRequest("stuff", singletonMap("source", "stuff2")).contentOrSourceParam()); - assertEquals(new BytesArray("stuff"), new ContentRestRequest("", singletonMap("source", "stuff")).contentOrSourceParam()); + assertEquals(BytesArray.EMPTY, new ContentRestRequest("", emptyMap()).contentOrSourceParam().v2()); + assertEquals(new BytesArray("stuff"), new ContentRestRequest("stuff", emptyMap()).contentOrSourceParam().v2()); + assertEquals(new BytesArray("stuff"), + new ContentRestRequest("stuff", singletonMap("source", "stuff2")).contentOrSourceParam().v2()); + assertEquals(new BytesArray("{\"foo\": \"stuff\"}"), + new ContentRestRequest("", singletonMap("source", "{\"foo\": \"stuff\"}")).contentOrSourceParam().v2()); + assertWarnings("Deprecated use of the [source] parameter without the [source_content_type] parameter."); } public void testHasContentOrSourceParam() throws IOException { @@ -74,6 +81,7 @@ public class RestRequestTests extends ESTestCase { assertEquals(emptyMap(), new ContentRestRequest("{}", emptyMap()).contentOrSourceParamParser().map()); assertEquals(emptyMap(), new ContentRestRequest("{}", singletonMap("source", "stuff2")).contentOrSourceParamParser().map()); assertEquals(emptyMap(), new ContentRestRequest("", singletonMap("source", "{}")).contentOrSourceParamParser().map()); + assertWarnings("Deprecated use of the [source] parameter without the [source_content_type] parameter."); } public void testWithContentOrSourceParamParserOrNull() throws IOException { @@ -83,12 +91,58 @@ public class RestRequestTests extends ESTestCase { assertEquals(emptyMap(), parser.map())); new ContentRestRequest("", singletonMap("source", "{}")).withContentOrSourceParamParserOrNull(parser -> assertEquals(emptyMap(), parser.map())); + assertWarnings("Deprecated use of the [source] parameter without the [source_content_type] parameter."); + } + + public void testContentTypeParsing() { + for (XContentType xContentType : XContentType.values()) { + Map<String, List<String>> map = new HashMap<>(); + map.put("Content-Type", Collections.singletonList(xContentType.mediaType())); + ContentRestRequest restRequest = new ContentRestRequest("", Collections.emptyMap(), map); + assertEquals(xContentType, restRequest.getXContentType()); + + map = new HashMap<>(); + map.put("Content-Type", Collections.singletonList(xContentType.mediaTypeWithoutParameters())); + restRequest = new ContentRestRequest("", Collections.emptyMap(), map); + assertEquals(xContentType, restRequest.getXContentType()); + } + } + + public void testPlainTextSupport() { + ContentRestRequest restRequest = new ContentRestRequest(randomAsciiOfLengthBetween(1, 30), Collections.emptyMap(), + Collections.singletonMap("Content-Type", + Collections.singletonList(randomFrom("text/plain", "text/plain; charset=utf-8", "text/plain;charset=utf-8")))); + assertNull(restRequest.getXContentType()); + } + + public void testMalformedContentTypeHeader() { + final String type = randomFrom("text", "text/:ain; charset=utf-8", "text/plain\";charset=utf-8", ":", "/", "t:/plain"); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new ContentRestRequest("", Collections.emptyMap(), + Collections.singletonMap("Content-Type", Collections.singletonList(type)))); + assertEquals("invalid Content-Type header [" + type + "]", e.getMessage()); + } + + public void testNoContentTypeHeader() { + ContentRestRequest contentRestRequest = new ContentRestRequest("", Collections.emptyMap(), Collections.emptyMap()); + assertNull(contentRestRequest.getXContentType()); + } + + public void testMultipleContentTypeHeaders() { + List<String> headers = new ArrayList<>(randomUnique(() -> randomAsciiOfLengthBetween(1, 16), randomIntBetween(2, 10))); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new ContentRestRequest("", Collections.emptyMap(), + Collections.singletonMap("Content-Type", headers))); + assertEquals("only one Content-Type header should be provided", e.getMessage()); } private static final class ContentRestRequest extends RestRequest { private final BytesArray content; - public ContentRestRequest(String content, Map<String, String> params) { - super(NamedXContentRegistry.EMPTY, params, "not used by this test"); + + ContentRestRequest(String content, Map<String, String> params) { + this(content, params, Collections.singletonMap("Content-Type", Collections.singletonList("application/json"))); + } + + ContentRestRequest(String content, Map<String, String> params, Map<String, List<String>> headers) { + super(NamedXContentRegistry.EMPTY, params, "not used by this test", headers); this.content = new BytesArray(content); } @@ -96,7 +150,7 @@ public class RestRequestTests extends ESTestCase { public boolean hasContent() { return Strings.hasLength(content); } - + @Override public BytesReference content() { return content; @@ -111,15 +165,5 @@ public class RestRequestTests extends ESTestCase { public Method method() { throw new UnsupportedOperationException("Not used by this test"); } - - @Override - public Iterable<Entry<String, String>> headers() { - throw new UnsupportedOperationException("Not used by this test"); - } - - @Override - public String header(String name) { - throw new UnsupportedOperationException("Not used by this test"); - } } } diff --git a/core/src/test/java/org/elasticsearch/rest/action/admin/indices/RestAnalyzeActionTests.java b/core/src/test/java/org/elasticsearch/rest/action/admin/indices/RestAnalyzeActionTests.java index da52358d3c..958b9e5222 100644 --- a/core/src/test/java/org/elasticsearch/rest/action/admin/indices/RestAnalyzeActionTests.java +++ b/core/src/test/java/org/elasticsearch/rest/action/admin/indices/RestAnalyzeActionTests.java @@ -23,6 +23,7 @@ import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.test.ESTestCase; @@ -92,7 +93,8 @@ public class RestAnalyzeActionTests extends ESTestCase { public void testParseXContentForAnalyzeRequestWithInvalidJsonThrowsException() throws Exception { RestAnalyzeAction action = new RestAnalyzeAction(Settings.EMPTY, mock(RestController.class)); - RestRequest request = new FakeRestRequest.Builder(xContentRegistry()).withContent(new BytesArray("{invalid_json}")).build(); + RestRequest request = new FakeRestRequest.Builder(xContentRegistry()) + .withContent(new BytesArray("{invalid_json}"), XContentType.JSON).build(); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> action.handleRequest(request, null, null)); assertThat(e.getMessage(), equalTo("Failed to parse request body")); } diff --git a/core/src/test/java/org/elasticsearch/rest/action/cat/RestTableTests.java b/core/src/test/java/org/elasticsearch/rest/action/cat/RestTableTests.java index 38ed76cae5..4f7bc1bedd 100644 --- a/core/src/test/java/org/elasticsearch/rest/action/cat/RestTableTests.java +++ b/core/src/test/java/org/elasticsearch/rest/action/cat/RestTableTests.java @@ -104,35 +104,35 @@ public class RestTableTests extends ESTestCase { } public void testThatWeUseTheAcceptHeaderJson() throws Exception { - assertResponse(Collections.singletonMap(ACCEPT, APPLICATION_JSON), + assertResponse(Collections.singletonMap(ACCEPT, Collections.singletonList(APPLICATION_JSON)), APPLICATION_JSON, JSON_TABLE_BODY); } public void testThatWeUseTheAcceptHeaderYaml() throws Exception { - assertResponse(Collections.singletonMap(ACCEPT, APPLICATION_YAML), + assertResponse(Collections.singletonMap(ACCEPT, Collections.singletonList(APPLICATION_YAML)), APPLICATION_YAML, YAML_TABLE_BODY); } public void testThatWeUseTheAcceptHeaderSmile() throws Exception { - assertResponseContentType(Collections.singletonMap(ACCEPT, APPLICATION_SMILE), + assertResponseContentType(Collections.singletonMap(ACCEPT, Collections.singletonList(APPLICATION_SMILE)), APPLICATION_SMILE); } public void testThatWeUseTheAcceptHeaderCbor() throws Exception { - assertResponseContentType(Collections.singletonMap(ACCEPT, APPLICATION_CBOR), + assertResponseContentType(Collections.singletonMap(ACCEPT, Collections.singletonList(APPLICATION_CBOR)), APPLICATION_CBOR); } public void testThatWeUseTheAcceptHeaderText() throws Exception { - assertResponse(Collections.singletonMap(ACCEPT, TEXT_PLAIN), + assertResponse(Collections.singletonMap(ACCEPT, Collections.singletonList(TEXT_PLAIN)), TEXT_PLAIN, TEXT_TABLE_BODY); } public void testIgnoreContentType() throws Exception { - assertResponse(Collections.singletonMap(CONTENT_TYPE, APPLICATION_JSON), + assertResponse(Collections.singletonMap(CONTENT_TYPE, Collections.singletonList(APPLICATION_JSON)), TEXT_PLAIN, TEXT_TABLE_BODY); } @@ -252,7 +252,7 @@ public class RestTableTests extends ESTestCase { assertEquals(Arrays.asList(1,0,2), rowOrder); } - private RestResponse assertResponseContentType(Map<String, String> headers, String mediaType) throws Exception { + private RestResponse assertResponseContentType(Map<String, List<String>> headers, String mediaType) throws Exception { FakeRestRequest requestWithAcceptHeader = new FakeRestRequest.Builder(xContentRegistry()).withHeaders(headers).build(); table.startRow(); table.addCell("foo"); @@ -274,7 +274,7 @@ public class RestTableTests extends ESTestCase { return response; } - private void assertResponse(Map<String, String> headers, String mediaType, String body) throws Exception { + private void assertResponse(Map<String, List<String>> headers, String mediaType, String body) throws Exception { RestResponse response = assertResponseContentType(headers, mediaType); assertThat(response.content().utf8ToString(), equalTo(body)); } |