feat(executor): support $-based custom headers from downstream request headers

- Propagate request headers into custom-header resolution for OpenAI/Gemini/XAI/Codex execution and websocket flows.
- Resolve auth `header:` values like `$ABC` from incoming request headers at request time and omit headers when no value is available.
- Add documentation for the dynamic custom-header behavior in `config.example.yaml`.

Closes: #5053
This commit is contained in:
Luis Pater
2026-08-18 19:33:37 +08:00
parent f3e836ce6c
commit e424bfad00
20 changed files with 646 additions and 59 deletions

View File

@@ -276,9 +276,11 @@ func codexIdentityConfuseUUID(authID string, kind string, value string) string {
return uuid.NewSHA1(uuid.NameSpaceOID, []byte(name)).String()
}
func applyCodexHeaders(r *http.Request, auth *cliproxyauth.Auth, token string, stream bool, cfg *config.Config) {
func applyCodexHeaders(r *http.Request, auth *cliproxyauth.Auth, token string, stream bool, cfg *config.Config, clientHeaders ...http.Header) {
var ginHeaders http.Header
if ginCtx, ok := r.Context().Value("gin").(*gin.Context); ok && ginCtx != nil && ginCtx.Request != nil {
if len(clientHeaders) > 0 && clientHeaders[0] != nil {
ginHeaders = clientHeaders[0]
} else if ginCtx, ok := r.Context().Value("gin").(*gin.Context); ok && ginCtx != nil && ginCtx.Request != nil {
ginHeaders = ginCtx.Request.Header
}
applyCodexHeadersFromSources(r, auth, token, stream, cfg, ginHeaders)
@@ -303,9 +305,12 @@ func applyModelHeaderOverrides(headers http.Header, modelName string) {
// applyCodexDirectImageHeaders sets Codex upstream headers for direct /images/* calls.
// Downstream client User-Agent values are not forwarded to reduce Cloudflare 1010 blocks.
func applyCodexDirectImageHeaders(r *http.Request, auth *cliproxyauth.Auth, token string, stream bool, cfg *config.Config) {
func applyCodexDirectImageHeaders(r *http.Request, auth *cliproxyauth.Auth, token string, stream bool, cfg *config.Config, clientHeaders ...http.Header) {
var ginHeaders http.Header
if ginCtx, ok := r.Context().Value("gin").(*gin.Context); ok && ginCtx != nil && ginCtx.Request != nil {
if len(clientHeaders) > 0 && clientHeaders[0] != nil {
ginHeaders = clientHeaders[0].Clone()
ginHeaders.Del("User-Agent")
} else if ginCtx, ok := r.Context().Value("gin").(*gin.Context); ok && ginCtx != nil && ginCtx.Request != nil {
ginHeaders = ginCtx.Request.Header.Clone()
ginHeaders.Del("User-Agent")
}
@@ -359,7 +364,7 @@ func applyCodexHeadersFromSources(r *http.Request, auth *cliproxyauth.Auth, toke
if auth != nil {
attrs = auth.Attributes
}
util.ApplyCustomHeadersFromAttrs(r, attrs)
util.ApplyCustomHeadersFromAttrs(r, attrs, ginHeaders)
applyCodexCloakingHeaders(r.Header, cfg)
}