Skip to content

fix(relay): apply channel header override on task API requests - #6595

Open
tancheng33 wants to merge 1 commit into
QuantumNous:mainfrom
tancheng33:fix/task-request-header-override
Open

fix(relay): apply channel header override on task API requests#6595
tancheng33 wants to merge 1 commit into
QuantumNous:mainfrom
tancheng33:fix/task-request-header-override

Conversation

@tancheng33

@tancheng33 tancheng33 commented Aug 2, 2026

Copy link
Copy Markdown

📝 变更描述 / Description

DoTaskApiRequest(视频/异步任务转发路径)只调用各 TaskAdaptor 的 BuildRequestHeader,没有像 DoApiRequest/DoWssRequest 等同步路径那样应用渠道「请求头覆盖」。因此任务类渠道(如豆包视频)上 {"*": true} 透传模板和显式覆盖均不生效,客户端的 Idempotency-Key 等头无法到达上游。

修复方式:在 BuildRequestHeader 之后按同文件既有模式调用 processHeaderOverride + applyHeaderOverrideToRequest,保持「用户设置优先级最高」的一致语义。通配透传仍受既有 skip 名单约束,Authorization 等凭据头不会被透传(新增测试覆盖了这一点)。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix)
  • ✨ 新功能 (New feature)
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

说明:本修复由 AI 辅助完成,已人工审阅代码与测试结果。

📸 运行证明 / Proof of Work

新增测试 TestDoTaskApiRequest_AppliesHeaderOverride:httptest 模拟上游 + stub TaskAdaptor,验证 {"*": ""} 下客户端 Idempotency-Key 透传、显式覆盖生效、且渠道 Authorization 不被通配透传覆盖。

$ go test ./relay/channel/ -run TestDoTaskApiRequest -v
=== RUN   TestDoTaskApiRequest_AppliesHeaderOverride
=== PAUSE TestDoTaskApiRequest_AppliesHeaderOverride
=== CONT  TestDoTaskApiRequest_AppliesHeaderOverride
--- PASS: TestDoTaskApiRequest_AppliesHeaderOverride (0.00s)
PASS
ok      github.com/QuantumNous/new-api/relay/channel    0.876s

$ go test ./relay/channel/
ok      github.com/QuantumNous/new-api/relay/channel

Summary by CodeRabbit

  • Bug Fixes
    • Configured header overrides are now applied correctly to outgoing API requests.
    • Existing request headers and authorization information are preserved.
    • Errors encountered while resolving header overrides are now surfaced properly.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

DoTaskApiRequest now applies configured header overrides after building request headers. The test coverage verifies idempotency-key forwarding, upstream token replacement, and preservation of adaptor-generated authorization.

Changes

Task request header overrides

Layer / File(s) Summary
Apply overrides and validate forwarding
relay/channel/api_request.go, relay/channel/api_request_test.go
DoTaskApiRequest resolves and applies configured header overrides before dispatch. Errors are returned directly. The integration test verifies idempotency-key forwarding, upstream token override, and retained authorization.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: seefs001

Poem

A rabbit checks each header line,
Override values now align.
The key hops through, auth stays true,
The upstream gets the values due.
Test ears twitch: the path is clear.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes applying channel header overrides to relay task API requests.
Linked Issues check ✅ Passed The change applies header overrides in DoTaskApiRequest and adds tests for passthrough, explicit overrides, and Authorization protection required by issue #6505.
Out of Scope Changes check ✅ Passed The implementation and tests remain within the scope of fixing channel header overrides for task API requests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@relay/channel/api_request_test.go`:
- Around line 205-242: Strengthen TestDoTaskApiRequest_AppliesHeaderOverride by
having headerOverrideTaskAdaptor.BuildRequestHeader set X-Upstream-Token to a
different value before the request is sent, then retain the assertion that the
received header is override-token. This verifies explicit channel overrides take
precedence over adaptor-provided headers.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c7055db-3de4-4adc-83c6-4b0c27cdc4e9

📥 Commits

Reviewing files that changed from the base of the PR and between 0ab0202 and ae3e312.

📒 Files selected for processing (2)
  • relay/channel/api_request.go
  • relay/channel/api_request_test.go

Comment on lines +205 to +242
func (a *headerOverrideTaskAdaptor) BuildRequestHeader(c *gin.Context, req *http.Request, info *relaycommon.RelayInfo) error {
req.Header.Set("Authorization", "Bearer channel-key")
return nil
}

func TestDoTaskApiRequest_AppliesHeaderOverride(t *testing.T) {
t.Parallel()

gin.SetMode(gin.TestMode)
received := make(chan http.Header, 1)
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
received <- r.Header.Clone()
w.WriteHeader(http.StatusOK)
}))
defer upstream.Close()

recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Request = httptest.NewRequest(http.MethodPost, "/v1/video/generations", strings.NewReader("{}"))
ctx.Request.Header.Set("Idempotency-Key", "idem-123")

info := &relaycommon.RelayInfo{
ChannelMeta: &relaycommon.ChannelMeta{
HeadersOverride: map[string]any{
"*": "",
"X-Upstream-Token": "override-token",
},
},
}

resp, err := DoTaskApiRequest(&headerOverrideTaskAdaptor{upstreamURL: upstream.URL}, ctx, info, strings.NewReader("{}"))
require.NoError(t, err)
defer resp.Body.Close()

headers := <-received
require.Equal(t, "idem-123", headers.Get("Idempotency-Key"))
require.Equal(t, "override-token", headers.Get("X-Upstream-Token"))
require.Equal(t, "Bearer channel-key", headers.Get("Authorization"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Test explicit override precedence against an adaptor header.

BuildRequestHeader does not set X-Upstream-Token. The test passes even if overrides run before BuildRequestHeader. Set a different X-Upstream-Token value in the adaptor. Then assert that "override-token" replaces it.

Proposed test change
 func (a *headerOverrideTaskAdaptor) BuildRequestHeader(c *gin.Context, req *http.Request, info *relaycommon.RelayInfo) error {
 	req.Header.Set("Authorization", "Bearer channel-key")
+	req.Header.Set("X-Upstream-Token", "channel-token")
 	return nil
 }

As per coding guidelines, “Backend tests must protect real behavior, API contracts, billing/accounting invariants, compatibility, or regression paths.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (a *headerOverrideTaskAdaptor) BuildRequestHeader(c *gin.Context, req *http.Request, info *relaycommon.RelayInfo) error {
req.Header.Set("Authorization", "Bearer channel-key")
return nil
}
func TestDoTaskApiRequest_AppliesHeaderOverride(t *testing.T) {
t.Parallel()
gin.SetMode(gin.TestMode)
received := make(chan http.Header, 1)
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
received <- r.Header.Clone()
w.WriteHeader(http.StatusOK)
}))
defer upstream.Close()
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Request = httptest.NewRequest(http.MethodPost, "/v1/video/generations", strings.NewReader("{}"))
ctx.Request.Header.Set("Idempotency-Key", "idem-123")
info := &relaycommon.RelayInfo{
ChannelMeta: &relaycommon.ChannelMeta{
HeadersOverride: map[string]any{
"*": "",
"X-Upstream-Token": "override-token",
},
},
}
resp, err := DoTaskApiRequest(&headerOverrideTaskAdaptor{upstreamURL: upstream.URL}, ctx, info, strings.NewReader("{}"))
require.NoError(t, err)
defer resp.Body.Close()
headers := <-received
require.Equal(t, "idem-123", headers.Get("Idempotency-Key"))
require.Equal(t, "override-token", headers.Get("X-Upstream-Token"))
require.Equal(t, "Bearer channel-key", headers.Get("Authorization"))
func (a *headerOverrideTaskAdaptor) BuildRequestHeader(c *gin.Context, req *http.Request, info *relaycommon.RelayInfo) error {
req.Header.Set("Authorization", "Bearer channel-key")
req.Header.Set("X-Upstream-Token", "channel-token")
return nil
}
func TestDoTaskApiRequest_AppliesHeaderOverride(t *testing.T) {
t.Parallel()
gin.SetMode(gin.TestMode)
received := make(chan http.Header, 1)
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
received <- r.Header.Clone()
w.WriteHeader(http.StatusOK)
}))
defer upstream.Close()
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Request = httptest.NewRequest(http.MethodPost, "/v1/video/generations", strings.NewReader("{}"))
ctx.Request.Header.Set("Idempotency-Key", "idem-123")
info := &relaycommon.RelayInfo{
ChannelMeta: &relaycommon.ChannelMeta{
HeadersOverride: map[string]any{
"*": "",
"X-Upstream-Token": "override-token",
},
},
}
resp, err := DoTaskApiRequest(&headerOverrideTaskAdaptor{upstreamURL: upstream.URL}, ctx, info, strings.NewReader("{}"))
require.NoError(t, err)
defer resp.Body.Close()
headers := <-received
require.Equal(t, "idem-123", headers.Get("Idempotency-Key"))
require.Equal(t, "override-token", headers.Get("X-Upstream-Token"))
require.Equal(t, "Bearer channel-key", headers.Get("Authorization"))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/channel/api_request_test.go` around lines 205 - 242, Strengthen
TestDoTaskApiRequest_AppliesHeaderOverride by having
headerOverrideTaskAdaptor.BuildRequestHeader set X-Upstream-Token to a different
value before the request is sent, then retain the assertion that the received
header is override-token. This verifies explicit channel overrides take
precedence over adaptor-provided headers.

Source: Coding guidelines

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.

视频任务路径未应用渠道「请求头覆盖」,导致客户端 Idempotency-Key 等头丢失

1 participant