From 120e13148bf8944e3dea01f0de73fcedad030fd7 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Tue, 12 Apr 2016 15:19:21 -0400 Subject: [PATCH 1/5] Handle core search refactoring Original commit: elastic/x-pack-elasticsearch@fb512063ca2ecc89a78b57a92f79650a797a0442 --- .../messy/tests/SearchTransformIT.java | 2 +- .../watcher/support/WatcherUtilsTests.java | 12 ++++++------ .../elasticsearch/watcher/watch/WatchTests.java | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/elasticsearch/qa/messy-test-xpack-with-mustache/src/test/java/org/elasticsearch/messy/tests/SearchTransformIT.java b/elasticsearch/qa/messy-test-xpack-with-mustache/src/test/java/org/elasticsearch/messy/tests/SearchTransformIT.java index b2394fcfe7a..1519bea48ab 100644 --- a/elasticsearch/qa/messy-test-xpack-with-mustache/src/test/java/org/elasticsearch/messy/tests/SearchTransformIT.java +++ b/elasticsearch/qa/messy-test-xpack-with-mustache/src/test/java/org/elasticsearch/messy/tests/SearchTransformIT.java @@ -196,7 +196,7 @@ public class SearchTransformIT extends ESIntegTestCase { assertThat(result.type(), is(SearchTransform.TYPE)); assertThat(result.status(), is(Transform.Result.Status.FAILURE)); assertThat(result.reason(), notNullValue()); - assertThat(result.reason(), containsString("No query registered for [_unknown_query_]")); + assertThat(result.reason(), containsString("no [query] registered for [_unknown_query_]")); // extract the base64 encoded query from the template script, path is: query -> wrapper -> query String jsonQuery = result.executedRequest().template().getScript(); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/support/WatcherUtilsTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/support/WatcherUtilsTests.java index 101050f67ef..3ffca1ffa25 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/support/WatcherUtilsTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/support/WatcherUtilsTests.java @@ -136,9 +136,9 @@ public class WatcherUtilsTests extends ESTestCase { builder = WatcherUtils.writeSearchRequest(expectedRequest, builder, ToXContent.EMPTY_PARAMS); XContentParser parser = XContentHelper.createParser(builder.bytes()); assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - QueryParser termQueryParser = MatchAllQueryBuilder::fromXContent; - IndicesQueriesRegistry registry = new IndicesQueriesRegistry(Settings.EMPTY, - singletonMap(MatchAllQueryBuilder.NAME, new Tuple<>(MatchAllQueryBuilder.QUERY_NAME_FIELD, termQueryParser))); + IndicesQueriesRegistry registry = new IndicesQueriesRegistry(); + QueryParser queryParser = MatchAllQueryBuilder::fromXContent; + registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD); QueryParseContext context = new QueryParseContext(registry); context.reset(parser); SearchRequest result = WatcherUtils.readSearchRequest(parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE, context, null, null); @@ -226,9 +226,9 @@ public class WatcherUtilsTests extends ESTestCase { XContentParser parser = XContentHelper.createParser(builder.bytes()); assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - QueryParser termQueryParser = MatchAllQueryBuilder::fromXContent; - IndicesQueriesRegistry registry = new IndicesQueriesRegistry(Settings.EMPTY, - singletonMap(MatchAllQueryBuilder.NAME, new Tuple<>(MatchAllQueryBuilder.QUERY_NAME_FIELD, termQueryParser))); + IndicesQueriesRegistry registry = new IndicesQueriesRegistry(); + QueryParser queryParser = MatchAllQueryBuilder::fromXContent; + registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD); QueryParseContext context = new QueryParseContext(registry); context.reset(parser); SearchRequest result = WatcherUtils.readSearchRequest(parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE, context, null, null); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java index 53cf580b49f..8735bbb3630 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java @@ -353,11 +353,11 @@ public class WatchTests extends ESTestCase { Map parsers = new HashMap<>(); switch (input.type()) { case SearchInput.TYPE: - QueryParser termQueryParser = MatchAllQueryBuilder::fromXContent; - IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry(Settings.EMPTY, singletonMap( - MatchAllQueryBuilder.NAME, new Tuple<>(MatchAllQueryBuilder.QUERY_NAME_FIELD, termQueryParser))); - parsers.put(SearchInput.TYPE, new SearchInputFactory(settings, client, queryRegistry, null, null)); - return new InputRegistry(parsers); + IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry(); + QueryParser queryParser = MatchAllQueryBuilder::fromXContent; + queryRegistry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD); + parsers.put(SearchInput.TYPE, new SearchInputFactory(settings, client, queryRegistry, null, null)); + return new InputRegistry(parsers); default: parsers.put(SimpleInput.TYPE, new SimpleInputFactory(settings)); return new InputRegistry(parsers); @@ -421,9 +421,9 @@ public class WatchTests extends ESTestCase { } private TransformRegistry transformRegistry() { - QueryParser termQueryParser = MatchAllQueryBuilder::fromXContent; - IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry(Settings.EMPTY, - singletonMap(MatchAllQueryBuilder.NAME, new Tuple<>(MatchAllQueryBuilder.QUERY_NAME_FIELD, termQueryParser))); + IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry(); + QueryParser queryParser = MatchAllQueryBuilder::fromXContent; + queryRegistry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD); Map factories = new HashMap<>(); ChainTransformFactory parser = new ChainTransformFactory(); factories.put(ChainTransform.TYPE, parser); From 0d0e2b432ca75e8e376fbb82be45b9077ba6f536 Mon Sep 17 00:00:00 2001 From: Daniel Mitterdorfer Date: Wed, 13 Apr 2016 10:39:04 +0200 Subject: [PATCH 2/5] Limit request size on transport level With this commit we limit the size of all in-flight requests on transport level. The size is guarded by a circuit breaker and is based on the content size of each request. By default we use 100% of available heap meaning that the parent circuit breaker will limit the maximum available size. This value can be changed by adjusting the setting network.breaker.inflight_requests.limit Relates elastic/elasticsearchelastic/elasticsearch#16011 Original commit: elastic/x-pack-elasticsearch@d1c43fe8d969b35a3d75446d43e3a88349e5b1af --- .../transport/netty/ShieldNettyTransport.java | 6 ++-- .../netty/ShieldNettyTransportTests.java | 31 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyTransport.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyTransport.java index 1a38d4d3e24..5a2b8ddd633 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyTransport.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyTransport.java @@ -16,6 +16,7 @@ import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.shield.ssl.ClientSSLService; import org.elasticsearch.shield.ssl.ServerSSLService; import org.elasticsearch.shield.transport.SSLClientAuth; @@ -79,8 +80,9 @@ public class ShieldNettyTransport extends NettyTransport { @Inject public ShieldNettyTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, Version version, @Nullable IPFilter authenticator, @Nullable ServerSSLService serverSSLService, - ClientSSLService clientSSLService, NamedWriteableRegistry namedWriteableRegistry) { - super(settings, threadPool, networkService, bigArrays, version, namedWriteableRegistry); + ClientSSLService clientSSLService, NamedWriteableRegistry namedWriteableRegistry, + CircuitBreakerService circuitBreakerService) { + super(settings, threadPool, networkService, bigArrays, version, namedWriteableRegistry, circuitBreakerService); this.authenticator = authenticator; this.ssl = SSL_SETTING.get(settings); this.serverSslService = serverSSLService; diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/netty/ShieldNettyTransportTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/netty/ShieldNettyTransportTests.java index 20508817029..079455736c0 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/netty/ShieldNettyTransportTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/netty/ShieldNettyTransportTests.java @@ -11,6 +11,7 @@ import org.elasticsearch.common.network.NetworkService; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.env.Environment; +import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.shield.ssl.ClientSSLService; import org.elasticsearch.shield.ssl.ServerSSLService; import org.elasticsearch.shield.transport.SSLClientAuth; @@ -49,7 +50,8 @@ public class ShieldNettyTransportTests extends ESTestCase { public void testThatSSLCanBeDisabledByProfile() throws Exception { Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class)); + mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.builder().put("xpack.security.ssl", false).build()); @@ -59,7 +61,8 @@ public class ShieldNettyTransportTests extends ESTestCase { public void testThatSSLCanBeEnabledByProfile() throws Exception { Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), false).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class)); + mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.builder().put("xpack.security.ssl", true).build()); @@ -69,7 +72,8 @@ public class ShieldNettyTransportTests extends ESTestCase { public void testThatProfileTakesDefaultSSLSetting() throws Exception { Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class)); + mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); assertThat(factory.getPipeline().get(SslHandler.class).getEngine(), notNullValue()); @@ -78,7 +82,8 @@ public class ShieldNettyTransportTests extends ESTestCase { public void testDefaultClientAuth() throws Exception { Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class)); + mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true)); @@ -91,7 +96,8 @@ public class ShieldNettyTransportTests extends ESTestCase { .put(ShieldNettyTransport.SSL_SETTING.getKey(), true) .put(ShieldNettyTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class)); + mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true)); @@ -104,7 +110,8 @@ public class ShieldNettyTransportTests extends ESTestCase { .put(ShieldNettyTransport.SSL_SETTING.getKey(), true) .put(ShieldNettyTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class)); + mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); @@ -117,7 +124,8 @@ public class ShieldNettyTransportTests extends ESTestCase { .put(ShieldNettyTransport.SSL_SETTING.getKey(), true) .put(ShieldNettyTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class)); + mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); @@ -128,7 +136,8 @@ public class ShieldNettyTransportTests extends ESTestCase { String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE"); Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class)); + mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.builder().put(ShieldNettyTransport.PROFILE_CLIENT_AUTH_SETTING, value).build()); @@ -140,7 +149,8 @@ public class ShieldNettyTransportTests extends ESTestCase { String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class)); + mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.builder().put(ShieldNettyTransport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build()); @@ -153,7 +163,8 @@ public class ShieldNettyTransportTests extends ESTestCase { Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build(); ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, - mock(NamedWriteableRegistry.class)); + mock(NamedWriteableRegistry.class), + mock(CircuitBreakerService.class)); NettyMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.builder().put(ShieldNettyTransport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build()); From 3fd3adef4c560bbee972389b1915e07572766fbc Mon Sep 17 00:00:00 2001 From: Daniel Mitterdorfer Date: Wed, 13 Apr 2016 10:39:49 +0200 Subject: [PATCH 3/5] Limit request size on HTTP level With this commit we limit the size of all in-flight requests on HTTP level. The size is guarded by the same circuit breaker that is also used on transport level. Similarly, the size that is used is HTTP content length. Relates elastic/elasticsearchelastic/elasticsearch#16011 Original commit: elastic/x-pack-elasticsearch@318b7a4a8ad53efc0a4e6e56af4c334d045dd9a3 --- .../transport/netty/ShieldNettyHttpServerTransport.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransport.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransport.java index d4a049a3228..79d1e5f2f4b 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransport.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransport.java @@ -50,8 +50,8 @@ public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport { private final boolean ssl; @Inject - public ShieldNettyHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, - IPFilter ipFilter, ServerSSLService sslService, ThreadPool threadPool) { + public ShieldNettyHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, IPFilter ipFilter, + ServerSSLService sslService, ThreadPool threadPool) { super(settings, networkService, bigArrays, threadPool); this.ipFilter = ipFilter; this.ssl = SSL_SETTING.get(settings); From 847287278bd00512ec0669ed011f8158e2e57234 Mon Sep 17 00:00:00 2001 From: Alexander Reelsen Date: Wed, 13 Apr 2016 11:43:54 +0200 Subject: [PATCH 4/5] Tests: Adapting to Version changes in core Original commit: elastic/x-pack-elasticsearch@89e9cf427d1759a6cac3463125b673c7e9787718 --- .../org/elasticsearch/shield/VersionCompatibilityTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/VersionCompatibilityTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/VersionCompatibilityTests.java index a02ac83c819..cc4a145ee61 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/VersionCompatibilityTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/VersionCompatibilityTests.java @@ -37,6 +37,6 @@ public class VersionCompatibilityTests extends ESTestCase { * */ assertThat("Remove workaround in LicenseService class when es core supports merging cluster level custom metadata", - Version.CURRENT.onOrBefore(Version.V_5_0_0_alpha1), is(true)); + Version.CURRENT.onOrBefore(Version.V_5_0_0), is(true)); } } From 6d0a2f642aa03dc088e6dfe51323b4323be0e203 Mon Sep 17 00:00:00 2001 From: Alexander Reelsen Date: Wed, 13 Apr 2016 08:59:27 +0200 Subject: [PATCH 5/5] Watcher: HttpResponse serialization may not contain dots in field names The HTTP response toXContent() method contains the http response headers, which are used as field names in Elasticsearch in the watch history. These can contain dots, like `es.index` being returned when Elasticsearch encounters an exception - which results in an index error. This patch changes the dots to an underscore when calling toXContent() Closes elastic/elasticsearch#1803 Original commit: elastic/x-pack-elasticsearch@e4070f8b70a9ac83dda07337c04282fca297243b --- .../watcher/support/http/HttpResponse.java | 4 ++- .../support/http/HttpResponseTests.java | 36 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/http/HttpResponse.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/http/HttpResponse.java index 2ce7a6c4a3a..d5e383c8c1f 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/http/HttpResponse.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/http/HttpResponse.java @@ -149,7 +149,9 @@ public class HttpResponse implements ToXContent { if (!headers.isEmpty()) { builder.startObject(Field.HEADERS.getPreferredName()); for (Map.Entry header : headers.entrySet()) { - builder.array(header.getKey(), header.getValue()); + // in order to prevent dots in field names, that might occur in headers, we simply de_dot those header names + // when writing toXContent + builder.array(header.getKey().replaceAll("\\.", "_"), header.getValue()); } builder.endObject(); } diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/support/http/HttpResponseTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/support/http/HttpResponseTests.java index 90167a891ca..bcb5e25e4ba 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/support/http/HttpResponseTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/support/http/HttpResponseTests.java @@ -5,11 +5,15 @@ */ package org.elasticsearch.watcher.support.http; +import com.google.common.collect.Lists; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.test.ESTestCase; +import org.hamcrest.Matchers; import java.nio.charset.StandardCharsets; import java.util.HashMap; @@ -21,13 +25,18 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.watcher.test.WatcherTestUtils.xContentParser; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.not; /** * */ public class HttpResponseTests extends ESTestCase { + public void testParseSelfGenerated() throws Exception { int status = randomIntBetween(200, 600); Map headers = emptyMap(); @@ -91,4 +100,31 @@ public class HttpResponseTests extends ESTestCase { assertThat(response.header("key")[0], is("value")); assertThat(response.contentType(), is("text/html")); } + + public void testThatHeaderNamesDoNotContainDotsOnSerialization() throws Exception { + Map headers = new HashMap<>(); + headers.put("es.index", new String[] { "value" }); + headers.put("es.index.2", new String[] { "value" }); + + HttpResponse response = new HttpResponse(200, headers); + assertThat(response.header("es.index")[0], is("value")); + assertThat(response.header("es.index.2")[0], is("value")); + + XContentBuilder builder = jsonBuilder(); + response.toXContent(builder, ToXContent.EMPTY_PARAMS); + + XContentParser parser = XContentFactory.xContent(builder.string()).createParser(builder.string()); + Map responseMap = parser.map(); + parser.close(); + + assertThat(responseMap, hasKey("headers")); + assertThat(responseMap.get("headers"), instanceOf(Map.class)); + Map responseHeaders = (Map) responseMap.get("headers"); + + assertThat(responseHeaders, not(hasKey("es.index"))); + assertThat(responseHeaders, hasEntry("es_index", Lists.newArrayList("value"))); + + assertThat(responseHeaders, not(hasKey("es.index.2"))); + assertThat(responseHeaders, hasEntry("es_index_2", Lists.newArrayList("value"))); + } }