Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 

2058 rader
57 KiB

  1. package common
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "regexp"
  7. "sort"
  8. "strconv"
  9. "strings"
  10. "github.com/QuantumNous/new-api/common"
  11. "github.com/QuantumNous/new-api/types"
  12. "github.com/samber/lo"
  13. "github.com/tidwall/gjson"
  14. "github.com/tidwall/sjson"
  15. )
  16. var negativeIndexRegexp = regexp.MustCompile(`\.(-\d+)`)
  17. const (
  18. paramOverrideContextRequestHeaders = "request_headers"
  19. paramOverrideContextHeaderOverride = "header_override"
  20. paramOverrideContextAuditRecorder = "__param_override_audit_recorder"
  21. )
  22. var errSourceHeaderNotFound = errors.New("source header does not exist")
  23. var paramOverrideKeyAuditPaths = map[string]struct{}{
  24. "model": {},
  25. "original_model": {},
  26. "upstream_model": {},
  27. "service_tier": {},
  28. "inference_geo": {},
  29. }
  30. type paramOverrideAuditRecorder struct {
  31. lines []string
  32. }
  33. type ConditionOperation struct {
  34. Path string `json:"path"` // JSON路径
  35. Mode string `json:"mode"` // full, prefix, suffix, contains, gt, gte, lt, lte
  36. Value interface{} `json:"value"` // 匹配的值
  37. Invert bool `json:"invert"` // 反选功能,true表示取反结果
  38. PassMissingKey bool `json:"pass_missing_key"` // 未获取到json key时的行为
  39. }
  40. type ParamOperation struct {
  41. Path string `json:"path"`
  42. Mode string `json:"mode"` // delete, set, move, copy, prepend, append, trim_prefix, trim_suffix, ensure_prefix, ensure_suffix, trim_space, to_lower, to_upper, replace, regex_replace, return_error, prune_objects, set_header, delete_header, copy_header, move_header, pass_headers, sync_fields
  43. Value interface{} `json:"value"`
  44. KeepOrigin bool `json:"keep_origin"`
  45. From string `json:"from,omitempty"`
  46. To string `json:"to,omitempty"`
  47. Conditions []ConditionOperation `json:"conditions,omitempty"` // 条件列表
  48. Logic string `json:"logic,omitempty"` // AND, OR (默认OR)
  49. }
  50. type ParamOverrideReturnError struct {
  51. Message string
  52. StatusCode int
  53. Code string
  54. Type string
  55. SkipRetry bool
  56. }
  57. func (e *ParamOverrideReturnError) Error() string {
  58. if e == nil {
  59. return "param override return error"
  60. }
  61. if e.Message == "" {
  62. return "param override return error"
  63. }
  64. return e.Message
  65. }
  66. func AsParamOverrideReturnError(err error) (*ParamOverrideReturnError, bool) {
  67. if err == nil {
  68. return nil, false
  69. }
  70. var target *ParamOverrideReturnError
  71. if errors.As(err, &target) {
  72. return target, true
  73. }
  74. return nil, false
  75. }
  76. func NewAPIErrorFromParamOverride(err *ParamOverrideReturnError) *types.NewAPIError {
  77. if err == nil {
  78. return types.NewError(
  79. errors.New("param override return error is nil"),
  80. types.ErrorCodeChannelParamOverrideInvalid,
  81. types.ErrOptionWithSkipRetry(),
  82. )
  83. }
  84. statusCode := err.StatusCode
  85. if statusCode < http.StatusContinue || statusCode > http.StatusNetworkAuthenticationRequired {
  86. statusCode = http.StatusBadRequest
  87. }
  88. errorCode := err.Code
  89. if strings.TrimSpace(errorCode) == "" {
  90. errorCode = string(types.ErrorCodeInvalidRequest)
  91. }
  92. errorType := err.Type
  93. if strings.TrimSpace(errorType) == "" {
  94. errorType = "invalid_request_error"
  95. }
  96. message := strings.TrimSpace(err.Message)
  97. if message == "" {
  98. message = "request blocked by param override"
  99. }
  100. opts := make([]types.NewAPIErrorOptions, 0, 1)
  101. if err.SkipRetry {
  102. opts = append(opts, types.ErrOptionWithSkipRetry())
  103. }
  104. return types.WithOpenAIError(types.OpenAIError{
  105. Message: message,
  106. Type: errorType,
  107. Code: errorCode,
  108. }, statusCode, opts...)
  109. }
  110. func ApplyParamOverride(jsonData []byte, paramOverride map[string]interface{}, conditionContext map[string]interface{}) ([]byte, error) {
  111. if len(paramOverride) == 0 {
  112. return jsonData, nil
  113. }
  114. auditRecorder := getParamOverrideAuditRecorder(conditionContext)
  115. // 尝试断言为操作格式
  116. if operations, ok := tryParseOperations(paramOverride); ok {
  117. legacyOverride := buildLegacyParamOverride(paramOverride)
  118. workingJSON := jsonData
  119. var err error
  120. if len(legacyOverride) > 0 {
  121. workingJSON, err = applyOperationsLegacy(workingJSON, legacyOverride, auditRecorder)
  122. if err != nil {
  123. return nil, err
  124. }
  125. }
  126. // 使用新方法
  127. result, err := applyOperations(string(workingJSON), operations, conditionContext)
  128. return []byte(result), err
  129. }
  130. // 直接使用旧方法
  131. return applyOperationsLegacy(jsonData, paramOverride, auditRecorder)
  132. }
  133. func buildLegacyParamOverride(paramOverride map[string]interface{}) map[string]interface{} {
  134. if len(paramOverride) == 0 {
  135. return nil
  136. }
  137. legacy := make(map[string]interface{}, len(paramOverride))
  138. for key, value := range paramOverride {
  139. if strings.EqualFold(strings.TrimSpace(key), "operations") {
  140. continue
  141. }
  142. legacy[key] = value
  143. }
  144. return legacy
  145. }
  146. func ApplyParamOverrideWithRelayInfo(jsonData []byte, info *RelayInfo) ([]byte, error) {
  147. paramOverride := getParamOverrideMap(info)
  148. if len(paramOverride) == 0 {
  149. return jsonData, nil
  150. }
  151. overrideCtx := BuildParamOverrideContext(info)
  152. var recorder *paramOverrideAuditRecorder
  153. if shouldEnableParamOverrideAudit(paramOverride) {
  154. recorder = &paramOverrideAuditRecorder{}
  155. overrideCtx[paramOverrideContextAuditRecorder] = recorder
  156. }
  157. result, err := ApplyParamOverride(jsonData, paramOverride, overrideCtx)
  158. if err != nil {
  159. return nil, err
  160. }
  161. syncRuntimeHeaderOverrideFromContext(info, overrideCtx)
  162. if info != nil {
  163. if recorder != nil {
  164. info.ParamOverrideAudit = recorder.lines
  165. } else {
  166. info.ParamOverrideAudit = nil
  167. }
  168. }
  169. return result, nil
  170. }
  171. func shouldEnableParamOverrideAudit(paramOverride map[string]interface{}) bool {
  172. if common.DebugEnabled {
  173. return true
  174. }
  175. if len(paramOverride) == 0 {
  176. return false
  177. }
  178. if operations, ok := tryParseOperations(paramOverride); ok {
  179. for _, operation := range operations {
  180. if shouldAuditParamPath(strings.TrimSpace(operation.Path)) ||
  181. shouldAuditParamPath(strings.TrimSpace(operation.To)) {
  182. return true
  183. }
  184. }
  185. for key := range buildLegacyParamOverride(paramOverride) {
  186. if shouldAuditParamPath(strings.TrimSpace(key)) {
  187. return true
  188. }
  189. }
  190. return false
  191. }
  192. for key := range paramOverride {
  193. if shouldAuditParamPath(strings.TrimSpace(key)) {
  194. return true
  195. }
  196. }
  197. return false
  198. }
  199. func getParamOverrideAuditRecorder(context map[string]interface{}) *paramOverrideAuditRecorder {
  200. if context == nil {
  201. return nil
  202. }
  203. recorder, _ := context[paramOverrideContextAuditRecorder].(*paramOverrideAuditRecorder)
  204. return recorder
  205. }
  206. func (r *paramOverrideAuditRecorder) recordOperation(mode, path, from, to string, value interface{}) {
  207. if r == nil {
  208. return
  209. }
  210. line := buildParamOverrideAuditLine(mode, path, from, to, value)
  211. if line == "" {
  212. return
  213. }
  214. if lo.Contains(r.lines, line) {
  215. return
  216. }
  217. r.lines = append(r.lines, line)
  218. }
  219. func shouldAuditParamPath(path string) bool {
  220. path = strings.TrimSpace(path)
  221. if path == "" {
  222. return false
  223. }
  224. if common.DebugEnabled {
  225. return true
  226. }
  227. _, ok := paramOverrideKeyAuditPaths[path]
  228. return ok
  229. }
  230. func shouldAuditOperation(mode, path, from, to string) bool {
  231. if common.DebugEnabled {
  232. return true
  233. }
  234. for _, candidate := range []string{path, to} {
  235. if shouldAuditParamPath(candidate) {
  236. return true
  237. }
  238. }
  239. return false
  240. }
  241. func formatParamOverrideAuditValue(value interface{}) string {
  242. switch typed := value.(type) {
  243. case nil:
  244. return "<empty>"
  245. case string:
  246. return typed
  247. default:
  248. return common.GetJsonString(typed)
  249. }
  250. }
  251. func buildParamOverrideAuditLine(mode, path, from, to string, value interface{}) string {
  252. mode = strings.TrimSpace(mode)
  253. path = strings.TrimSpace(path)
  254. from = strings.TrimSpace(from)
  255. to = strings.TrimSpace(to)
  256. if !shouldAuditOperation(mode, path, from, to) {
  257. return ""
  258. }
  259. switch mode {
  260. case "set":
  261. if path == "" {
  262. return ""
  263. }
  264. return fmt.Sprintf("set %s = %s", path, formatParamOverrideAuditValue(value))
  265. case "delete":
  266. if path == "" {
  267. return ""
  268. }
  269. return fmt.Sprintf("delete %s", path)
  270. case "copy":
  271. if from == "" || to == "" {
  272. return ""
  273. }
  274. return fmt.Sprintf("copy %s -> %s", from, to)
  275. case "move":
  276. if from == "" || to == "" {
  277. return ""
  278. }
  279. return fmt.Sprintf("move %s -> %s", from, to)
  280. case "prepend":
  281. if path == "" {
  282. return ""
  283. }
  284. return fmt.Sprintf("prepend %s with %s", path, formatParamOverrideAuditValue(value))
  285. case "append":
  286. if path == "" {
  287. return ""
  288. }
  289. return fmt.Sprintf("append %s with %s", path, formatParamOverrideAuditValue(value))
  290. case "trim_prefix", "trim_suffix", "ensure_prefix", "ensure_suffix":
  291. if path == "" {
  292. return ""
  293. }
  294. return fmt.Sprintf("%s %s with %s", mode, path, formatParamOverrideAuditValue(value))
  295. case "trim_space", "to_lower", "to_upper":
  296. if path == "" {
  297. return ""
  298. }
  299. return fmt.Sprintf("%s %s", mode, path)
  300. case "replace", "regex_replace":
  301. if path == "" {
  302. return ""
  303. }
  304. return fmt.Sprintf("%s %s from %s to %s", mode, path, from, to)
  305. case "set_header":
  306. if path == "" {
  307. return ""
  308. }
  309. return fmt.Sprintf("set_header %s = %s", path, formatParamOverrideAuditValue(value))
  310. case "delete_header":
  311. if path == "" {
  312. return ""
  313. }
  314. return fmt.Sprintf("delete_header %s", path)
  315. case "copy_header", "move_header":
  316. if from == "" || to == "" {
  317. return ""
  318. }
  319. return fmt.Sprintf("%s %s -> %s", mode, from, to)
  320. case "pass_headers":
  321. return fmt.Sprintf("pass_headers %s", formatParamOverrideAuditValue(value))
  322. case "sync_fields":
  323. if from == "" || to == "" {
  324. return ""
  325. }
  326. return fmt.Sprintf("sync_fields %s -> %s", from, to)
  327. case "return_error":
  328. return fmt.Sprintf("return_error %s", formatParamOverrideAuditValue(value))
  329. default:
  330. if path == "" {
  331. return mode
  332. }
  333. return fmt.Sprintf("%s %s", mode, path)
  334. }
  335. }
  336. func getParamOverrideMap(info *RelayInfo) map[string]interface{} {
  337. if info == nil || info.ChannelMeta == nil {
  338. return nil
  339. }
  340. return info.ChannelMeta.ParamOverride
  341. }
  342. func getHeaderOverrideMap(info *RelayInfo) map[string]interface{} {
  343. if info == nil || info.ChannelMeta == nil {
  344. return nil
  345. }
  346. return info.ChannelMeta.HeadersOverride
  347. }
  348. func sanitizeHeaderOverrideMap(source map[string]interface{}) map[string]interface{} {
  349. if len(source) == 0 {
  350. return map[string]interface{}{}
  351. }
  352. target := make(map[string]interface{}, len(source))
  353. for key, value := range source {
  354. normalizedKey := normalizeHeaderContextKey(key)
  355. if normalizedKey == "" {
  356. continue
  357. }
  358. normalizedValue := strings.TrimSpace(fmt.Sprintf("%v", value))
  359. if normalizedValue == "" {
  360. if isHeaderPassthroughRuleKeyForOverride(normalizedKey) {
  361. target[normalizedKey] = ""
  362. }
  363. continue
  364. }
  365. target[normalizedKey] = normalizedValue
  366. }
  367. return target
  368. }
  369. func isHeaderPassthroughRuleKeyForOverride(key string) bool {
  370. key = strings.TrimSpace(strings.ToLower(key))
  371. if key == "" {
  372. return false
  373. }
  374. if key == "*" {
  375. return true
  376. }
  377. return strings.HasPrefix(key, "re:") || strings.HasPrefix(key, "regex:")
  378. }
  379. func GetEffectiveHeaderOverride(info *RelayInfo) map[string]interface{} {
  380. if info == nil {
  381. return map[string]interface{}{}
  382. }
  383. if info.UseRuntimeHeadersOverride {
  384. return sanitizeHeaderOverrideMap(info.RuntimeHeadersOverride)
  385. }
  386. return sanitizeHeaderOverrideMap(getHeaderOverrideMap(info))
  387. }
  388. func tryParseOperations(paramOverride map[string]interface{}) ([]ParamOperation, bool) {
  389. // 检查是否包含 "operations" 字段
  390. opsValue, exists := paramOverride["operations"]
  391. if !exists {
  392. return nil, false
  393. }
  394. var opMaps []map[string]interface{}
  395. switch ops := opsValue.(type) {
  396. case []interface{}:
  397. opMaps = make([]map[string]interface{}, 0, len(ops))
  398. for _, op := range ops {
  399. opMap, ok := op.(map[string]interface{})
  400. if !ok {
  401. return nil, false
  402. }
  403. opMaps = append(opMaps, opMap)
  404. }
  405. case []map[string]interface{}:
  406. opMaps = ops
  407. default:
  408. return nil, false
  409. }
  410. operations := make([]ParamOperation, 0, len(opMaps))
  411. for _, opMap := range opMaps {
  412. operation := ParamOperation{}
  413. // 断言必要字段
  414. if path, ok := opMap["path"].(string); ok {
  415. operation.Path = path
  416. }
  417. if mode, ok := opMap["mode"].(string); ok {
  418. operation.Mode = mode
  419. } else {
  420. return nil, false // mode 是必需的
  421. }
  422. // 可选字段
  423. if value, exists := opMap["value"]; exists {
  424. operation.Value = value
  425. }
  426. if keepOrigin, ok := opMap["keep_origin"].(bool); ok {
  427. operation.KeepOrigin = keepOrigin
  428. }
  429. if from, ok := opMap["from"].(string); ok {
  430. operation.From = from
  431. }
  432. if to, ok := opMap["to"].(string); ok {
  433. operation.To = to
  434. }
  435. if logic, ok := opMap["logic"].(string); ok {
  436. operation.Logic = logic
  437. } else {
  438. operation.Logic = "OR" // 默认为OR
  439. }
  440. // 解析条件
  441. if conditions, exists := opMap["conditions"]; exists {
  442. parsedConditions, err := parseConditionOperations(conditions)
  443. if err != nil {
  444. return nil, false
  445. }
  446. operation.Conditions = append(operation.Conditions, parsedConditions...)
  447. }
  448. operations = append(operations, operation)
  449. }
  450. return operations, true
  451. }
  452. func checkConditions(jsonStr, contextJSON string, conditions []ConditionOperation, logic string) (bool, error) {
  453. if len(conditions) == 0 {
  454. return true, nil // 没有条件,直接通过
  455. }
  456. results := make([]bool, len(conditions))
  457. for i, condition := range conditions {
  458. result, err := checkSingleCondition(jsonStr, contextJSON, condition)
  459. if err != nil {
  460. return false, err
  461. }
  462. results[i] = result
  463. }
  464. if strings.ToUpper(logic) == "AND" {
  465. return lo.EveryBy(results, func(item bool) bool { return item }), nil
  466. }
  467. return lo.SomeBy(results, func(item bool) bool { return item }), nil
  468. }
  469. func checkSingleCondition(jsonStr, contextJSON string, condition ConditionOperation) (bool, error) {
  470. // 处理负数索引
  471. path := processNegativeIndex(jsonStr, condition.Path)
  472. value := gjson.Get(jsonStr, path)
  473. if !value.Exists() && contextJSON != "" {
  474. value = gjson.Get(contextJSON, condition.Path)
  475. }
  476. if !value.Exists() {
  477. if condition.PassMissingKey {
  478. return true, nil
  479. }
  480. return false, nil
  481. }
  482. // 利用gjson的类型解析
  483. targetBytes, err := common.Marshal(condition.Value)
  484. if err != nil {
  485. return false, fmt.Errorf("failed to marshal condition value: %v", err)
  486. }
  487. targetValue := gjson.ParseBytes(targetBytes)
  488. result, err := compareGjsonValues(value, targetValue, strings.ToLower(condition.Mode))
  489. if err != nil {
  490. return false, fmt.Errorf("comparison failed for path %s: %v", condition.Path, err)
  491. }
  492. if condition.Invert {
  493. result = !result
  494. }
  495. return result, nil
  496. }
  497. func processNegativeIndex(jsonStr string, path string) string {
  498. matches := negativeIndexRegexp.FindAllStringSubmatch(path, -1)
  499. if len(matches) == 0 {
  500. return path
  501. }
  502. result := path
  503. for _, match := range matches {
  504. negIndex := match[1]
  505. index, _ := strconv.Atoi(negIndex)
  506. arrayPath := strings.Split(path, negIndex)[0]
  507. if strings.HasSuffix(arrayPath, ".") {
  508. arrayPath = arrayPath[:len(arrayPath)-1]
  509. }
  510. array := gjson.Get(jsonStr, arrayPath)
  511. if array.IsArray() {
  512. length := len(array.Array())
  513. actualIndex := length + index
  514. if actualIndex >= 0 && actualIndex < length {
  515. result = strings.Replace(result, match[0], "."+strconv.Itoa(actualIndex), 1)
  516. }
  517. }
  518. }
  519. return result
  520. }
  521. // compareGjsonValues 直接比较两个gjson.Result,支持所有比较模式
  522. func compareGjsonValues(jsonValue, targetValue gjson.Result, mode string) (bool, error) {
  523. switch mode {
  524. case "full":
  525. return compareEqual(jsonValue, targetValue)
  526. case "prefix":
  527. return strings.HasPrefix(jsonValue.String(), targetValue.String()), nil
  528. case "suffix":
  529. return strings.HasSuffix(jsonValue.String(), targetValue.String()), nil
  530. case "contains":
  531. return strings.Contains(jsonValue.String(), targetValue.String()), nil
  532. case "gt":
  533. return compareNumeric(jsonValue, targetValue, "gt")
  534. case "gte":
  535. return compareNumeric(jsonValue, targetValue, "gte")
  536. case "lt":
  537. return compareNumeric(jsonValue, targetValue, "lt")
  538. case "lte":
  539. return compareNumeric(jsonValue, targetValue, "lte")
  540. default:
  541. return false, fmt.Errorf("unsupported comparison mode: %s", mode)
  542. }
  543. }
  544. func compareEqual(jsonValue, targetValue gjson.Result) (bool, error) {
  545. // 对null值特殊处理:两个都是null返回true,一个是null另一个不是返回false
  546. if jsonValue.Type == gjson.Null || targetValue.Type == gjson.Null {
  547. return jsonValue.Type == gjson.Null && targetValue.Type == gjson.Null, nil
  548. }
  549. // 对布尔值特殊处理
  550. if (jsonValue.Type == gjson.True || jsonValue.Type == gjson.False) &&
  551. (targetValue.Type == gjson.True || targetValue.Type == gjson.False) {
  552. return jsonValue.Bool() == targetValue.Bool(), nil
  553. }
  554. // 如果类型不同,报错
  555. if jsonValue.Type != targetValue.Type {
  556. return false, fmt.Errorf("compare for different types, got %v and %v", jsonValue.Type, targetValue.Type)
  557. }
  558. switch jsonValue.Type {
  559. case gjson.True, gjson.False:
  560. return jsonValue.Bool() == targetValue.Bool(), nil
  561. case gjson.Number:
  562. return jsonValue.Num == targetValue.Num, nil
  563. case gjson.String:
  564. return jsonValue.String() == targetValue.String(), nil
  565. default:
  566. return jsonValue.String() == targetValue.String(), nil
  567. }
  568. }
  569. func compareNumeric(jsonValue, targetValue gjson.Result, operator string) (bool, error) {
  570. // 只有数字类型才支持数值比较
  571. if jsonValue.Type != gjson.Number || targetValue.Type != gjson.Number {
  572. return false, fmt.Errorf("numeric comparison requires both values to be numbers, got %v and %v", jsonValue.Type, targetValue.Type)
  573. }
  574. jsonNum := jsonValue.Num
  575. targetNum := targetValue.Num
  576. switch operator {
  577. case "gt":
  578. return jsonNum > targetNum, nil
  579. case "gte":
  580. return jsonNum >= targetNum, nil
  581. case "lt":
  582. return jsonNum < targetNum, nil
  583. case "lte":
  584. return jsonNum <= targetNum, nil
  585. default:
  586. return false, fmt.Errorf("unsupported numeric operator: %s", operator)
  587. }
  588. }
  589. // applyOperationsLegacy 原参数覆盖方法
  590. func applyOperationsLegacy(jsonData []byte, paramOverride map[string]interface{}, auditRecorder *paramOverrideAuditRecorder) ([]byte, error) {
  591. reqMap := make(map[string]interface{})
  592. err := common.Unmarshal(jsonData, &reqMap)
  593. if err != nil {
  594. return nil, err
  595. }
  596. for key, value := range paramOverride {
  597. reqMap[key] = value
  598. auditRecorder.recordOperation("set", key, "", "", value)
  599. }
  600. return common.Marshal(reqMap)
  601. }
  602. func applyOperations(jsonStr string, operations []ParamOperation, conditionContext map[string]interface{}) (string, error) {
  603. context := ensureContextMap(conditionContext)
  604. auditRecorder := getParamOverrideAuditRecorder(context)
  605. contextJSON, err := marshalContextJSON(context)
  606. if err != nil {
  607. return "", fmt.Errorf("failed to marshal condition context: %v", err)
  608. }
  609. result := jsonStr
  610. for _, op := range operations {
  611. // 检查条件是否满足
  612. ok, err := checkConditions(result, contextJSON, op.Conditions, op.Logic)
  613. if err != nil {
  614. return "", err
  615. }
  616. if !ok {
  617. continue // 条件不满足,跳过当前操作
  618. }
  619. // 处理路径中的负数索引
  620. opPath := processNegativeIndex(result, op.Path)
  621. var opPaths []string
  622. if isPathBasedOperation(op.Mode) {
  623. opPaths, err = resolveOperationPaths(result, opPath)
  624. if err != nil {
  625. return "", err
  626. }
  627. if len(opPaths) == 0 {
  628. continue
  629. }
  630. }
  631. switch op.Mode {
  632. case "delete":
  633. for _, path := range opPaths {
  634. result, err = deleteValue(result, path)
  635. if err != nil {
  636. break
  637. }
  638. auditRecorder.recordOperation("delete", path, "", "", nil)
  639. }
  640. case "set":
  641. for _, path := range opPaths {
  642. if op.KeepOrigin && gjson.Get(result, path).Exists() {
  643. continue
  644. }
  645. result, err = sjson.Set(result, path, op.Value)
  646. if err != nil {
  647. break
  648. }
  649. auditRecorder.recordOperation("set", path, "", "", op.Value)
  650. }
  651. case "move":
  652. opFrom := processNegativeIndex(result, op.From)
  653. opTo := processNegativeIndex(result, op.To)
  654. result, err = moveValue(result, opFrom, opTo)
  655. if err == nil {
  656. auditRecorder.recordOperation("move", "", opFrom, opTo, nil)
  657. }
  658. case "copy":
  659. if op.From == "" || op.To == "" {
  660. return "", fmt.Errorf("copy from/to is required")
  661. }
  662. opFrom := processNegativeIndex(result, op.From)
  663. opTo := processNegativeIndex(result, op.To)
  664. result, err = copyValue(result, opFrom, opTo)
  665. if err == nil {
  666. auditRecorder.recordOperation("copy", "", opFrom, opTo, nil)
  667. }
  668. case "prepend":
  669. for _, path := range opPaths {
  670. result, err = modifyValue(result, path, op.Value, op.KeepOrigin, true)
  671. if err != nil {
  672. break
  673. }
  674. auditRecorder.recordOperation("prepend", path, "", "", op.Value)
  675. }
  676. case "append":
  677. for _, path := range opPaths {
  678. result, err = modifyValue(result, path, op.Value, op.KeepOrigin, false)
  679. if err != nil {
  680. break
  681. }
  682. auditRecorder.recordOperation("append", path, "", "", op.Value)
  683. }
  684. case "trim_prefix":
  685. for _, path := range opPaths {
  686. result, err = trimStringValue(result, path, op.Value, true)
  687. if err != nil {
  688. break
  689. }
  690. auditRecorder.recordOperation("trim_prefix", path, "", "", op.Value)
  691. }
  692. case "trim_suffix":
  693. for _, path := range opPaths {
  694. result, err = trimStringValue(result, path, op.Value, false)
  695. if err != nil {
  696. break
  697. }
  698. auditRecorder.recordOperation("trim_suffix", path, "", "", op.Value)
  699. }
  700. case "ensure_prefix":
  701. for _, path := range opPaths {
  702. result, err = ensureStringAffix(result, path, op.Value, true)
  703. if err != nil {
  704. break
  705. }
  706. auditRecorder.recordOperation("ensure_prefix", path, "", "", op.Value)
  707. }
  708. case "ensure_suffix":
  709. for _, path := range opPaths {
  710. result, err = ensureStringAffix(result, path, op.Value, false)
  711. if err != nil {
  712. break
  713. }
  714. auditRecorder.recordOperation("ensure_suffix", path, "", "", op.Value)
  715. }
  716. case "trim_space":
  717. for _, path := range opPaths {
  718. result, err = transformStringValue(result, path, strings.TrimSpace)
  719. if err != nil {
  720. break
  721. }
  722. auditRecorder.recordOperation("trim_space", path, "", "", nil)
  723. }
  724. case "to_lower":
  725. for _, path := range opPaths {
  726. result, err = transformStringValue(result, path, strings.ToLower)
  727. if err != nil {
  728. break
  729. }
  730. auditRecorder.recordOperation("to_lower", path, "", "", nil)
  731. }
  732. case "to_upper":
  733. for _, path := range opPaths {
  734. result, err = transformStringValue(result, path, strings.ToUpper)
  735. if err != nil {
  736. break
  737. }
  738. auditRecorder.recordOperation("to_upper", path, "", "", nil)
  739. }
  740. case "replace":
  741. for _, path := range opPaths {
  742. result, err = replaceStringValue(result, path, op.From, op.To)
  743. if err != nil {
  744. break
  745. }
  746. auditRecorder.recordOperation("replace", path, op.From, op.To, nil)
  747. }
  748. case "regex_replace":
  749. for _, path := range opPaths {
  750. result, err = regexReplaceStringValue(result, path, op.From, op.To)
  751. if err != nil {
  752. break
  753. }
  754. auditRecorder.recordOperation("regex_replace", path, op.From, op.To, nil)
  755. }
  756. case "return_error":
  757. auditRecorder.recordOperation("return_error", op.Path, "", "", op.Value)
  758. returnErr, parseErr := parseParamOverrideReturnError(op.Value)
  759. if parseErr != nil {
  760. return "", parseErr
  761. }
  762. return "", returnErr
  763. case "prune_objects":
  764. for _, path := range opPaths {
  765. result, err = pruneObjects(result, path, contextJSON, op.Value)
  766. if err != nil {
  767. break
  768. }
  769. }
  770. case "set_header":
  771. err = setHeaderOverrideInContext(context, op.Path, op.Value, op.KeepOrigin)
  772. if err == nil {
  773. auditRecorder.recordOperation("set_header", op.Path, "", "", op.Value)
  774. contextJSON, err = marshalContextJSON(context)
  775. }
  776. case "delete_header":
  777. err = deleteHeaderOverrideInContext(context, op.Path)
  778. if err == nil {
  779. auditRecorder.recordOperation("delete_header", op.Path, "", "", nil)
  780. contextJSON, err = marshalContextJSON(context)
  781. }
  782. case "copy_header":
  783. sourceHeader := strings.TrimSpace(op.From)
  784. targetHeader := strings.TrimSpace(op.To)
  785. if sourceHeader == "" {
  786. sourceHeader = strings.TrimSpace(op.Path)
  787. }
  788. if targetHeader == "" {
  789. targetHeader = strings.TrimSpace(op.Path)
  790. }
  791. err = copyHeaderInContext(context, sourceHeader, targetHeader, op.KeepOrigin)
  792. if errors.Is(err, errSourceHeaderNotFound) {
  793. err = nil
  794. }
  795. if err == nil {
  796. auditRecorder.recordOperation("copy_header", "", sourceHeader, targetHeader, nil)
  797. contextJSON, err = marshalContextJSON(context)
  798. }
  799. case "move_header":
  800. sourceHeader := strings.TrimSpace(op.From)
  801. targetHeader := strings.TrimSpace(op.To)
  802. if sourceHeader == "" {
  803. sourceHeader = strings.TrimSpace(op.Path)
  804. }
  805. if targetHeader == "" {
  806. targetHeader = strings.TrimSpace(op.Path)
  807. }
  808. err = moveHeaderInContext(context, sourceHeader, targetHeader, op.KeepOrigin)
  809. if errors.Is(err, errSourceHeaderNotFound) {
  810. err = nil
  811. }
  812. if err == nil {
  813. auditRecorder.recordOperation("move_header", "", sourceHeader, targetHeader, nil)
  814. contextJSON, err = marshalContextJSON(context)
  815. }
  816. case "pass_headers":
  817. headerNames, parseErr := parseHeaderPassThroughNames(op.Value)
  818. if parseErr != nil {
  819. return "", parseErr
  820. }
  821. for _, headerName := range headerNames {
  822. if err = copyHeaderInContext(context, headerName, headerName, op.KeepOrigin); err != nil {
  823. if errors.Is(err, errSourceHeaderNotFound) {
  824. err = nil
  825. continue
  826. }
  827. break
  828. }
  829. }
  830. if err == nil {
  831. auditRecorder.recordOperation("pass_headers", "", "", "", headerNames)
  832. contextJSON, err = marshalContextJSON(context)
  833. }
  834. case "sync_fields":
  835. result, err = syncFieldsBetweenTargets(result, context, op.From, op.To)
  836. if err == nil {
  837. auditRecorder.recordOperation("sync_fields", "", op.From, op.To, nil)
  838. contextJSON, err = marshalContextJSON(context)
  839. }
  840. default:
  841. return "", fmt.Errorf("unknown operation: %s", op.Mode)
  842. }
  843. if err != nil {
  844. return "", fmt.Errorf("operation %s failed: %w", op.Mode, err)
  845. }
  846. }
  847. return result, nil
  848. }
  849. func parseParamOverrideReturnError(value interface{}) (*ParamOverrideReturnError, error) {
  850. result := &ParamOverrideReturnError{
  851. StatusCode: http.StatusBadRequest,
  852. Code: string(types.ErrorCodeInvalidRequest),
  853. Type: "invalid_request_error",
  854. SkipRetry: true,
  855. }
  856. switch raw := value.(type) {
  857. case nil:
  858. return nil, fmt.Errorf("return_error value is required")
  859. case string:
  860. result.Message = strings.TrimSpace(raw)
  861. case map[string]interface{}:
  862. if message, ok := raw["message"].(string); ok {
  863. result.Message = strings.TrimSpace(message)
  864. }
  865. if result.Message == "" {
  866. if message, ok := raw["msg"].(string); ok {
  867. result.Message = strings.TrimSpace(message)
  868. }
  869. }
  870. if code, exists := raw["code"]; exists {
  871. codeStr := strings.TrimSpace(fmt.Sprintf("%v", code))
  872. if codeStr != "" {
  873. result.Code = codeStr
  874. }
  875. }
  876. if errType, ok := raw["type"].(string); ok {
  877. errType = strings.TrimSpace(errType)
  878. if errType != "" {
  879. result.Type = errType
  880. }
  881. }
  882. if skipRetry, ok := raw["skip_retry"].(bool); ok {
  883. result.SkipRetry = skipRetry
  884. }
  885. if statusCodeRaw, exists := raw["status_code"]; exists {
  886. statusCode, ok := parseOverrideInt(statusCodeRaw)
  887. if !ok {
  888. return nil, fmt.Errorf("return_error status_code must be an integer")
  889. }
  890. result.StatusCode = statusCode
  891. } else if statusRaw, exists := raw["status"]; exists {
  892. statusCode, ok := parseOverrideInt(statusRaw)
  893. if !ok {
  894. return nil, fmt.Errorf("return_error status must be an integer")
  895. }
  896. result.StatusCode = statusCode
  897. }
  898. default:
  899. return nil, fmt.Errorf("return_error value must be string or object")
  900. }
  901. if result.Message == "" {
  902. return nil, fmt.Errorf("return_error message is required")
  903. }
  904. if result.StatusCode < http.StatusContinue || result.StatusCode > http.StatusNetworkAuthenticationRequired {
  905. return nil, fmt.Errorf("return_error status code out of range: %d", result.StatusCode)
  906. }
  907. return result, nil
  908. }
  909. func parseOverrideInt(v interface{}) (int, bool) {
  910. switch value := v.(type) {
  911. case int:
  912. return value, true
  913. case float64:
  914. if value != float64(int(value)) {
  915. return 0, false
  916. }
  917. return int(value), true
  918. default:
  919. return 0, false
  920. }
  921. }
  922. func ensureContextMap(conditionContext map[string]interface{}) map[string]interface{} {
  923. if conditionContext != nil {
  924. return conditionContext
  925. }
  926. return make(map[string]interface{})
  927. }
  928. func marshalContextJSON(context map[string]interface{}) (string, error) {
  929. if context == nil || len(context) == 0 {
  930. return "", nil
  931. }
  932. ctxBytes, err := common.Marshal(context)
  933. if err != nil {
  934. return "", err
  935. }
  936. return string(ctxBytes), nil
  937. }
  938. func setHeaderOverrideInContext(context map[string]interface{}, headerName string, value interface{}, keepOrigin bool) error {
  939. headerName = normalizeHeaderContextKey(headerName)
  940. if headerName == "" {
  941. return fmt.Errorf("header name is required")
  942. }
  943. rawHeaders := ensureMapKeyInContext(context, paramOverrideContextHeaderOverride)
  944. if keepOrigin {
  945. if existing, ok := rawHeaders[headerName]; ok {
  946. existingValue := strings.TrimSpace(fmt.Sprintf("%v", existing))
  947. if existingValue != "" {
  948. return nil
  949. }
  950. }
  951. }
  952. headerValue, hasValue, err := resolveHeaderOverrideValue(context, headerName, value)
  953. if err != nil {
  954. return err
  955. }
  956. if !hasValue {
  957. delete(rawHeaders, headerName)
  958. return nil
  959. }
  960. rawHeaders[headerName] = headerValue
  961. return nil
  962. }
  963. func resolveHeaderOverrideValue(context map[string]interface{}, headerName string, value interface{}) (string, bool, error) {
  964. if value == nil {
  965. return "", false, fmt.Errorf("header value is required")
  966. }
  967. if mapping, ok := value.(map[string]interface{}); ok {
  968. return resolveHeaderOverrideValueByMapping(context, headerName, mapping)
  969. }
  970. if mapping, ok := value.(map[string]string); ok {
  971. converted := make(map[string]interface{}, len(mapping))
  972. for key, item := range mapping {
  973. converted[key] = item
  974. }
  975. return resolveHeaderOverrideValueByMapping(context, headerName, converted)
  976. }
  977. headerValue := strings.TrimSpace(fmt.Sprintf("%v", value))
  978. if headerValue == "" {
  979. return "", false, nil
  980. }
  981. return headerValue, true, nil
  982. }
  983. func resolveHeaderOverrideValueByMapping(context map[string]interface{}, headerName string, mapping map[string]interface{}) (string, bool, error) {
  984. if len(mapping) == 0 {
  985. return "", false, fmt.Errorf("header value mapping cannot be empty")
  986. }
  987. appendTokens, err := parseHeaderAppendTokens(mapping)
  988. if err != nil {
  989. return "", false, err
  990. }
  991. keepOnlyDeclared := parseHeaderKeepOnlyDeclared(mapping)
  992. sourceValue, exists := getHeaderValueFromContext(context, headerName)
  993. sourceTokens := make([]string, 0)
  994. if exists {
  995. sourceTokens = splitHeaderListValue(sourceValue)
  996. }
  997. wildcardValue, hasWildcard := mapping["*"]
  998. resultTokens := make([]string, 0, len(sourceTokens)+len(appendTokens))
  999. for _, token := range sourceTokens {
  1000. replacementRaw, hasReplacement := mapping[token]
  1001. if !hasReplacement && hasWildcard && !keepOnlyDeclared {
  1002. replacementRaw = wildcardValue
  1003. hasReplacement = true
  1004. }
  1005. if !hasReplacement {
  1006. if keepOnlyDeclared {
  1007. continue
  1008. }
  1009. resultTokens = append(resultTokens, token)
  1010. continue
  1011. }
  1012. replacementTokens, err := parseHeaderReplacementTokens(replacementRaw)
  1013. if err != nil {
  1014. return "", false, err
  1015. }
  1016. resultTokens = append(resultTokens, replacementTokens...)
  1017. }
  1018. resultTokens = append(resultTokens, appendTokens...)
  1019. resultTokens = lo.Uniq(resultTokens)
  1020. if len(resultTokens) == 0 {
  1021. return "", false, nil
  1022. }
  1023. return strings.Join(resultTokens, ","), true, nil
  1024. }
  1025. func parseHeaderAppendTokens(mapping map[string]interface{}) ([]string, error) {
  1026. appendRaw, ok := mapping["$append"]
  1027. if !ok {
  1028. return nil, nil
  1029. }
  1030. return parseHeaderReplacementTokens(appendRaw)
  1031. }
  1032. func parseHeaderKeepOnlyDeclared(mapping map[string]interface{}) bool {
  1033. keepOnlyDeclaredRaw, ok := mapping["$keep_only_declared"]
  1034. if !ok {
  1035. return false
  1036. }
  1037. keepOnlyDeclared, ok := keepOnlyDeclaredRaw.(bool)
  1038. if !ok {
  1039. return false
  1040. }
  1041. return keepOnlyDeclared
  1042. }
  1043. func parseHeaderReplacementTokens(value interface{}) ([]string, error) {
  1044. switch raw := value.(type) {
  1045. case nil:
  1046. return nil, nil
  1047. case string:
  1048. return splitHeaderListValue(raw), nil
  1049. case []string:
  1050. tokens := make([]string, 0, len(raw))
  1051. for _, item := range raw {
  1052. tokens = append(tokens, splitHeaderListValue(item)...)
  1053. }
  1054. return lo.Uniq(tokens), nil
  1055. case []interface{}:
  1056. tokens := make([]string, 0, len(raw))
  1057. for _, item := range raw {
  1058. itemTokens, err := parseHeaderReplacementTokens(item)
  1059. if err != nil {
  1060. return nil, err
  1061. }
  1062. tokens = append(tokens, itemTokens...)
  1063. }
  1064. return lo.Uniq(tokens), nil
  1065. case map[string]interface{}, map[string]string:
  1066. return nil, fmt.Errorf("header replacement value must be string, array or null")
  1067. default:
  1068. token := strings.TrimSpace(fmt.Sprintf("%v", raw))
  1069. if token == "" {
  1070. return nil, nil
  1071. }
  1072. return []string{token}, nil
  1073. }
  1074. }
  1075. func splitHeaderListValue(raw string) []string {
  1076. items := strings.Split(raw, ",")
  1077. return lo.FilterMap(items, func(item string, _ int) (string, bool) {
  1078. token := strings.TrimSpace(item)
  1079. if token == "" {
  1080. return "", false
  1081. }
  1082. return token, true
  1083. })
  1084. }
  1085. func copyHeaderInContext(context map[string]interface{}, fromHeader, toHeader string, keepOrigin bool) error {
  1086. fromHeader = normalizeHeaderContextKey(fromHeader)
  1087. toHeader = normalizeHeaderContextKey(toHeader)
  1088. if fromHeader == "" || toHeader == "" {
  1089. return fmt.Errorf("copy_header from/to is required")
  1090. }
  1091. value, exists := getHeaderValueFromContext(context, fromHeader)
  1092. if !exists {
  1093. return fmt.Errorf("%w: %s", errSourceHeaderNotFound, fromHeader)
  1094. }
  1095. return setHeaderOverrideInContext(context, toHeader, value, keepOrigin)
  1096. }
  1097. func moveHeaderInContext(context map[string]interface{}, fromHeader, toHeader string, keepOrigin bool) error {
  1098. fromHeader = normalizeHeaderContextKey(fromHeader)
  1099. toHeader = normalizeHeaderContextKey(toHeader)
  1100. if fromHeader == "" || toHeader == "" {
  1101. return fmt.Errorf("move_header from/to is required")
  1102. }
  1103. if err := copyHeaderInContext(context, fromHeader, toHeader, keepOrigin); err != nil {
  1104. return err
  1105. }
  1106. if strings.EqualFold(fromHeader, toHeader) {
  1107. return nil
  1108. }
  1109. return deleteHeaderOverrideInContext(context, fromHeader)
  1110. }
  1111. func deleteHeaderOverrideInContext(context map[string]interface{}, headerName string) error {
  1112. headerName = normalizeHeaderContextKey(headerName)
  1113. if headerName == "" {
  1114. return fmt.Errorf("header name is required")
  1115. }
  1116. rawHeaders := ensureMapKeyInContext(context, paramOverrideContextHeaderOverride)
  1117. delete(rawHeaders, headerName)
  1118. return nil
  1119. }
  1120. func parseHeaderPassThroughNames(value interface{}) ([]string, error) {
  1121. normalizeNames := func(values []string) []string {
  1122. names := lo.FilterMap(values, func(item string, _ int) (string, bool) {
  1123. headerName := normalizeHeaderContextKey(item)
  1124. if headerName == "" {
  1125. return "", false
  1126. }
  1127. return headerName, true
  1128. })
  1129. return lo.Uniq(names)
  1130. }
  1131. switch raw := value.(type) {
  1132. case nil:
  1133. return nil, fmt.Errorf("pass_headers value is required")
  1134. case string:
  1135. trimmed := strings.TrimSpace(raw)
  1136. if trimmed == "" {
  1137. return nil, fmt.Errorf("pass_headers value is required")
  1138. }
  1139. if strings.HasPrefix(trimmed, "[") || strings.HasPrefix(trimmed, "{") {
  1140. var parsed interface{}
  1141. if err := common.UnmarshalJsonStr(trimmed, &parsed); err == nil {
  1142. return parseHeaderPassThroughNames(parsed)
  1143. }
  1144. }
  1145. names := normalizeNames(strings.Split(trimmed, ","))
  1146. if len(names) == 0 {
  1147. return nil, fmt.Errorf("pass_headers value is invalid")
  1148. }
  1149. return names, nil
  1150. case []interface{}:
  1151. names := lo.FilterMap(raw, func(item interface{}, _ int) (string, bool) {
  1152. headerName := normalizeHeaderContextKey(fmt.Sprintf("%v", item))
  1153. if headerName == "" {
  1154. return "", false
  1155. }
  1156. return headerName, true
  1157. })
  1158. names = lo.Uniq(names)
  1159. if len(names) == 0 {
  1160. return nil, fmt.Errorf("pass_headers value is invalid")
  1161. }
  1162. return names, nil
  1163. case []string:
  1164. names := lo.FilterMap(raw, func(item string, _ int) (string, bool) {
  1165. headerName := normalizeHeaderContextKey(item)
  1166. if headerName == "" {
  1167. return "", false
  1168. }
  1169. return headerName, true
  1170. })
  1171. names = lo.Uniq(names)
  1172. if len(names) == 0 {
  1173. return nil, fmt.Errorf("pass_headers value is invalid")
  1174. }
  1175. return names, nil
  1176. case map[string]interface{}:
  1177. candidates := make([]string, 0, 8)
  1178. if headersRaw, ok := raw["headers"]; ok {
  1179. names, err := parseHeaderPassThroughNames(headersRaw)
  1180. if err == nil {
  1181. candidates = append(candidates, names...)
  1182. }
  1183. }
  1184. if namesRaw, ok := raw["names"]; ok {
  1185. names, err := parseHeaderPassThroughNames(namesRaw)
  1186. if err == nil {
  1187. candidates = append(candidates, names...)
  1188. }
  1189. }
  1190. if headerRaw, ok := raw["header"]; ok {
  1191. names, err := parseHeaderPassThroughNames(headerRaw)
  1192. if err == nil {
  1193. candidates = append(candidates, names...)
  1194. }
  1195. }
  1196. names := normalizeNames(candidates)
  1197. if len(names) == 0 {
  1198. return nil, fmt.Errorf("pass_headers value is invalid")
  1199. }
  1200. return names, nil
  1201. default:
  1202. return nil, fmt.Errorf("pass_headers value must be string, array or object")
  1203. }
  1204. }
  1205. type syncTarget struct {
  1206. kind string
  1207. key string
  1208. }
  1209. func parseSyncTarget(spec string) (syncTarget, error) {
  1210. raw := strings.TrimSpace(spec)
  1211. if raw == "" {
  1212. return syncTarget{}, fmt.Errorf("sync_fields target is required")
  1213. }
  1214. idx := strings.Index(raw, ":")
  1215. if idx < 0 {
  1216. // Backward compatibility: treat bare value as JSON path.
  1217. return syncTarget{
  1218. kind: "json",
  1219. key: raw,
  1220. }, nil
  1221. }
  1222. kind := strings.ToLower(strings.TrimSpace(raw[:idx]))
  1223. key := strings.TrimSpace(raw[idx+1:])
  1224. if key == "" {
  1225. return syncTarget{}, fmt.Errorf("sync_fields target key is required: %s", raw)
  1226. }
  1227. switch kind {
  1228. case "json", "body":
  1229. return syncTarget{
  1230. kind: "json",
  1231. key: key,
  1232. }, nil
  1233. case "header":
  1234. return syncTarget{
  1235. kind: "header",
  1236. key: key,
  1237. }, nil
  1238. default:
  1239. return syncTarget{}, fmt.Errorf("sync_fields target prefix is invalid: %s", raw)
  1240. }
  1241. }
  1242. func readSyncTargetValue(jsonStr string, context map[string]interface{}, target syncTarget) (interface{}, bool, error) {
  1243. switch target.kind {
  1244. case "json":
  1245. path := processNegativeIndex(jsonStr, target.key)
  1246. value := gjson.Get(jsonStr, path)
  1247. if !value.Exists() || value.Type == gjson.Null {
  1248. return nil, false, nil
  1249. }
  1250. if value.Type == gjson.String && strings.TrimSpace(value.String()) == "" {
  1251. return nil, false, nil
  1252. }
  1253. return value.Value(), true, nil
  1254. case "header":
  1255. value, ok := getHeaderValueFromContext(context, target.key)
  1256. if !ok || strings.TrimSpace(value) == "" {
  1257. return nil, false, nil
  1258. }
  1259. return value, true, nil
  1260. default:
  1261. return nil, false, fmt.Errorf("unsupported sync_fields target kind: %s", target.kind)
  1262. }
  1263. }
  1264. func writeSyncTargetValue(jsonStr string, context map[string]interface{}, target syncTarget, value interface{}) (string, error) {
  1265. switch target.kind {
  1266. case "json":
  1267. path := processNegativeIndex(jsonStr, target.key)
  1268. nextJSON, err := sjson.Set(jsonStr, path, value)
  1269. if err != nil {
  1270. return "", err
  1271. }
  1272. return nextJSON, nil
  1273. case "header":
  1274. if err := setHeaderOverrideInContext(context, target.key, value, false); err != nil {
  1275. return "", err
  1276. }
  1277. return jsonStr, nil
  1278. default:
  1279. return "", fmt.Errorf("unsupported sync_fields target kind: %s", target.kind)
  1280. }
  1281. }
  1282. func syncFieldsBetweenTargets(jsonStr string, context map[string]interface{}, fromSpec string, toSpec string) (string, error) {
  1283. fromTarget, err := parseSyncTarget(fromSpec)
  1284. if err != nil {
  1285. return "", err
  1286. }
  1287. toTarget, err := parseSyncTarget(toSpec)
  1288. if err != nil {
  1289. return "", err
  1290. }
  1291. fromValue, fromExists, err := readSyncTargetValue(jsonStr, context, fromTarget)
  1292. if err != nil {
  1293. return "", err
  1294. }
  1295. toValue, toExists, err := readSyncTargetValue(jsonStr, context, toTarget)
  1296. if err != nil {
  1297. return "", err
  1298. }
  1299. // If one side exists and the other side is missing, sync the missing side.
  1300. if fromExists && !toExists {
  1301. return writeSyncTargetValue(jsonStr, context, toTarget, fromValue)
  1302. }
  1303. if toExists && !fromExists {
  1304. return writeSyncTargetValue(jsonStr, context, fromTarget, toValue)
  1305. }
  1306. return jsonStr, nil
  1307. }
  1308. func ensureMapKeyInContext(context map[string]interface{}, key string) map[string]interface{} {
  1309. if context == nil {
  1310. return map[string]interface{}{}
  1311. }
  1312. if existing, ok := context[key]; ok {
  1313. if mapVal, ok := existing.(map[string]interface{}); ok {
  1314. return mapVal
  1315. }
  1316. }
  1317. result := make(map[string]interface{})
  1318. context[key] = result
  1319. return result
  1320. }
  1321. func getHeaderValueFromContext(context map[string]interface{}, headerName string) (string, bool) {
  1322. headerName = normalizeHeaderContextKey(headerName)
  1323. if headerName == "" {
  1324. return "", false
  1325. }
  1326. for _, key := range []string{paramOverrideContextHeaderOverride, paramOverrideContextRequestHeaders} {
  1327. source := ensureMapKeyInContext(context, key)
  1328. raw, ok := source[headerName]
  1329. if !ok {
  1330. continue
  1331. }
  1332. value := strings.TrimSpace(fmt.Sprintf("%v", raw))
  1333. if value != "" {
  1334. return value, true
  1335. }
  1336. }
  1337. return "", false
  1338. }
  1339. func normalizeHeaderContextKey(key string) string {
  1340. return strings.TrimSpace(strings.ToLower(key))
  1341. }
  1342. func buildRequestHeadersContext(headers map[string]string) map[string]interface{} {
  1343. if len(headers) == 0 {
  1344. return map[string]interface{}{}
  1345. }
  1346. entries := lo.Entries(headers)
  1347. normalizedEntries := lo.FilterMap(entries, func(item lo.Entry[string, string], _ int) (lo.Entry[string, string], bool) {
  1348. normalized := normalizeHeaderContextKey(item.Key)
  1349. value := strings.TrimSpace(item.Value)
  1350. if normalized == "" || value == "" {
  1351. return lo.Entry[string, string]{}, false
  1352. }
  1353. return lo.Entry[string, string]{Key: normalized, Value: value}, true
  1354. })
  1355. return lo.SliceToMap(normalizedEntries, func(item lo.Entry[string, string]) (string, interface{}) {
  1356. return item.Key, item.Value
  1357. })
  1358. }
  1359. func syncRuntimeHeaderOverrideFromContext(info *RelayInfo, context map[string]interface{}) {
  1360. if info == nil || context == nil {
  1361. return
  1362. }
  1363. raw, exists := context[paramOverrideContextHeaderOverride]
  1364. if !exists {
  1365. return
  1366. }
  1367. rawMap, ok := raw.(map[string]interface{})
  1368. if !ok {
  1369. return
  1370. }
  1371. info.RuntimeHeadersOverride = sanitizeHeaderOverrideMap(rawMap)
  1372. info.UseRuntimeHeadersOverride = true
  1373. }
  1374. func moveValue(jsonStr, fromPath, toPath string) (string, error) {
  1375. sourceValue := gjson.Get(jsonStr, fromPath)
  1376. if !sourceValue.Exists() {
  1377. return jsonStr, fmt.Errorf("source path does not exist: %s", fromPath)
  1378. }
  1379. result, err := sjson.Set(jsonStr, toPath, sourceValue.Value())
  1380. if err != nil {
  1381. return "", err
  1382. }
  1383. return sjson.Delete(result, fromPath)
  1384. }
  1385. func copyValue(jsonStr, fromPath, toPath string) (string, error) {
  1386. sourceValue := gjson.Get(jsonStr, fromPath)
  1387. if !sourceValue.Exists() {
  1388. return jsonStr, fmt.Errorf("source path does not exist: %s", fromPath)
  1389. }
  1390. return sjson.Set(jsonStr, toPath, sourceValue.Value())
  1391. }
  1392. func isPathBasedOperation(mode string) bool {
  1393. switch mode {
  1394. case "delete", "set", "prepend", "append", "trim_prefix", "trim_suffix", "ensure_prefix", "ensure_suffix", "trim_space", "to_lower", "to_upper", "replace", "regex_replace", "prune_objects":
  1395. return true
  1396. default:
  1397. return false
  1398. }
  1399. }
  1400. func resolveOperationPaths(jsonStr, path string) ([]string, error) {
  1401. if !strings.Contains(path, "*") {
  1402. return []string{path}, nil
  1403. }
  1404. return expandWildcardPaths(jsonStr, path)
  1405. }
  1406. func expandWildcardPaths(jsonStr, path string) ([]string, error) {
  1407. var root interface{}
  1408. if err := common.Unmarshal([]byte(jsonStr), &root); err != nil {
  1409. return nil, err
  1410. }
  1411. segments := strings.Split(path, ".")
  1412. paths := collectWildcardPaths(root, segments, nil)
  1413. return lo.Uniq(paths), nil
  1414. }
  1415. func collectWildcardPaths(node interface{}, segments []string, prefix []string) []string {
  1416. if len(segments) == 0 {
  1417. return []string{strings.Join(prefix, ".")}
  1418. }
  1419. segment := strings.TrimSpace(segments[0])
  1420. if segment == "" {
  1421. return nil
  1422. }
  1423. isLast := len(segments) == 1
  1424. if segment == "*" {
  1425. switch typed := node.(type) {
  1426. case map[string]interface{}:
  1427. keys := lo.Keys(typed)
  1428. sort.Strings(keys)
  1429. return lo.FlatMap(keys, func(key string, _ int) []string {
  1430. return collectWildcardPaths(typed[key], segments[1:], append(prefix, key))
  1431. })
  1432. case []interface{}:
  1433. return lo.FlatMap(lo.Range(len(typed)), func(index int, _ int) []string {
  1434. return collectWildcardPaths(typed[index], segments[1:], append(prefix, strconv.Itoa(index)))
  1435. })
  1436. default:
  1437. return nil
  1438. }
  1439. }
  1440. switch typed := node.(type) {
  1441. case map[string]interface{}:
  1442. if isLast {
  1443. return []string{strings.Join(append(prefix, segment), ".")}
  1444. }
  1445. next, exists := typed[segment]
  1446. if !exists {
  1447. return nil
  1448. }
  1449. return collectWildcardPaths(next, segments[1:], append(prefix, segment))
  1450. case []interface{}:
  1451. index, err := strconv.Atoi(segment)
  1452. if err != nil || index < 0 || index >= len(typed) {
  1453. return nil
  1454. }
  1455. if isLast {
  1456. return []string{strings.Join(append(prefix, segment), ".")}
  1457. }
  1458. return collectWildcardPaths(typed[index], segments[1:], append(prefix, segment))
  1459. default:
  1460. return nil
  1461. }
  1462. }
  1463. func deleteValue(jsonStr, path string) (string, error) {
  1464. if strings.TrimSpace(path) == "" {
  1465. return jsonStr, nil
  1466. }
  1467. return sjson.Delete(jsonStr, path)
  1468. }
  1469. func modifyValue(jsonStr, path string, value interface{}, keepOrigin, isPrepend bool) (string, error) {
  1470. current := gjson.Get(jsonStr, path)
  1471. switch {
  1472. case current.IsArray():
  1473. return modifyArray(jsonStr, path, value, isPrepend)
  1474. case current.Type == gjson.String:
  1475. return modifyString(jsonStr, path, value, isPrepend)
  1476. case current.Type == gjson.JSON:
  1477. return mergeObjects(jsonStr, path, value, keepOrigin)
  1478. }
  1479. return jsonStr, fmt.Errorf("operation not supported for type: %v", current.Type)
  1480. }
  1481. func modifyArray(jsonStr, path string, value interface{}, isPrepend bool) (string, error) {
  1482. current := gjson.Get(jsonStr, path)
  1483. var newArray []interface{}
  1484. // 添加新值
  1485. addValue := func() {
  1486. if arr, ok := value.([]interface{}); ok {
  1487. newArray = append(newArray, arr...)
  1488. } else {
  1489. newArray = append(newArray, value)
  1490. }
  1491. }
  1492. // 添加原值
  1493. addOriginal := func() {
  1494. current.ForEach(func(_, val gjson.Result) bool {
  1495. newArray = append(newArray, val.Value())
  1496. return true
  1497. })
  1498. }
  1499. if isPrepend {
  1500. addValue()
  1501. addOriginal()
  1502. } else {
  1503. addOriginal()
  1504. addValue()
  1505. }
  1506. return sjson.Set(jsonStr, path, newArray)
  1507. }
  1508. func modifyString(jsonStr, path string, value interface{}, isPrepend bool) (string, error) {
  1509. current := gjson.Get(jsonStr, path)
  1510. valueStr := fmt.Sprintf("%v", value)
  1511. var newStr string
  1512. if isPrepend {
  1513. newStr = valueStr + current.String()
  1514. } else {
  1515. newStr = current.String() + valueStr
  1516. }
  1517. return sjson.Set(jsonStr, path, newStr)
  1518. }
  1519. func trimStringValue(jsonStr, path string, value interface{}, isPrefix bool) (string, error) {
  1520. current := gjson.Get(jsonStr, path)
  1521. if current.Type != gjson.String {
  1522. return jsonStr, fmt.Errorf("operation not supported for type: %v", current.Type)
  1523. }
  1524. if value == nil {
  1525. return jsonStr, fmt.Errorf("trim value is required")
  1526. }
  1527. valueStr := fmt.Sprintf("%v", value)
  1528. var newStr string
  1529. if isPrefix {
  1530. newStr = strings.TrimPrefix(current.String(), valueStr)
  1531. } else {
  1532. newStr = strings.TrimSuffix(current.String(), valueStr)
  1533. }
  1534. return sjson.Set(jsonStr, path, newStr)
  1535. }
  1536. func ensureStringAffix(jsonStr, path string, value interface{}, isPrefix bool) (string, error) {
  1537. current := gjson.Get(jsonStr, path)
  1538. if current.Type != gjson.String {
  1539. return jsonStr, fmt.Errorf("operation not supported for type: %v", current.Type)
  1540. }
  1541. if value == nil {
  1542. return jsonStr, fmt.Errorf("ensure value is required")
  1543. }
  1544. valueStr := fmt.Sprintf("%v", value)
  1545. if valueStr == "" {
  1546. return jsonStr, fmt.Errorf("ensure value is required")
  1547. }
  1548. currentStr := current.String()
  1549. if isPrefix {
  1550. if strings.HasPrefix(currentStr, valueStr) {
  1551. return jsonStr, nil
  1552. }
  1553. return sjson.Set(jsonStr, path, valueStr+currentStr)
  1554. }
  1555. if strings.HasSuffix(currentStr, valueStr) {
  1556. return jsonStr, nil
  1557. }
  1558. return sjson.Set(jsonStr, path, currentStr+valueStr)
  1559. }
  1560. func transformStringValue(jsonStr, path string, transform func(string) string) (string, error) {
  1561. current := gjson.Get(jsonStr, path)
  1562. if current.Type != gjson.String {
  1563. return jsonStr, fmt.Errorf("operation not supported for type: %v", current.Type)
  1564. }
  1565. return sjson.Set(jsonStr, path, transform(current.String()))
  1566. }
  1567. func replaceStringValue(jsonStr, path, from, to string) (string, error) {
  1568. current := gjson.Get(jsonStr, path)
  1569. if current.Type != gjson.String {
  1570. return jsonStr, fmt.Errorf("operation not supported for type: %v", current.Type)
  1571. }
  1572. if from == "" {
  1573. return jsonStr, fmt.Errorf("replace from is required")
  1574. }
  1575. return sjson.Set(jsonStr, path, strings.ReplaceAll(current.String(), from, to))
  1576. }
  1577. func regexReplaceStringValue(jsonStr, path, pattern, replacement string) (string, error) {
  1578. current := gjson.Get(jsonStr, path)
  1579. if current.Type != gjson.String {
  1580. return jsonStr, fmt.Errorf("operation not supported for type: %v", current.Type)
  1581. }
  1582. if pattern == "" {
  1583. return jsonStr, fmt.Errorf("regex pattern is required")
  1584. }
  1585. re, err := regexp.Compile(pattern)
  1586. if err != nil {
  1587. return jsonStr, err
  1588. }
  1589. return sjson.Set(jsonStr, path, re.ReplaceAllString(current.String(), replacement))
  1590. }
  1591. type pruneObjectsOptions struct {
  1592. conditions []ConditionOperation
  1593. logic string
  1594. recursive bool
  1595. }
  1596. func pruneObjects(jsonStr, path, contextJSON string, value interface{}) (string, error) {
  1597. options, err := parsePruneObjectsOptions(value)
  1598. if err != nil {
  1599. return "", err
  1600. }
  1601. if path == "" {
  1602. var root interface{}
  1603. if err := common.Unmarshal([]byte(jsonStr), &root); err != nil {
  1604. return "", err
  1605. }
  1606. cleaned, _, err := pruneObjectsNode(root, options, contextJSON, true)
  1607. if err != nil {
  1608. return "", err
  1609. }
  1610. cleanedBytes, err := common.Marshal(cleaned)
  1611. if err != nil {
  1612. return "", err
  1613. }
  1614. return string(cleanedBytes), nil
  1615. }
  1616. target := gjson.Get(jsonStr, path)
  1617. if !target.Exists() {
  1618. return jsonStr, nil
  1619. }
  1620. var targetNode interface{}
  1621. if target.Type == gjson.JSON {
  1622. if err := common.Unmarshal([]byte(target.Raw), &targetNode); err != nil {
  1623. return "", err
  1624. }
  1625. } else {
  1626. targetNode = target.Value()
  1627. }
  1628. cleaned, _, err := pruneObjectsNode(targetNode, options, contextJSON, true)
  1629. if err != nil {
  1630. return "", err
  1631. }
  1632. cleanedBytes, err := common.Marshal(cleaned)
  1633. if err != nil {
  1634. return "", err
  1635. }
  1636. return sjson.SetRaw(jsonStr, path, string(cleanedBytes))
  1637. }
  1638. func parsePruneObjectsOptions(value interface{}) (pruneObjectsOptions, error) {
  1639. opts := pruneObjectsOptions{
  1640. logic: "AND",
  1641. recursive: true,
  1642. }
  1643. switch raw := value.(type) {
  1644. case nil:
  1645. return opts, fmt.Errorf("prune_objects value is required")
  1646. case string:
  1647. v := strings.TrimSpace(raw)
  1648. if v == "" {
  1649. return opts, fmt.Errorf("prune_objects value is required")
  1650. }
  1651. opts.conditions = []ConditionOperation{
  1652. {
  1653. Path: "type",
  1654. Mode: "full",
  1655. Value: v,
  1656. },
  1657. }
  1658. case map[string]interface{}:
  1659. if logic, ok := raw["logic"].(string); ok && strings.TrimSpace(logic) != "" {
  1660. opts.logic = logic
  1661. }
  1662. if recursive, ok := raw["recursive"].(bool); ok {
  1663. opts.recursive = recursive
  1664. }
  1665. if condRaw, exists := raw["conditions"]; exists {
  1666. conditions, err := parseConditionOperations(condRaw)
  1667. if err != nil {
  1668. return opts, err
  1669. }
  1670. opts.conditions = append(opts.conditions, conditions...)
  1671. }
  1672. if whereRaw, exists := raw["where"]; exists {
  1673. whereMap, ok := whereRaw.(map[string]interface{})
  1674. if !ok {
  1675. return opts, fmt.Errorf("prune_objects where must be object")
  1676. }
  1677. for key, val := range whereMap {
  1678. key = strings.TrimSpace(key)
  1679. if key == "" {
  1680. continue
  1681. }
  1682. opts.conditions = append(opts.conditions, ConditionOperation{
  1683. Path: key,
  1684. Mode: "full",
  1685. Value: val,
  1686. })
  1687. }
  1688. }
  1689. if matchType, exists := raw["type"]; exists {
  1690. opts.conditions = append(opts.conditions, ConditionOperation{
  1691. Path: "type",
  1692. Mode: "full",
  1693. Value: matchType,
  1694. })
  1695. }
  1696. default:
  1697. return opts, fmt.Errorf("prune_objects value must be string or object")
  1698. }
  1699. if len(opts.conditions) == 0 {
  1700. return opts, fmt.Errorf("prune_objects conditions are required")
  1701. }
  1702. return opts, nil
  1703. }
  1704. func parseConditionOperations(raw interface{}) ([]ConditionOperation, error) {
  1705. switch typed := raw.(type) {
  1706. case map[string]interface{}:
  1707. entries := lo.Entries(typed)
  1708. conditions := lo.FilterMap(entries, func(item lo.Entry[string, interface{}], _ int) (ConditionOperation, bool) {
  1709. path := strings.TrimSpace(item.Key)
  1710. if path == "" {
  1711. return ConditionOperation{}, false
  1712. }
  1713. return ConditionOperation{
  1714. Path: path,
  1715. Mode: "full",
  1716. Value: item.Value,
  1717. }, true
  1718. })
  1719. if len(conditions) == 0 {
  1720. return nil, fmt.Errorf("conditions object must contain at least one key")
  1721. }
  1722. return conditions, nil
  1723. case []interface{}:
  1724. items := typed
  1725. result := make([]ConditionOperation, 0, len(items))
  1726. for _, item := range items {
  1727. itemMap, ok := item.(map[string]interface{})
  1728. if !ok {
  1729. return nil, fmt.Errorf("condition must be object")
  1730. }
  1731. path, _ := itemMap["path"].(string)
  1732. mode, _ := itemMap["mode"].(string)
  1733. if strings.TrimSpace(path) == "" || strings.TrimSpace(mode) == "" {
  1734. return nil, fmt.Errorf("condition path/mode is required")
  1735. }
  1736. condition := ConditionOperation{
  1737. Path: path,
  1738. Mode: mode,
  1739. }
  1740. if value, exists := itemMap["value"]; exists {
  1741. condition.Value = value
  1742. }
  1743. if invert, ok := itemMap["invert"].(bool); ok {
  1744. condition.Invert = invert
  1745. }
  1746. if passMissingKey, ok := itemMap["pass_missing_key"].(bool); ok {
  1747. condition.PassMissingKey = passMissingKey
  1748. }
  1749. result = append(result, condition)
  1750. }
  1751. return result, nil
  1752. default:
  1753. return nil, fmt.Errorf("conditions must be an array or object")
  1754. }
  1755. }
  1756. func pruneObjectsNode(node interface{}, options pruneObjectsOptions, contextJSON string, isRoot bool) (interface{}, bool, error) {
  1757. switch value := node.(type) {
  1758. case []interface{}:
  1759. result := make([]interface{}, 0, len(value))
  1760. for _, item := range value {
  1761. next, drop, err := pruneObjectsNode(item, options, contextJSON, false)
  1762. if err != nil {
  1763. return nil, false, err
  1764. }
  1765. if drop {
  1766. continue
  1767. }
  1768. result = append(result, next)
  1769. }
  1770. return result, false, nil
  1771. case map[string]interface{}:
  1772. shouldDrop, err := shouldPruneObject(value, options, contextJSON)
  1773. if err != nil {
  1774. return nil, false, err
  1775. }
  1776. if shouldDrop && !isRoot {
  1777. return nil, true, nil
  1778. }
  1779. if !options.recursive {
  1780. return value, false, nil
  1781. }
  1782. for key, child := range value {
  1783. next, drop, err := pruneObjectsNode(child, options, contextJSON, false)
  1784. if err != nil {
  1785. return nil, false, err
  1786. }
  1787. if drop {
  1788. delete(value, key)
  1789. continue
  1790. }
  1791. value[key] = next
  1792. }
  1793. return value, false, nil
  1794. default:
  1795. return node, false, nil
  1796. }
  1797. }
  1798. func shouldPruneObject(node map[string]interface{}, options pruneObjectsOptions, contextJSON string) (bool, error) {
  1799. nodeBytes, err := common.Marshal(node)
  1800. if err != nil {
  1801. return false, err
  1802. }
  1803. return checkConditions(string(nodeBytes), contextJSON, options.conditions, options.logic)
  1804. }
  1805. func mergeObjects(jsonStr, path string, value interface{}, keepOrigin bool) (string, error) {
  1806. current := gjson.Get(jsonStr, path)
  1807. var currentMap, newMap map[string]interface{}
  1808. // 解析当前值
  1809. if err := common.Unmarshal([]byte(current.Raw), &currentMap); err != nil {
  1810. return "", err
  1811. }
  1812. // 解析新值
  1813. switch v := value.(type) {
  1814. case map[string]interface{}:
  1815. newMap = v
  1816. default:
  1817. jsonBytes, _ := common.Marshal(v)
  1818. if err := common.Unmarshal(jsonBytes, &newMap); err != nil {
  1819. return "", err
  1820. }
  1821. }
  1822. // 合并
  1823. result := make(map[string]interface{})
  1824. for k, v := range currentMap {
  1825. result[k] = v
  1826. }
  1827. for k, v := range newMap {
  1828. if !keepOrigin || result[k] == nil {
  1829. result[k] = v
  1830. }
  1831. }
  1832. return sjson.Set(jsonStr, path, result)
  1833. }
  1834. // BuildParamOverrideContext 提供 ApplyParamOverride 可用的上下文信息。
  1835. // 目前内置以下字段:
  1836. // - upstream_model/model:始终为通道映射后的上游模型名。
  1837. // - original_model:请求最初指定的模型名。
  1838. // - request_path:请求路径
  1839. // - is_channel_test:是否为渠道测试请求(同 is_test)。
  1840. func BuildParamOverrideContext(info *RelayInfo) map[string]interface{} {
  1841. if info == nil {
  1842. return nil
  1843. }
  1844. ctx := make(map[string]interface{})
  1845. if info.ChannelMeta != nil && info.ChannelMeta.UpstreamModelName != "" {
  1846. ctx["model"] = info.ChannelMeta.UpstreamModelName
  1847. ctx["upstream_model"] = info.ChannelMeta.UpstreamModelName
  1848. }
  1849. if info.OriginModelName != "" {
  1850. ctx["original_model"] = info.OriginModelName
  1851. if _, exists := ctx["model"]; !exists {
  1852. ctx["model"] = info.OriginModelName
  1853. }
  1854. }
  1855. if info.RequestURLPath != "" {
  1856. requestPath := info.RequestURLPath
  1857. if requestPath != "" {
  1858. ctx["request_path"] = requestPath
  1859. }
  1860. }
  1861. ctx[paramOverrideContextRequestHeaders] = buildRequestHeadersContext(info.RequestHeaders)
  1862. headerOverrideSource := GetEffectiveHeaderOverride(info)
  1863. ctx[paramOverrideContextHeaderOverride] = sanitizeHeaderOverrideMap(headerOverrideSource)
  1864. ctx["retry_index"] = info.RetryIndex
  1865. ctx["is_retry"] = info.RetryIndex > 0
  1866. ctx["retry"] = map[string]interface{}{
  1867. "index": info.RetryIndex,
  1868. "is_retry": info.RetryIndex > 0,
  1869. }
  1870. if info.LastError != nil {
  1871. code := string(info.LastError.GetErrorCode())
  1872. errorType := string(info.LastError.GetErrorType())
  1873. lastError := map[string]interface{}{
  1874. "status_code": info.LastError.StatusCode,
  1875. "message": info.LastError.Error(),
  1876. "code": code,
  1877. "error_code": code,
  1878. "type": errorType,
  1879. "error_type": errorType,
  1880. "skip_retry": types.IsSkipRetryError(info.LastError),
  1881. }
  1882. ctx["last_error"] = lastError
  1883. ctx["last_error_status_code"] = info.LastError.StatusCode
  1884. ctx["last_error_message"] = info.LastError.Error()
  1885. ctx["last_error_code"] = code
  1886. ctx["last_error_type"] = errorType
  1887. }
  1888. ctx["is_channel_test"] = info.IsChannelTest
  1889. return ctx
  1890. }