diff --git a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/remote/RemoteRequestBuilders.java b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/remote/RemoteRequestBuilders.java index d20be747980..2423de5fd70 100644 --- a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/remote/RemoteRequestBuilders.java +++ b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/remote/RemoteRequestBuilders.java @@ -38,6 +38,10 @@ import org.elasticsearch.search.sort.FieldSortBuilder; import org.elasticsearch.search.sort.SortBuilder; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Arrays; +import java.util.stream.Collectors; import static org.elasticsearch.common.unit.TimeValue.timeValueMillis; @@ -54,8 +58,8 @@ final class RemoteRequestBuilders { static Request initialSearch(SearchRequest searchRequest, BytesReference query, Version remoteVersion) { // It is nasty to build paths with StringBuilder but we'll be careful.... StringBuilder path = new StringBuilder("/"); - addIndexesOrTypes(path, "Index", searchRequest.indices()); - addIndexesOrTypes(path, "Type", searchRequest.types()); + addIndices(path, searchRequest.indices()); + addTypes(path, searchRequest.types()); path.append("_search"); Request request = new Request("POST", path.toString()); @@ -158,14 +162,34 @@ final class RemoteRequestBuilders { return request; } - private static void addIndexesOrTypes(StringBuilder path, String name, String[] indicesOrTypes) { - if (indicesOrTypes == null || indicesOrTypes.length == 0) { + private static void addIndices(StringBuilder path, String[] indices) { + if (indices == null || indices.length == 0) { return; } - for (String indexOrType : indicesOrTypes) { - checkIndexOrType(name, indexOrType); + + path.append(Arrays.stream(indices).map(RemoteRequestBuilders::encodeIndex).collect(Collectors.joining(","))).append('/'); + } + + private static String encodeIndex(String s) { + if (s.contains("%")) { // already encoded, pass-through to allow this in mixed version clusters + checkIndexOrType("Index", s); + return s; } - path.append(Strings.arrayToCommaDelimitedString(indicesOrTypes)).append('/'); + try { + return URLEncoder.encode(s, "utf-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + private static void addTypes(StringBuilder path, String[] types) { + if (types == null || types.length == 0) { + return; + } + for (String indexOrType : types) { + checkIndexOrType("Type", indexOrType); + } + path.append(Strings.arrayToCommaDelimitedString(types)).append('/'); } private static void checkIndexOrType(String name, String indexOrType) { diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/remote/RemoteRequestBuildersTests.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/remote/RemoteRequestBuildersTests.java index 0f985fd3701..eb6192a0431 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/remote/RemoteRequestBuildersTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/remote/RemoteRequestBuildersTests.java @@ -68,19 +68,26 @@ public class RemoteRequestBuildersTests extends ESTestCase { searchRequest.indices("a", "b"); searchRequest.types("c", "d"); assertEquals("/a,b/c,d/_search", initialSearch(searchRequest, query, remoteVersion).getEndpoint()); - searchRequest.indices("cat,"); - expectBadStartRequest(searchRequest, "Index", ",", "cat,"); - searchRequest.indices("cat,", "dog"); - expectBadStartRequest(searchRequest, "Index", ",", "cat,"); - searchRequest.indices("dog", "cat,"); - expectBadStartRequest(searchRequest, "Index", ",", "cat,"); + assertEquals("/cat%2C/c,d/_search", initialSearch(searchRequest, query, remoteVersion).getEndpoint()); searchRequest.indices("cat/"); - expectBadStartRequest(searchRequest, "Index", "/", "cat/"); + assertEquals("/cat%2F/c,d/_search", initialSearch(searchRequest, query, remoteVersion).getEndpoint()); searchRequest.indices("cat/", "dog"); - expectBadStartRequest(searchRequest, "Index", "/", "cat/"); - searchRequest.indices("dog", "cat/"); - expectBadStartRequest(searchRequest, "Index", "/", "cat/"); + assertEquals("/cat%2F,dog/c,d/_search", initialSearch(searchRequest, query, remoteVersion).getEndpoint()); + // test a specific date math + all characters that need escaping. + searchRequest.indices("", "<>/{}|+:,"); + assertEquals("/%3Ccat%7Bnow%2Fd%7D%3E,%3C%3E%2F%7B%7D%7C%2B%3A%2C/c,d/_search", + initialSearch(searchRequest, query, remoteVersion).getEndpoint()); + + // pass-through if already escaped. + searchRequest.indices("%2f", "%3a"); + assertEquals("/%2f,%3a/c,d/_search", initialSearch(searchRequest, query, remoteVersion).getEndpoint()); + + // do not allow , and / if already escaped. + searchRequest.indices("%2fcat,"); + expectBadStartRequest(searchRequest, "Index", ",", "%2fcat,"); + searchRequest.indices("%3ccat/"); + expectBadStartRequest(searchRequest, "Index", "/", "%3ccat/"); searchRequest.indices("ok"); searchRequest.types("cat,");