This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new f6e3e31552 [api] Fix REST catalog double-encoding warehouse query
parameter (#8792)
f6e3e31552 is described below
commit f6e3e315522a0e8eebca04288dce9143d92ed027
Author: eye-gu <[email protected]>
AuthorDate: Thu Jul 23 22:04:27 2026 +0800
[api] Fix REST catalog double-encoding warehouse query parameter (#8792)
---
.../main/java/org/apache/paimon/rest/RESTApi.java | 2 +-
.../paimon/rest/RESTApiWarehouseEncodingTest.java | 86 ++++++++++++++++++++++
2 files changed, 87 insertions(+), 1 deletion(-)
diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
b/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
index e8e1ff96c8..a49982d680 100644
--- a/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
+++ b/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
@@ -199,7 +199,7 @@ public class RESTApi {
String warehouse = options.get(WAREHOUSE);
Map<String, String> queryParams =
StringUtils.isNotEmpty(warehouse)
- ? ImmutableMap.of(WAREHOUSE.key(),
RESTUtil.encodeString(warehouse))
+ ? ImmutableMap.of(WAREHOUSE.key(), warehouse)
: ImmutableMap.of();
options =
new Options(
diff --git
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTApiWarehouseEncodingTest.java
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTApiWarehouseEncodingTest.java
new file mode 100644
index 0000000000..2e14f00ecb
--- /dev/null
+++
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTApiWarehouseEncodingTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.rest;
+
+import org.apache.paimon.options.Options;
+import org.apache.paimon.rest.responses.ConfigResponse;
+
+import org.apache.paimon.shade.guava30.com.google.common.collect.ImmutableMap;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.paimon.options.CatalogOptions.WAREHOUSE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class RESTApiWarehouseEncodingTest {
+
+ private MockWebServer server;
+
+ @AfterEach
+ void tearDown() throws Exception {
+ if (server != null) {
+ server.shutdown();
+ }
+ }
+
+ @Test
+ void testWarehouseQueryParameterNotDoubleEncoded() throws Exception {
+ // A warehouse path containing ':' and '/' exposes the encoding bug.
+ String warehouse = "file:///tmp/paimon-warehouse";
+
+ server = new MockWebServer();
+ server.start();
+
+ ConfigResponse config =
+ new ConfigResponse(
+ ImmutableMap.of(
+ WAREHOUSE.key(),
+ warehouse,
+ RESTCatalogInternalOptions.PREFIX.key(),
+ "paimon"),
+ ImmutableMap.of());
+ server.enqueue(
+ new MockResponse()
+ .setResponseCode(200)
+ .setBody(RESTApi.toJson(config))
+ .addHeader("Content-Type", "application/json"));
+
+ Options options = new Options();
+ options.set(RESTCatalogOptions.URI, server.url("/").toString());
+ options.set(WAREHOUSE, warehouse);
+ options.set(RESTCatalogOptions.TOKEN, "token");
+ options.set(RESTCatalogOptions.TOKEN_PROVIDER, "bear");
+
+ // Triggers the /v1/config request inside the RESTApi constructor.
+ new RESTApi(options);
+
+ RecordedRequest request = server.takeRequest(10, TimeUnit.SECONDS);
+ String receivedWarehouse =
request.getRequestUrl().queryParameter(WAREHOUSE.key());
+
+ // The query parameter is decoded once by the HTTP layer, so it must
equal the original
+ // value. Double encoding on the client side makes it differ.
+ assertEquals(warehouse, receivedWarehouse, "warehouse query param was
double-encoded");
+ }
+}