This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new d2a8992b fix: encode API path segments (#639)
d2a8992b is described below
commit d2a8992bc35687649354fc44912d9f221e55d029
Author: aias00 <[email protected]>
AuthorDate: Tue Jul 28 07:21:14 2026 -0700
fix: encode API path segments (#639)
---
web/src/api/cluster.test.ts | 29 +++++++++++++++++++++++++++++
web/src/api/cluster.ts | 6 ++++--
web/src/api/message.test.ts | 10 ++++++++++
web/src/api/message.ts | 2 +-
4 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/web/src/api/cluster.test.ts b/web/src/api/cluster.test.ts
index 7019f8b0..65eea44e 100644
--- a/web/src/api/cluster.test.ts
+++ b/web/src/api/cluster.test.ts
@@ -23,8 +23,10 @@ import {
createNameServer,
deleteK8sCert,
deleteNameServer,
+ getCluster,
listK8sCerts,
renewK8sCert,
+ restartBroker,
restartNameServer,
restartProxy,
updateK8sCert,
@@ -103,6 +105,33 @@ describe('K8s certificate API', () => {
await expect(deleteK8sCert(cert.id)).resolves.toBeUndefined();
});
+ it('encodes cluster path parameters', async () => {
+ const cluster = {
+ id: 'cloud/prod cluster:1',
+ name: 'prod',
+ };
+ mock.onGet('/clusters/cloud%2Fprod%20cluster%3A1').reply(200, {
+ code: 200,
+ data: cluster,
+ });
+
+ await expect(getCluster(cluster.id)).resolves.toEqual(cluster);
+ });
+
+ it('encodes broker restart path parameters', async () => {
+ mock
+
.onPost('/clusters/cloud%2Fprod%20cluster%3A1/brokers/broker%2Fmain%3A10911/restart')
+ .reply(200, {
+ code: 200,
+ data: { success: true, message: 'restarted' },
+ });
+
+ await expect(restartBroker('cloud/prod cluster:1',
'broker/main:10911')).resolves.toEqual({
+ success: true,
+ message: 'restarted',
+ });
+ });
+
it('sends NameServer operation payloads to their endpoints', async () => {
const target = { clusterId: 'cluster-1', addr: '127.0.0.1:9876' };
const requests = [
diff --git a/web/src/api/cluster.ts b/web/src/api/cluster.ts
index b8de22fa..5ea7912d 100644
--- a/web/src/api/cluster.ts
+++ b/web/src/api/cluster.ts
@@ -17,6 +17,8 @@
import client from './client';
+const pathSegment = (value: string): string => encodeURIComponent(value);
+
// ─── Types ──────────────────────────────────────────────────────
export interface ClusterInfo {
id: string;
@@ -92,7 +94,7 @@ export async function listClusters() {
}
export async function getCluster(id: string) {
- const res = await client.get<{ data: ClusterInfo }>(`/clusters/${id}`);
+ const res = await client.get<{ data: ClusterInfo
}>(`/clusters/${pathSegment(id)}`);
return res.data.data;
}
@@ -102,7 +104,7 @@ export async function updateClusterConfig(data: { id:
string } & Partial<Cluster
export async function restartBroker(clusterId: string, brokerName: string) {
const res = await client.post<{ data: { success: boolean; message: string }
}>(
- `/clusters/${clusterId}/brokers/${brokerName}/restart`,
+
`/clusters/${pathSegment(clusterId)}/brokers/${pathSegment(brokerName)}/restart`,
);
return res.data.data;
}
diff --git a/web/src/api/message.test.ts b/web/src/api/message.test.ts
index b435b4e8..75b8e697 100644
--- a/web/src/api/message.test.ts
+++ b/web/src/api/message.test.ts
@@ -110,4 +110,14 @@ describe('message API', () => {
await expect(getMessageTrace('msg-1')).resolves.toEqual(trace);
});
+
+ it('encodes message IDs before requesting trace records', async () => {
+ const trace = {
+ nodes: [],
+ consumerStatus: [],
+ };
+ mock.onGet('/messages/AC1E0A64%2F0000%202A9F%3A1/trace').reply(200, {
code: 200, data: trace });
+
+ await expect(getMessageTrace('AC1E0A64/0000
2A9F:1')).resolves.toEqual(trace);
+ });
});
diff --git a/web/src/api/message.ts b/web/src/api/message.ts
index 39a0da03..0c879543 100644
--- a/web/src/api/message.ts
+++ b/web/src/api/message.ts
@@ -70,7 +70,7 @@ export async function queryMessages(params: MessageQuery) {
}
export async function getMessageTrace(msgId: string) {
- const res = await client.get<{ data: TraceRecord
}>(`/messages/${msgId}/trace`);
+ const res = await client.get<{ data: TraceRecord
}>(`/messages/${encodeURIComponent(msgId)}/trace`);
return res.data.data;
}