Skip to content

Commit e302d80

Browse files
beiskejasontedor
authored andcommitted
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 /.
1 parent bd6653f commit e302d80

File tree

6 files changed

+46
-14
lines changed

6 files changed

+46
-14
lines changed

client/rest/src/main/java/org/elasticsearch/client/RestClient.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,8 +794,10 @@ static URI buildUri(String pathPrefix, String path, Map<String, String> params)
794794
Objects.requireNonNull(path, "path must not be null");
795795
try {
796796
String fullPath;
797-
if (pathPrefix != null) {
798-
if (path.startsWith("/")) {
797+
if (pathPrefix != null && pathPrefix.isEmpty() == false) {
798+
if (pathPrefix.endsWith("/") && path.startsWith("/")) {
799+
fullPath = pathPrefix.substring(0, pathPrefix.length() - 1) + path;
800+
} else if (pathPrefix.endsWith("/") || path.startsWith("/")) {
799801
fullPath = pathPrefix + path;
800802
} else {
801803
fullPath = pathPrefix + "/" + path;

client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,32 +143,33 @@ public RestClientBuilder setRequestConfigCallback(RequestConfigCallback requestC
143143
* For example, if this is set to "/my/path", then any client request will become <code>"/my/path/" + endpoint</code>.
144144
* <p>
145145
* In essence, every request's {@code endpoint} is prefixed by this {@code pathPrefix}. The path prefix is useful for when
146-
* Elasticsearch is behind a proxy that provides a base path; it is not intended for other purposes and it should not be supplied in
147-
* other scenarios.
146+
* Elasticsearch is behind a proxy that provides a base path or a proxy that requires all paths to start with '/';
147+
* it is not intended for other purposes and it should not be supplied in other scenarios.
148148
*
149149
* @throws NullPointerException if {@code pathPrefix} is {@code null}.
150-
* @throws IllegalArgumentException if {@code pathPrefix} is empty, only '/', or ends with more than one '/'.
150+
* @throws IllegalArgumentException if {@code pathPrefix} is empty, or ends with more than one '/'.
151151
*/
152152
public RestClientBuilder setPathPrefix(String pathPrefix) {
153153
Objects.requireNonNull(pathPrefix, "pathPrefix must not be null");
154-
String cleanPathPrefix = pathPrefix;
155154

155+
if (pathPrefix.isEmpty()) {
156+
throw new IllegalArgumentException("pathPrefix must not be empty");
157+
}
158+
159+
String cleanPathPrefix = pathPrefix;
156160
if (cleanPathPrefix.startsWith("/") == false) {
157161
cleanPathPrefix = "/" + cleanPathPrefix;
158162
}
159163

160164
// best effort to ensure that it looks like "/base/path" rather than "/base/path/"
161-
if (cleanPathPrefix.endsWith("/")) {
165+
if (cleanPathPrefix.endsWith("/") && cleanPathPrefix.length() > 1) {
162166
cleanPathPrefix = cleanPathPrefix.substring(0, cleanPathPrefix.length() - 1);
163167

164168
if (cleanPathPrefix.endsWith("/")) {
165169
throw new IllegalArgumentException("pathPrefix is malformed. too many trailing slashes: [" + pathPrefix + "]");
166170
}
167171
}
168172

169-
if (cleanPathPrefix.isEmpty() || "/".equals(cleanPathPrefix)) {
170-
throw new IllegalArgumentException("pathPrefix must not be empty or '/': [" + pathPrefix + "]");
171-
}
172173

173174
this.pathPrefix = cleanPathPrefix;
174175
return this;

client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderTests.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ public void testSetPathPrefixNull() {
180180
}
181181

182182
public void testSetPathPrefixEmpty() {
183-
assertSetPathPrefixThrows("/");
184183
assertSetPathPrefixThrows("");
185184
}
186185

client/rest/src/test/java/org/elasticsearch/client/RestClientTests.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,33 @@ public void onFailure(Exception exception) {
223223
}
224224

225225
public void testBuildUriLeavesPathUntouched() {
226+
final Map<String, String> emptyMap = Collections.emptyMap();
226227
{
227-
URI uri = RestClient.buildUri("/foo$bar", "/index/type/id", Collections.<String, String>emptyMap());
228+
URI uri = RestClient.buildUri("/foo$bar", "/index/type/id", emptyMap);
228229
assertEquals("/foo$bar/index/type/id", uri.getPath());
229230
}
230231
{
231-
URI uri = RestClient.buildUri(null, "/foo$bar/ty/pe/i/d", Collections.<String, String>emptyMap());
232+
URI uri = RestClient.buildUri("/", "/*", emptyMap);
233+
assertEquals("/*", uri.getPath());
234+
}
235+
{
236+
URI uri = RestClient.buildUri("/", "*", emptyMap);
237+
assertEquals("/*", uri.getPath());
238+
}
239+
{
240+
URI uri = RestClient.buildUri(null, "*", emptyMap);
241+
assertEquals("*", uri.getPath());
242+
}
243+
{
244+
URI uri = RestClient.buildUri("", "*", emptyMap);
245+
assertEquals("*", uri.getPath());
246+
}
247+
{
248+
URI uri = RestClient.buildUri(null, "/*", emptyMap);
249+
assertEquals("/*", uri.getPath());
250+
}
251+
{
252+
URI uri = RestClient.buildUri(null, "/foo$bar/ty/pe/i/d", emptyMap);
232253
assertEquals("/foo$bar/ty/pe/i/d", uri.getPath());
233254
}
234255
{

test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public abstract class ESRestTestCase extends ESTestCase {
9090
public static final String TRUSTSTORE_PASSWORD = "truststore.password";
9191
public static final String CLIENT_RETRY_TIMEOUT = "client.retry.timeout";
9292
public static final String CLIENT_SOCKET_TIMEOUT = "client.socket.timeout";
93+
public static final String CLIENT_PATH_PREFIX = "client.path.prefix";
9394

9495
/**
9596
* Convert the entity from a {@link Response} into a map of maps.
@@ -383,7 +384,11 @@ private void waitForClusterStateUpdatesToFinish() throws Exception {
383384
* Used to obtain settings for the REST client that is used to send REST requests.
384385
*/
385386
protected Settings restClientSettings() {
386-
return Settings.EMPTY;
387+
Settings.Builder builder = Settings.builder();
388+
if (System.getProperty("tests.rest.client_path_prefix") != null) {
389+
builder.put(CLIENT_PATH_PREFIX, System.getProperty("tests.rest.client_path_prefix"));
390+
}
391+
return builder.build();
387392
}
388393

389394
/**
@@ -454,6 +459,9 @@ protected static void configureClient(RestClientBuilder builder, Settings settin
454459
final TimeValue socketTimeout = TimeValue.parseTimeValue(socketTimeoutString, CLIENT_SOCKET_TIMEOUT);
455460
builder.setRequestConfigCallback(conf -> conf.setSocketTimeout(Math.toIntExact(socketTimeout.getMillis())));
456461
}
462+
if (settings.hasValue(CLIENT_PATH_PREFIX)) {
463+
builder.setPathPrefix(settings.get(CLIENT_PATH_PREFIX));
464+
}
457465
}
458466

459467
@SuppressWarnings("unchecked")

x-pack/qa/core-rest-tests-with-security/src/test/java/org/elasticsearch/xpack/security/CoreWithSecurityClientYamlTestSuiteIT.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public static Iterable<Object[]> parameters() throws Exception {
3939
protected Settings restClientSettings() {
4040
String token = basicAuthHeaderValue(USER, new SecureString(PASS.toCharArray()));
4141
return Settings.builder()
42+
.put(super.restClientSettings())
4243
.put(ThreadContext.PREFIX + ".Authorization", token)
4344
.build();
4445
}

0 commit comments

Comments
 (0)