Skip to content

fix: apply channel header overrides to async video task requests - #3158

Closed
kukisama wants to merge 5376 commits into
QuantumNous:mainfrom
kukisama:fix/video-task-header-override
Closed

fix: apply channel header overrides to async video task requests#3158
kukisama wants to merge 5376 commits into
QuantumNous:mainfrom
kukisama:fix/video-task-header-override

Conversation

@kukisama

@kukisama kukisama commented Mar 6, 2026

Copy link
Copy Markdown

Problem

Channel configuration already supports HeaderOverride, but async video task requests do not consistently apply these headers.

This causes Sora2 task submission, polling, and content download to behave differently from regular relay requests, especially when the upstream is behind Microsoft APIM or another gateway that requires additional request headers.

Solution

This PR applies channel header overrides to the Sora2 async video task flow:

  • apply HeaderOverride in the shared task submit request path
  • apply HeaderOverride in Sora task polling requests
  • apply HeaderOverride in Sora/OpenAI video content proxy requests

Compatibility

  • no behavior change when HeaderOverride is not configured
  • existing default Authorization: Bearer <key> behavior is preserved
  • header override remains the final override layer

Scope

This PR is intentionally scoped to the Sora2 async video task flow.

Summary by CodeRabbit

  • New Features
    • Header override support expanded across video proxy and task API paths, allowing dynamic per-request header customization (including Host).
    • Resolved headers are now preserved with tasks for consistent async follow-ups.
  • Bug Fixes
    • Header override precedence unified so explicit overrides take priority over defaults; failures during resolution surface as an error response.

Calcium-Ion and others added 30 commits February 5, 2026 21:18
- Add support for custom OAuth providers, including creation, retrieval, updating, and deletion.
- Introduce new model and controller for managing custom OAuth providers.
- Enhance existing OAuth logic to accommodate custom providers.
- Update API routes for custom OAuth provider management.
- Include i18n support for custom OAuth-related messages.
…th user creation and binding

- Improve error handling in DeleteCustomOAuthProvider to log and return errors when fetching binding counts.
- Refactor user creation and OAuth binding logic to use transactions for atomic operations, ensuring data integrity.
- Add unique constraints to UserOAuthBinding model to prevent duplicate bindings.
- Enhance GitHub OAuth provider error logging for non-200 responses.
- Update AccountManagement component to provide clearer error messages on API failures.
…ers for optional fields

- Change fields in UpdateCustomOAuthProviderRequest struct to use pointers for optional values, allowing for better handling of nil cases.
- Update UpdateCustomOAuthProvider function to check for nil before assigning optional fields, ensuring existing values are preserved when not provided.
…al file types for LF normalization and binary detection
Mitigate XSS vulnerabilities in the playground where AI-generated content
is rendered without sanitization, allowing potential script injection via
prompt injection attacks.

MarkdownRenderer.jsx:
- Replace dangerouslySetInnerHTML with a sandboxed iframe for HTML preview
- Use sandbox="allow-same-origin" to block script execution while allowing
  CSS rendering and iframe height auto-sizing
- Add SandboxedHtmlPreview component with automatic height adjustment

CodeViewer.jsx:
- Add escapeHtml() utility to encode HTML entities before rendering
- Rewrite highlightJson() to process tokens iteratively, escaping each
  token and structural text before wrapping in syntax highlighting spans
- Escape non-JSON and very-large content paths that previously bypassed
  sanitization
- Update linkRegex to correctly match URLs containing &amp; entities

These changes only affect the playground (AI output rendering). Admin-
configured content (home page, about page, footer, notices) remains
unaffected as they use separate code paths and are within the trusted
admin boundary.
🔒 fix(security): sanitize AI-generated HTML to prevent XSS in playground
…idation

- Add configurable per-user token creation limit (max_user_tokens)
- Sanitize search input patterns to prevent expensive queries
- Add per-user search rate limiting (by user ID)
- Add pagination to search endpoint with strict page size cap
- Skip empty search fields instead of matching nothing
- Hide internal errors from API responses
- Fix Interface2String float64 formatting causing config parse failures
- Add float-string fallback in config system for int/uint fields
fix: harden token search with pagination, rate limiting and input validation
- Change ESCAPE character from '\' to '!' for compatibility with MySQL/PostgreSQL/SQLite
- Adjust sanitization logic to escape '!' and '_' correctly, improving input validation for search queries
Calcium-Ion and others added 23 commits March 4, 2026 18:19
…d-path

Feature/param override wildcard path
…7ca33dbb4dc9610a

fix: fetch model add header passthrough rule key check
feats: repair the thinking of claude to openrouter convert
…7ac8c1e4b5b3e537

feat: kling cost quota support use FinalUnitDeduction as totalToken
fix: If top_p is not provided, Claude's logic will set to 1
…retry

fix(relay): skip retries for bad response body errors
Keep the model pricing editor wording aligned with the new price-based UI while exposing cache, image, and audio pricing in the marketplace so users can see the full configured pricing model.
@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Resolves and applies header overrides derived from channel configuration and task private data across the video proxy, task API request path, Sora task adaptor, and task polling, including special handling for the Host header and Authorization resolution for OpenAI/Sora flows.

Changes

Cohort / File(s) Summary
Video proxy & relay integration
controller/video_proxy.go, controller/relay.go
Resolve effective API key and call relaychannel.ResolveHeaderOverride; store resolved headers in task.PrivateData.ResolvedHeaders; apply resolved headers (including Host) for OpenAI/Sora proxy requests.
Task API request flow
relay/channel/api_request.go
Invoke header override processing in DoTaskApiRequest, then apply resolved header overrides to the outgoing proxied request before dispatch.
Sora task adaptor
relay/channel/task/sora/adaptor.go
Support body["header_override"] map in FetchTask: trim keys/values, substitute {api_key}, skip passthrough/client headers and empty values, set request headers and adjust req.Host when Host is overridden.
Task polling / fetch payload
service/task_polling.go
Include header_override in FetchTask payload derived from channel header override or from task.PrivateData.ResolvedHeaders when present.
Model/task metadata
model/task.go
Add ResolvedHeaders, TokenId, and BillingContext to TaskPrivateData; update Value() logic to treat these fields as part of non-zero state and include resolved_headers in JSON serialization.
Manifest
go.mod
Minor module manifest updates referenced by multiple diffs.

Sequence Diagram

sequenceDiagram
    autonumber
    actor Client
    participant VidProxy as Video Proxy Controller
    participant Relay as Relay/Controller
    participant Channel as Channel Config
    participant TaskAPI as Task API Request Flow
    participant Sora as Sora Task Adaptor
    participant Upstream as Upstream Service

    Client->>VidProxy: Send OpenAI/Sora video request
    VidProxy->>Relay: Build relayInfo (apiKey, headersOverride)
    Relay->>Channel: Request ResolveHeaderOverride(relayInfo)
    Channel-->>Relay: header_override (map) / error
    alt resolved headers
      Relay->>VidProxy: store in task.PrivateData.ResolvedHeaders
      VidProxy->>Upstream: apply header_override (set headers, update Host if present)
    else resolution error
      Relay-->>VidProxy: log warning (non-fatal)
    end

    Note over TaskAPI,Sora: Task API / FetchTask flow
    TaskAPI->>TaskAPI: Setup request headers (default)
    TaskAPI->>Channel: processHeaderOverride(relayInfo)
    Channel-->>TaskAPI: header_override
    TaskAPI->>Upstream: apply header_override (override headers, Host)
    TaskAPI->>Sora: send FetchTask with body["header_override"] (if present)
    Sora->>Sora: extract header_override, trim/substitute {api_key}, skip passthrough/client headers
    Sora->>Upstream: set headers on outgoing request (update Host if overridden)
    Upstream-->>Client: proxied response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • seefs001

Poem

🐇 I hopped through headers, neat and spry,
Trimming keys beneath the sky,
Replaced the token, set the Host,
Bounced packets where they mattered most—
Carrots for success! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: applying channel header overrides to async video task requests (Sora2 flow).

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

@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: 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 `@controller/video_proxy.go`:
- Around line 109-128: The code sets Authorization and builds RelayInfo.ApiKey
only from channel.Key, which ignores a per-task key; compute an effectiveKey
(use task.PrivateData.Key if present else channel.Key), use effectiveKey for the
Authorization header (req.Header.Set("Authorization", "Bearer "+effectiveKey))
and pass it into relaychannel.ResolveHeaderOverride via
relaycommon.RelayInfo.ChannelMeta.ApiKey so {api_key} expands correctly; keep
the rest of the ResolveHeaderOverride usage and Host header handling the same.

In `@service/task_polling.go`:
- Around line 362-366: The polling path calls adaptor.FetchTask with
ch.GetHeaderOverride(), which returns only the template/rule map; resolve and
persist the concrete headers at submit time and reuse them during polling: add a
field on the Task (e.g., ResolvedHeaderOverride or HeaderOverrideSnapshot), set
that snapshot in the submit flow where templates like {client_header:*} and
passthrough rules are evaluated, and change the polling call (the FetchTask
invocation that uses task.GetUpstreamTaskID() / task.Action) to pass the
persisted snapshot (falling back to ch.GetHeaderOverride() only if the snapshot
is nil) so forwarded gateway headers are available during status/content
fetches.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 34e51888-4c70-45b2-af13-f5395e5494c4

📥 Commits

Reviewing files that changed from the base of the PR and between f9b5ecc and 22ce713.

📒 Files selected for processing (4)
  • controller/video_proxy.go
  • relay/channel/api_request.go
  • relay/channel/task/sora/adaptor.go
  • service/task_polling.go

Comment thread controller/video_proxy.go
Comment thread service/task_polling.go

@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.

♻️ Duplicate comments (1)
controller/video_proxy.go (1)

117-125: ⚠️ Potential issue | 🟠 Major

Pass the effective key in RelayInfo.ApiKey when re-resolving overrides.

The fallback path still builds RelayInfo without ApiKey, but processHeaderOverride expands {api_key} from info.ApiKey. That means older tasks without ResolvedHeaders can still send literal {api_key} values in override headers and fail behind gateways.

Suggested fix
 		if len(headerOverride) == 0 {
 			var resolveErr error
 			headerOverride, resolveErr = relaychannel.ResolveHeaderOverride(&relaycommon.RelayInfo{
+				ApiKey: effectiveKey,
 				ChannelMeta: &relaycommon.ChannelMeta{
 					ApiKey:          effectiveKey,
 					HeadersOverride: channel.GetHeaderOverride(),
 				},
 			}, c)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/video_proxy.go` around lines 117 - 125, The fallback path that
calls relaychannel.ResolveHeaderOverride builds a relaycommon.RelayInfo without
setting ChannelMeta.ApiKey, so processHeaderOverride can expand a literal
"{api_key}" incorrectly; update the RelayInfo construction in the branch where
headerOverride is empty to set ChannelMeta.ApiKey = effectiveKey (i.e., pass
effectiveKey into RelayInfo.ApiKey) when calling
relaychannel.ResolveHeaderOverride so that task.PrivateData.ResolvedHeaders are
re-resolved with the correct ApiKey.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@controller/video_proxy.go`:
- Around line 117-125: The fallback path that calls
relaychannel.ResolveHeaderOverride builds a relaycommon.RelayInfo without
setting ChannelMeta.ApiKey, so processHeaderOverride can expand a literal
"{api_key}" incorrectly; update the RelayInfo construction in the branch where
headerOverride is empty to set ChannelMeta.ApiKey = effectiveKey (i.e., pass
effectiveKey into RelayInfo.ApiKey) when calling
relaychannel.ResolveHeaderOverride so that task.PrivateData.ResolvedHeaders are
re-resolved with the correct ApiKey.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fdf0d9c6-9c4b-4894-bcd2-bff5c8bdecec

📥 Commits

Reviewing files that changed from the base of the PR and between 22ce713 and c680654.

📒 Files selected for processing (4)
  • controller/relay.go
  • controller/video_proxy.go
  • model/task.go
  • service/task_polling.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • service/task_polling.go

@kukisama

kukisama commented Mar 7, 2026

Copy link
Copy Markdown
Author

This is already covered in the fallback path. RelayInfo embeds ChannelMeta, so the effective key assigned to ChannelMeta.ApiKey is what ResolveHeaderOverride reads as info.ApiKey. That means older tasks without a stored header snapshot still resolve the api_key placeholder with the effective key during live fallback resolution.

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.