Enable setting client path prefix to / (#30119)

Some proxies require all requests to have paths starting with / since
there are no relative paths at the HTTP connection level. Elasticsearch
assumes paths are absolute. In order to run rest tests against a cluster
behind such a proxy, set the system property
tests.rest.client_path_prefix to /.
This commit is contained in:
Konrad Beiske 2018-07-01 19:42:03 +02:00 committed by Jason Tedor
parent 85ec497056
commit 2971dd56ca
6 changed files with 46 additions and 14 deletions

View File

@ -794,8 +794,10 @@ public class RestClient implements Closeable {
Objects.requireNonNull(path, "path must not be null");
try {
String fullPath;
if (pathPrefix != null) {
if (path.startsWith("/")) {
if (pathPrefix != null && pathPrefix.isEmpty() == false) {
if (pathPrefix.endsWith("/") && path.startsWith("/")) {
fullPath = pathPrefix.substring(0, pathPrefix.length() - 1) + path;
} else if (pathPrefix.endsWith("/") || path.startsWith("/")) {
fullPath = pathPrefix + path;
} else {
fullPath = pathPrefix + "/" + path;

View File

@ -143,22 +143,26 @@ public final class RestClientBuilder {
* For example, if this is set to "/my/path", then any client request will become <code>"/my/path/" + endpoint</code>.
* <p>
* In essence, every request's {@code endpoint} is prefixed by this {@code pathPrefix}. The path prefix is useful for when
* Elasticsearch is behind a proxy that provides a base path; it is not intended for other purposes and it should not be supplied in
* other scenarios.
* Elasticsearch is behind a proxy that provides a base path or a proxy that requires all paths to start with '/';
* it is not intended for other purposes and it should not be supplied in other scenarios.
*
* @throws NullPointerException if {@code pathPrefix} is {@code null}.
* @throws IllegalArgumentException if {@code pathPrefix} is empty, only '/', or ends with more than one '/'.
* @throws IllegalArgumentException if {@code pathPrefix} is empty, or ends with more than one '/'.
*/
public RestClientBuilder setPathPrefix(String pathPrefix) {
Objects.requireNonNull(pathPrefix, "pathPrefix must not be null");
String cleanPathPrefix = pathPrefix;
if (pathPrefix.isEmpty()) {
throw new IllegalArgumentException("pathPrefix must not be empty");
}
String cleanPathPrefix = pathPrefix;
if (cleanPathPrefix.startsWith("/") == false) {
cleanPathPrefix = "/" + cleanPathPrefix;
}
// best effort to ensure that it looks like "/base/path" rather than "/base/path/"
if (cleanPathPrefix.endsWith("/")) {
if (cleanPathPrefix.endsWith("/") && cleanPathPrefix.length() > 1) {
cleanPathPrefix = cleanPathPrefix.substring(0, cleanPathPrefix.length() - 1);
if (cleanPathPrefix.endsWith("/")) {
@ -166,9 +170,6 @@ public final class RestClientBuilder {
}
}
if (cleanPathPrefix.isEmpty() || "/".equals(cleanPathPrefix)) {
throw new IllegalArgumentException("pathPrefix must not be empty or '/': [" + pathPrefix + "]");
}
this.pathPrefix = cleanPathPrefix;
return this;

View File

@ -180,7 +180,6 @@ public class RestClientBuilderTests extends RestClientTestCase {
}
public void testSetPathPrefixEmpty() {
assertSetPathPrefixThrows("/");
assertSetPathPrefixThrows("");
}

View File

@ -223,12 +223,33 @@ public class RestClientTests extends RestClientTestCase {
}
public void testBuildUriLeavesPathUntouched() {
final Map<String, String> emptyMap = Collections.emptyMap();
{
URI uri = RestClient.buildUri("/foo$bar", "/index/type/id", Collections.<String, String>emptyMap());
URI uri = RestClient.buildUri("/foo$bar", "/index/type/id", emptyMap);
assertEquals("/foo$bar/index/type/id", uri.getPath());
}
{
URI uri = RestClient.buildUri(null, "/foo$bar/ty/pe/i/d", Collections.<String, String>emptyMap());
URI uri = RestClient.buildUri("/", "/*", emptyMap);
assertEquals("/*", uri.getPath());
}
{
URI uri = RestClient.buildUri("/", "*", emptyMap);
assertEquals("/*", uri.getPath());
}
{
URI uri = RestClient.buildUri(null, "*", emptyMap);
assertEquals("*", uri.getPath());
}
{
URI uri = RestClient.buildUri("", "*", emptyMap);
assertEquals("*", uri.getPath());
}
{
URI uri = RestClient.buildUri(null, "/*", emptyMap);
assertEquals("/*", uri.getPath());
}
{
URI uri = RestClient.buildUri(null, "/foo$bar/ty/pe/i/d", emptyMap);
assertEquals("/foo$bar/ty/pe/i/d", uri.getPath());
}
{

View File

@ -90,6 +90,7 @@ public abstract class ESRestTestCase extends ESTestCase {
public static final String TRUSTSTORE_PASSWORD = "truststore.password";
public static final String CLIENT_RETRY_TIMEOUT = "client.retry.timeout";
public static final String CLIENT_SOCKET_TIMEOUT = "client.socket.timeout";
public static final String CLIENT_PATH_PREFIX = "client.path.prefix";
/**
* Convert the entity from a {@link Response} into a map of maps.
@ -383,7 +384,11 @@ public abstract class ESRestTestCase extends ESTestCase {
* Used to obtain settings for the REST client that is used to send REST requests.
*/
protected Settings restClientSettings() {
return Settings.EMPTY;
Settings.Builder builder = Settings.builder();
if (System.getProperty("tests.rest.client_path_prefix") != null) {
builder.put(CLIENT_PATH_PREFIX, System.getProperty("tests.rest.client_path_prefix"));
}
return builder.build();
}
/**
@ -454,6 +459,9 @@ public abstract class ESRestTestCase extends ESTestCase {
final TimeValue socketTimeout = TimeValue.parseTimeValue(socketTimeoutString, CLIENT_SOCKET_TIMEOUT);
builder.setRequestConfigCallback(conf -> conf.setSocketTimeout(Math.toIntExact(socketTimeout.getMillis())));
}
if (settings.hasValue(CLIENT_PATH_PREFIX)) {
builder.setPathPrefix(settings.get(CLIENT_PATH_PREFIX));
}
}
@SuppressWarnings("unchecked")

View File

@ -39,6 +39,7 @@ public class CoreWithSecurityClientYamlTestSuiteIT extends ESClientYamlSuiteTest
protected Settings restClientSettings() {
String token = basicAuthHeaderValue(USER, new SecureString(PASS.toCharArray()));
return Settings.builder()
.put(super.restClientSettings())
.put(ThreadContext.PREFIX + ".Authorization", token)
.build();
}