Skip to content

<fix>[core]: support configure reply-location URL#3874

Closed
ZStack-Robot wants to merge 1 commit into
zsv_5.0.0from
sync/wenhao.zhang/zsv-8
Closed

<fix>[core]: support configure reply-location URL#3874
ZStack-Robot wants to merge 1 commit into
zsv_5.0.0from
sync/wenhao.zhang/zsv-8

Conversation

@ZStack-Robot

Copy link
Copy Markdown
Collaborator

Introduces configurable reply-location URL pieces (protocol, IP, port)
and has RESTFacadeImpl build a replyLocationUrl string from them.

The REST API's async job Location header (used when returning
202 Accepted for async messages) now uses this replyLocationUrl
instead of the internal baseUrl.

This allows overriding the public-facing callback host/IP/port
used by clients while keeping internal base URL configuration separate.

Resolves: ZSV-11815

Change-Id: I67656e6d72687462676966616b72666372746d64

sync from gitlab !9753

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown

Walkthrough

新增三个全局配置(回复位置的协议、IP、端口);RESTFacade 接口扩展并由 RESTFacadeImpl 在 init 阶段预构建并暴露 replyLocationBaseUrl;RestServer 在异步 202 响应的 Location 头中使用该预构建 URL。

Changes

Cohort / File(s) Summary
全局配置属性
core/src/main/java/org/zstack/core/CoreGlobalProperty.java
新增全局属性:core.reply.location.url.protocol(默认 http)、core.reply.location.url.ip(默认空字符串)、core.reply.location.url.port(默认 0,带 @NumberRange({0,65535}))。
REST 外观接口
header/src/main/java/org/zstack/header/rest/RESTFacade.java
接口新增方法 String getReplyLocationBaseUrl(),用于暴露预构建的回复位置基础 URL。
REST 实现
core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java
init() 中读取协议/IP/端口等配置,规范化 path,组合并校验生成 replyLocationBaseUrl,将结果缓存并通过新方法返回。
REST 服务器响应
rest/src/main/java/org/zstack/rest/RestServer.java
异步(非 APISyncCallMessage)的 202 Accepted 响应,Location 头改为基于 restf.getReplyLocationBaseUrl() 拼接版本/async-job 路径和消息 UUID。

Sequence Diagram(s)

sequenceDiagram
    participant Config as 全局配置\n(REPLY_LOCATION_URL_*)
    participant Init as RESTFacadeImpl\n(init)
    participant Facade as RESTFacade\n(getReplyLocationBaseUrl)
    participant Server as RestServer\n(handle request)
    participant Client as 客户端

    Config->>Init: 读取 protocol / ip / port / path / callbackHostName
    Init->>Init: 规范化并计算 replyLocationBaseUrl,校验可解析性
    Init-->>Facade: 缓存并暴露 replyLocationBaseUrl
    Client->>Server: 发送异步 API 请求
    Server->>Facade: 调用 getReplyLocationBaseUrl()
    Facade-->>Server: 返回 replyLocationBaseUrl
    Server->>Server: 拼接版本/async-job 路径/Job-UUID
    Server->>Client: 返回 202 Accepted\nLocation: {replyLocationBaseUrl}/...
Loading

估计代码审查工作量

🎯 3 (Moderate) | ⏱️ ~20 minutes

庆祝诗

🐇 新址设定跳又笑,
协议、IP、端口都报到。
异步回执有归路,
小兔翻滚鼓掌闹,
胡萝卜香里代码俏。

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 标题清晰准确地概括了PR的主要变更——添加可配置的回复位置URL功能,属于简洁明了的单句标题。
Description check ✅ Passed 描述详细说明了PR的目的、实现方式和业务价值,包括配置参数、URL组装逻辑和与async API的关系,与代码变更内容高度相关。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync/wenhao.zhang/zsv-8

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/src/main/java/org/zstack/core/CoreGlobalProperty.java`:
- Around line 103-105: The default value for REPLY_LOCATION_URL_PORT in
CoreGlobalProperty conflicts with its `@NumberRange` constraint and
RESTFacadeImpl's sentinel usage of 0; change the numeric range to allow 0 by
updating the `@NumberRange` on REPLY_LOCATION_URL_PORT to include 0 (e.g.,
`@NumberRange`({0, 65535})) so the default "0" remains valid and continues to
serve as the "use management port" sentinel used by RESTFacadeImpl and related
code paths.

In `@core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java`:
- Around line 155-160: The replyLocationUrl construction in RESTFacadeImpl
currently appends "/" when path is blank, which can produce a double-slash like
"//v1/..." when RestServer later calls ub.path(...); change the path fragment
logic so it is empty when path is blank and only prefix with "/" when path is
non-blank (i.e., compute a pathPart = StringUtils.isBlank(path) ? "" : "/" +
path and use that in the String.format for replyLocationUrl), referencing the
replyLocationUrl assignment in RESTFacadeImpl and the CoreGlobalProperty fields
used there.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: be894249-aebd-4fdc-bbfe-a9923077bcb9

📥 Commits

Reviewing files that changed from the base of the PR and between 6b4f0e5 and f78ea70.

📒 Files selected for processing (4)
  • core/src/main/java/org/zstack/core/CoreGlobalProperty.java
  • core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java
  • header/src/main/java/org/zstack/header/rest/RESTFacade.java
  • rest/src/main/java/org/zstack/rest/RestServer.java

Comment thread core/src/main/java/org/zstack/core/CoreGlobalProperty.java
Comment thread core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java Outdated
@MatheMatrix MatheMatrix force-pushed the sync/wenhao.zhang/zsv-8 branch from f78ea70 to a41a289 Compare April 28, 2026 09:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java`:
- Around line 159-163: The code builds replyLocationUrl from CoreGlobalProperty
values in RESTFacadeImpl (replyLocationUrl) but doesn't validate it at startup;
add a fail-fast URI/URL validation in RESTFacadeImpl.init() after constructing
replyLocationUrl (e.g. try new URI/String parsing or use
UriComponentsBuilder.build() to validate) and throw a clear
InitializationException if parsing fails so misconfigured CoreGlobalProperty
values (protocol/IP/port) are reported at startup rather than causing a runtime
error later in RestServer.sendMessage() where
UriComponentsBuilder.fromHttpUrl(restf.getReplyLocationUrl()) is called.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b6c2fced-9dc9-4c4d-b4b3-987c15924b2b

📥 Commits

Reviewing files that changed from the base of the PR and between f78ea70 and a41a289.

📒 Files selected for processing (4)
  • core/src/main/java/org/zstack/core/CoreGlobalProperty.java
  • core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java
  • header/src/main/java/org/zstack/header/rest/RESTFacade.java
  • rest/src/main/java/org/zstack/rest/RestServer.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • rest/src/main/java/org/zstack/rest/RestServer.java
  • header/src/main/java/org/zstack/header/rest/RESTFacade.java
  • core/src/main/java/org/zstack/core/CoreGlobalProperty.java

Comment thread core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java Outdated
@ZStack-Robot

Copy link
Copy Markdown
Collaborator Author

Comment from yaohua.wu:

Review: MR !9753 — ZSV-11815

背景

为解决金山客户场景下 async API 返回的 Location 头使用管理网内部 baseUrl、外网客户端无法访问的问题,引入三个 GlobalProperty(protocol/IP/port),在 RESTFacadeImpl.init() 启动时组装 replyLocationUrlRestServer 在生成 202 Accepted Location 时改用该 URL。修复方向正确,封装合理。


🔴 Critical

# File:Line Issue Fix
1 core/src/main/java/org/zstack/core/CoreGlobalProperty.java:103-104 @NumberRange({1, 65535}) 与默认值 0 + sentinel 语义直接冲突。第 103 行 defaultValue = "0",第 104 行注解约束 [1, 65535],且 RESTFacadeImpl.java:163 明确把 0 当作"使用 management port"的 sentinel 值。如果客户依赖默认值(不显式配置该属性),属性校验阶段会拒绝默认值 0 ;即使校验只在 API 写入时触发,sentinel 0 与"合法范围"也是矛盾语义,未来代码读者会误判。该问题 CodeRabbit (note 720661) 已提出且作者点了 resolved,但代码并未修改 改为 @NumberRange({0, 65535}),并在注释里明确 0 表示使用 management node service port

🟡 Warning

# File:Line Issue Fix
2 core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java:155-163 replyLocationUrl 缺 fail-fast 校验init() 中仅用 String.format 拼接,未对结果做 URI 解析;若客户把 protocol 配成 htttpHTTPtcp 或把 IP 配成 192.168.1.1.2 / 含特殊字符,启动正常。直到客户端发起首个 async API 调用,RestServer:1276UriComponentsBuilder.fromHttpUrl(replyLocationUrl) 才抛 IllegalArgumentException,错误暴露被推迟到客户业务请求,定位困难(堆栈在 RestServer,不指向 GlobalProperty 配置)。 init() 拼接完成后追加 try { UriComponentsBuilder.fromHttpUrl(replyLocationUrl).build(); } catch (Exception e) { throw new CloudRuntimeException("invalid core.reply.location.url.* configuration: " + replyLocationUrl, e); }
3 core/src/main/java/org/zstack/core/CoreGlobalProperty.java:98 REPLY_LOCATION_URL_PROTOCOL 没有白名单约束。下游 UriComponentsBuilder.fromHttpUrl() 只支持 http/https,但属性接受任意字符串。问题路径同 #2,建议合并修复。 #2 一并由 fromHttpUrl 校验托底,并在 javadoc 注明仅支持 http/https
4 core/src/main/java/org/zstack/core/CoreGlobalProperty.java:101-102 注释里 "maybe Platform.getManagementNodeServicePort()" 不严谨maybe 暗示作者也不确定 sentinel 行为,但读 RESTFacadeImpl.java:163 可知 0 明确 fallback 到 port(即 RESTFacadeImpl.port)。同时 REPLY_LOCATION_URL_IP 也有"空串 fallback 到 callbackHostName"的 sentinel 但完全没注释。 // 0 表示使用 management node service port + 给 REPLY_LOCATION_URL_IP// 空串表示使用 callbackHostName

🟢 Suggestion

# File:Line Issue Fix
5 core/src/main/java/org/zstack/core/CoreGlobalProperty.java:97-104 三段独立属性(protocol/ip/port)配置体验偏低(用户要在 zstack.properties 里改三处),相比"一个 core.reply.location.url 完整 URL 字符串"略显繁琐。但拆三段也有好处(每段独立 fallback、更易做局部校验),可酌情保留。建议在 admin manual / 客户交付文档补一段说明三属性如何协作(以及 IP 空串 / port 0 的 sentinel 语义)。 文档补充,不必改代码
6 header/src/main/java/org/zstack/header/rest/RESTFacade.java:83-86 Javadoc in location of API message reply body 表意不清,建议 Returns the externally-reachable base URL used in the Location header of async API responses (HTTP 202). 改 javadoc
7 core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java:69 字段 replyLocationUrl 实际是 base URL(RestServer:1276-1280 还会 ub.path(API_VERSION).path(ASYNC_JOB_PATH).path("/"+id) 继续拼)。命名 replyLocationBaseUrl 更贴近实际语义。 可选 rename

Coverage

  • 高信号(CodeRabbit + 本次 reviewer 双重命中):1 条(Test1 #1 port range 冲突)
  • 单源(reviewer 独立发现):6 条(tao.yang/zstack-ZSV-3564@@2 #2-Wenhao.zhang/zstack fix 61743@@2 #7
  • Upstream freshness: ✅ zsv_5.0.0 可合并、无冲突、无路径碰撞
  • 已 resolved 的 CodeRabbit 评论核对:路径前缀双斜杠问题(720662)已实际修复(diff 中可见 normalizedPath 处理);port range 冲突(720661)未实际修复已升为 Critical
  • Residual risks: protocol/IP 误配的运行时失败(tao.yang/zstack-ZSV-3564@@2 #2 修复后即可消除)
  • Testing gaps: 未见单测验证三种 fallback 路径(IP 空 / port 0 / path 空)以及非法配置场景

Verdict: REVISION_REQUIRED

需修复 #1 后再合并;建议同时合并修复 #2/#3 以彻底解决误配问题。Suggestion 类条目作者酌情采纳。


🤖 Robot Reviewer

@MatheMatrix MatheMatrix force-pushed the sync/wenhao.zhang/zsv-8 branch from a41a289 to 7e4bcad Compare April 28, 2026 09:48

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
header/src/main/java/org/zstack/header/rest/RESTFacade.java (1)

83-86: Javadoc 语义不够明确,建议直接写清 202 Location 的用途。

Line [84] 当前描述不足以区分该方法与 getBaseUrl() 的职责边界,后续维护时容易误用。

✏️ 建议修改
-    /**
-     * in location of API message reply body
-     */
+    /**
+     * Returns the externally reachable base URL used to build the HTTP 202
+     * Location header for async API job polling.
+     */
     String getReplyLocationBaseUrl();

As per coding guidelines, 接口方法不应有多余的修饰符(例如 public),且必须配有有效的 Javadoc 注释。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@header/src/main/java/org/zstack/header/rest/RESTFacade.java` around lines 83
- 86, Update the Javadoc for getReplyLocationBaseUrl() to explicitly state that
it returns the base URL used to construct the HTTP Location header for 202
Accepted responses (i.e., where clients can retrieve the eventual reply),
specify the expected format (e.g., scheme://host[:port] without path) and
explicitly contrast it with getBaseUrl() (which is the general service base URL
for APIs), so callers won't confuse the two methods; ensure the method has a
concise, clear Javadoc and no extra access modifiers.
core/src/main/java/org/zstack/core/CoreGlobalProperty.java (1)

99-105: 建议在属性层收紧协议取值,并把哨兵语义写成确定性注释。

Line [99]-Line [105] 的功能已可用,但 REPLY_LOCATION_URL_PROTOCOL 仍可配置任意字符串;另外 REPLY_LOCATION_URL_PORT 注释里的 “maybe” 不够确定,IP 空串回退语义也建议就地说明,减少配置试错。

✏️ 建议修改
     `@GlobalProperty`(name = "core.reply.location.url.protocol", defaultValue = "http")
+    `@AvailableValues`(value = {"http", "https"})
     public static String REPLY_LOCATION_URL_PROTOCOL;
     `@GlobalProperty`(name = "core.reply.location.url.ip", defaultValue = "")
+    // empty -> use callbackHostName
     public static String REPLY_LOCATION_URL_IP;
     `@GlobalProperty`(name = "core.reply.location.url.port", defaultValue = "0")
-    `@NumberRange`({0, 65535}) // Note: 0 -> use default value (maybe Platform.getManagementNodeServicePort())
+    `@NumberRange`({0, 65535}) // 0 -> use management node service port
     public static int REPLY_LOCATION_URL_PORT;

As per coding guidelines, 代码应尽量做到自解释,且注释需要随代码更新并确保内容正确。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/org/zstack/core/CoreGlobalProperty.java` around lines 99 -
105, REPLY_LOCATION_URL_PROTOCOL should be constrained to a small set of allowed
values (e.g., "http" or "https") instead of allowing any string; enforce this by
validating/normalizing the property when read (or replace the declaration with
an enum-backed/global property validator) and reject or default unknown values;
clarify sentinel semantics inline: document that REPLY_LOCATION_URL_IP == ""
means "use management node IP" and REPLY_LOCATION_URL_PORT == 0
deterministically means "use Platform.getManagementNodeServicePort()", updating
the comment on REPLY_LOCATION_URL_PORT and adding a short comment for
REPLY_LOCATION_URL_IP; reference the symbols REPLY_LOCATION_URL_PROTOCOL,
REPLY_LOCATION_URL_IP, and REPLY_LOCATION_URL_PORT when making these changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java`:
- Around line 155-158: The current normalization sets normalizedPath = "/" +
StringUtils.strip(path, "/") when StringUtils.isNotBlank(path), which yields "/"
for inputs like "/" or "///" and can reintroduce double-slash paths; change the
logic in RESTFacadeImpl to strip the slashes first and only prepend a single "/"
if the stripped result is non-empty (i.e., use StringUtils.strip(path, "/") into
a temp variable, check for notBlank on that stripped value, then set
normalizedPath = "/" + stripped), ensuring normalizedPath stays empty for
root-only inputs and avoiding "//" when later calling ub.path(...).

---

Nitpick comments:
In `@core/src/main/java/org/zstack/core/CoreGlobalProperty.java`:
- Around line 99-105: REPLY_LOCATION_URL_PROTOCOL should be constrained to a
small set of allowed values (e.g., "http" or "https") instead of allowing any
string; enforce this by validating/normalizing the property when read (or
replace the declaration with an enum-backed/global property validator) and
reject or default unknown values; clarify sentinel semantics inline: document
that REPLY_LOCATION_URL_IP == "" means "use management node IP" and
REPLY_LOCATION_URL_PORT == 0 deterministically means "use
Platform.getManagementNodeServicePort()", updating the comment on
REPLY_LOCATION_URL_PORT and adding a short comment for REPLY_LOCATION_URL_IP;
reference the symbols REPLY_LOCATION_URL_PROTOCOL, REPLY_LOCATION_URL_IP, and
REPLY_LOCATION_URL_PORT when making these changes.

In `@header/src/main/java/org/zstack/header/rest/RESTFacade.java`:
- Around line 83-86: Update the Javadoc for getReplyLocationBaseUrl() to
explicitly state that it returns the base URL used to construct the HTTP
Location header for 202 Accepted responses (i.e., where clients can retrieve the
eventual reply), specify the expected format (e.g., scheme://host[:port] without
path) and explicitly contrast it with getBaseUrl() (which is the general service
base URL for APIs), so callers won't confuse the two methods; ensure the method
has a concise, clear Javadoc and no extra access modifiers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0d96975d-eafa-4832-9863-91c1dc82f25c

📥 Commits

Reviewing files that changed from the base of the PR and between a41a289 and 7e4bcad.

📒 Files selected for processing (4)
  • core/src/main/java/org/zstack/core/CoreGlobalProperty.java
  • core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java
  • header/src/main/java/org/zstack/header/rest/RESTFacade.java
  • rest/src/main/java/org/zstack/rest/RestServer.java

Comment on lines +155 to +158
String normalizedPath = "";
if (StringUtils.isNotBlank(path)) {
normalizedPath = "/" + StringUtils.strip(path, "/");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

path 仅含 / 时仍会生成尾部斜杠,可能回退出 //v1/...

Line [156]-Line [158] 先判断 isNotBlank(path) 再拼接,path="/"(或 "///")时 strip 后为空字符串,但仍会得到 normalizedPath="/"。这会把之前修复过的双斜杠风险带回来(下游继续 ub.path(...) 时)。

🐛 建议修复
-        String normalizedPath = "";
-        if (StringUtils.isNotBlank(path)) {
-            normalizedPath = "/" + StringUtils.strip(path, "/");
-        }
+        String normalizedPath = "";
+        String strippedPath = StringUtils.strip(path, "/");
+        if (StringUtils.isNotBlank(strippedPath)) {
+            normalizedPath = "/" + strippedPath;
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java` around lines 155
- 158, The current normalization sets normalizedPath = "/" +
StringUtils.strip(path, "/") when StringUtils.isNotBlank(path), which yields "/"
for inputs like "/" or "///" and can reintroduce double-slash paths; change the
logic in RESTFacadeImpl to strip the slashes first and only prepend a single "/"
if the stripped result is non-empty (i.e., use StringUtils.strip(path, "/") into
a temp variable, check for notBlank on that stripped value, then set
normalizedPath = "/" + stripped), ensuring normalizedPath stays empty for
root-only inputs and avoiding "//" when later calling ub.path(...).

Introduces configurable reply-location URL pieces (protocol, IP, port)
and has RESTFacadeImpl build a replyLocationUrl string from them.

The REST API's async job Location header (used when returning
202 Accepted for async messages) now uses this replyLocationUrl
instead of the internal baseUrl.

This allows overriding the public-facing callback host/IP/port
used by clients while keeping internal base URL configuration separate.

Resolves: ZSV-11815

Change-Id: I67656e6d72687462676966616b72666372746d64
@MatheMatrix MatheMatrix force-pushed the sync/wenhao.zhang/zsv-8 branch from 7e4bcad to 2f9d87c Compare April 28, 2026 09:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java (1)

155-158: ⚠️ Potential issue | 🟡 Minor

path 为仅斜杠时仍会回退到 "/",可能再次产生双斜杠 URL

Line [156]-Line [157] 先判断原始 pathstrip,当 path="/""///" 时,normalizedPath 仍会被设置为 "/"。下游继续拼接 path 时,可能出现 //v1/...

🐛 建议修复
-        String normalizedPath = "";
-        if (StringUtils.isNotBlank(path)) {
-            normalizedPath = "/" + StringUtils.strip(path, "/");
-        }
+        String normalizedPath = "";
+        String strippedPath = StringUtils.strip(path, "/");
+        if (StringUtils.isNotBlank(strippedPath)) {
+            normalizedPath = "/" + strippedPath;
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java` around lines 155
- 158, The current normalization in RESTFacadeImpl sets normalizedPath = "/" +
StringUtils.strip(path, "/") whenever path is not blank, which yields "/" for
inputs like "/" or "///" and can cause double slashes downstream; change the
logic to strip leading/trailing slashes first into a temporary String (e.g.,
stripped = StringUtils.strip(path, "/")), then set normalizedPath to empty
string if stripped is empty, otherwise set normalizedPath = "/" + stripped, so
that inputs of only slashes produce "" rather than "/".
🧹 Nitpick comments (2)
core/src/main/java/org/zstack/core/CoreGlobalProperty.java (1)

101-102: IP 回退注释建议改为“空串/空白”而非仅 null

当前注释写的是 null -> use callbackHostName,但实现实际按 blank(含空串/空白)回退。建议注释与真实语义保持一致,避免运维误解。

📝 建议修改
-    `@GlobalProperty`(name = "core.reply.location.url.ip", defaultValue = "") // Note: null -> use callbackHostName
+    `@GlobalProperty`(name = "core.reply.location.url.ip", defaultValue = "") // Note: blank -> use callbackHostName
     public static String REPLY_LOCATION_URL_IP;

As per coding guidelines “对于较长的注释,需要仔细校对并随代码更新,确保内容正确”。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/org/zstack/core/CoreGlobalProperty.java` around lines 101
- 102, Update the comment on the CoreGlobalProperty.REPLY_LOCATION_URL_IP
declaration to reflect that the fallback is used when the property is
blank/empty (empty string or whitespace) rather than only null; modify the
inline comment "@GlobalProperty(name = "core.reply.location.url.ip",
defaultValue = "") // Note: null -> use callbackHostName" to indicate
blank/empty string -> use callbackHostName so the comment matches the actual
fallback semantics.
header/src/main/java/org/zstack/header/rest/RESTFacade.java (1)

83-86: 补充 getReplyLocationBaseUrl() 的 Javadoc 语义说明

当前注释语义不清晰(Line [84]),建议明确这是“异步 API 返回 202 Accepted 时用于 Location 头的外部可达基础 URL”,避免后续调用方误解。

✏️ 建议修改
-    /**
-     * in location of API message reply body
-     */
+    /**
+     * Returns the externally reachable base URL used to build the HTTP Location
+     * header for async API responses (202 Accepted).
+     */
     String getReplyLocationBaseUrl();

As per coding guidelines 接口方法“必须配有有效的 Javadoc 注释”。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@header/src/main/java/org/zstack/header/rest/RESTFacade.java` around lines 83
- 86, Update the Javadoc for the RESTFacade.getReplyLocationBaseUrl() method to
clearly state that this string is the externally reachable base URL used to
populate the HTTP Location response header for asynchronous APIs that return 202
Accepted; specify that callers should append the reply resource path/ID to this
base URL (include expected format/behavior regarding trailing slashes or path
concatenation) so there is no ambiguity about how to construct the full Location
header.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java`:
- Around line 155-158: The current normalization in RESTFacadeImpl sets
normalizedPath = "/" + StringUtils.strip(path, "/") whenever path is not blank,
which yields "/" for inputs like "/" or "///" and can cause double slashes
downstream; change the logic to strip leading/trailing slashes first into a
temporary String (e.g., stripped = StringUtils.strip(path, "/")), then set
normalizedPath to empty string if stripped is empty, otherwise set
normalizedPath = "/" + stripped, so that inputs of only slashes produce ""
rather than "/".

---

Nitpick comments:
In `@core/src/main/java/org/zstack/core/CoreGlobalProperty.java`:
- Around line 101-102: Update the comment on the
CoreGlobalProperty.REPLY_LOCATION_URL_IP declaration to reflect that the
fallback is used when the property is blank/empty (empty string or whitespace)
rather than only null; modify the inline comment "@GlobalProperty(name =
"core.reply.location.url.ip", defaultValue = "") // Note: null -> use
callbackHostName" to indicate blank/empty string -> use callbackHostName so the
comment matches the actual fallback semantics.

In `@header/src/main/java/org/zstack/header/rest/RESTFacade.java`:
- Around line 83-86: Update the Javadoc for the
RESTFacade.getReplyLocationBaseUrl() method to clearly state that this string is
the externally reachable base URL used to populate the HTTP Location response
header for asynchronous APIs that return 202 Accepted; specify that callers
should append the reply resource path/ID to this base URL (include expected
format/behavior regarding trailing slashes or path concatenation) so there is no
ambiguity about how to construct the full Location header.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7826d0d6-e282-417b-a686-e910d3999cbe

📥 Commits

Reviewing files that changed from the base of the PR and between 7e4bcad and 2f9d87c.

📒 Files selected for processing (4)
  • core/src/main/java/org/zstack/core/CoreGlobalProperty.java
  • core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java
  • header/src/main/java/org/zstack/header/rest/RESTFacade.java
  • rest/src/main/java/org/zstack/rest/RestServer.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • rest/src/main/java/org/zstack/rest/RestServer.java

@zstack-robot-2 zstack-robot-2 deleted the sync/wenhao.zhang/zsv-8 branch April 29, 2026 02:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant