processHeaderOverride applies channel header overrides, with placeholder substitution. Supported placeholders: - {api_key}: resolved to the channel API key - {client_header: }: resolved to the incoming request header value Header passthrough rules (keys only; values are ignored): - "*": passth
(info *common.RelayInfo, c *gin.Context)
| 188 | // |
| 189 | // Passthrough rules are applied first, then normal overrides are applied, so explicit overrides win. |
| 190 | func processHeaderOverride(info *common.RelayInfo, c *gin.Context) (map[string]string, error) { |
| 191 | headerOverride := make(map[string]string) |
| 192 | if info == nil { |
| 193 | return headerOverride, nil |
| 194 | } |
| 195 | |
| 196 | headerOverrideSource := common.GetEffectiveHeaderOverride(info) |
| 197 | |
| 198 | passAll := false |
| 199 | var passthroughRegex []*regexp.Regexp |
| 200 | if !info.IsChannelTest { |
| 201 | for k := range headerOverrideSource { |
| 202 | key := strings.TrimSpace(strings.ToLower(k)) |
| 203 | if key == "" { |
| 204 | continue |
| 205 | } |
| 206 | if key == headerPassthroughAllKey { |
| 207 | passAll = true |
| 208 | continue |
| 209 | } |
| 210 | |
| 211 | var pattern string |
| 212 | switch { |
| 213 | case strings.HasPrefix(key, headerPassthroughRegexPrefix): |
| 214 | pattern = strings.TrimSpace(key[len(headerPassthroughRegexPrefix):]) |
| 215 | case strings.HasPrefix(key, headerPassthroughRegexPrefixV2): |
| 216 | pattern = strings.TrimSpace(key[len(headerPassthroughRegexPrefixV2):]) |
| 217 | default: |
| 218 | continue |
| 219 | } |
| 220 | |
| 221 | if pattern == "" { |
| 222 | return nil, types.NewError(fmt.Errorf("header passthrough regex pattern is empty: %q", k), types.ErrorCodeChannelHeaderOverrideInvalid) |
| 223 | } |
| 224 | compiled, err := getHeaderPassthroughRegex(pattern) |
| 225 | if err != nil { |
| 226 | return nil, types.NewError(err, types.ErrorCodeChannelHeaderOverrideInvalid) |
| 227 | } |
| 228 | passthroughRegex = append(passthroughRegex, compiled) |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | if passAll || len(passthroughRegex) > 0 { |
| 233 | if c == nil || c.Request == nil { |
| 234 | return nil, types.NewError(fmt.Errorf("missing request context for header passthrough"), types.ErrorCodeChannelHeaderOverrideInvalid) |
| 235 | } |
| 236 | for name := range c.Request.Header { |
| 237 | if shouldSkipPassthroughHeader(name) { |
| 238 | continue |
| 239 | } |
| 240 | if !passAll { |
| 241 | matched := false |
| 242 | for _, re := range passthroughRegex { |
| 243 | if re.MatchString(name) { |
| 244 | matched = true |
| 245 | break |
| 246 | } |
| 247 | } |