in plugins/wasm-go/extensions/transformer/main.go [894:1011]
func (h kvHandler) handle(host, path string, kvs map[string][]string, mapSourceData map[string]MapSourceData) error {
// arbitary order. for example: remove → rename → replace → add → append → map → dedupe
for _, kvtOp := range h.kvtOps {
switch kvtOp.kvtOpType {
case RemoveK:
// remove
for _, remove := range kvtOp.removeKvtGroup {
delete(kvs, remove.key)
}
case RenameK:
// rename: 若指定 oldKey 不存在则无操作;否则将 oldKey 的值追加给 newKey,并删除 oldKey:value
for _, rename := range kvtOp.renameKvtGroup {
oldKey, newKey := rename.oldKey, rename.newKey
if ovs, ok := kvs[oldKey]; ok {
kvs[newKey] = append(kvs[newKey], ovs...)
delete(kvs, oldKey)
}
}
case ReplaceK:
// replace: 若指定 key 不存在,则无操作;否则替换 value 为 newValue
for _, replace := range kvtOp.replaceKvtGroup {
key, newValue := replace.key, replace.newValue
if _, ok := kvs[key]; !ok {
continue
}
if replace.reg != nil {
newValue = replace.reg.matchAndReplace(newValue, host, path)
}
kvs[replace.key] = []string{newValue}
}
case AddK:
// add: 若指定 key 存在则无操作;否则添加 key:value
for _, add := range kvtOp.addKvtGroup {
key, value := add.key, add.value
if _, ok := kvs[key]; ok {
continue
}
if add.reg != nil {
value = add.reg.matchAndReplace(value, host, path)
}
kvs[key] = []string{value}
}
case AppendK:
// append: 若指定 key 存在,则追加同名 kv;否则相当于添加操作
for _, append_ := range kvtOp.appendKvtGroup {
key, appendValue := append_.key, append_.appendValue
if append_.reg != nil {
appendValue = append_.reg.matchAndReplace(appendValue, host, path)
}
kvs[key] = append(kvs[key], appendValue)
}
case MapK:
// map: 若指定 fromKey 不存在则无操作;否则将 fromKey 的值映射给 toKey 的值
for _, map_ := range kvtOp.mapKvtGroup {
fromKey, toKey := map_.fromKey, map_.toKey
if kvtOp.mapSource == "headers" {
fromKey = strings.ToLower(fromKey)
}
source, exist := mapSourceData[kvtOp.mapSource]
if !exist {
proxywasm.LogWarnf("map key failed, source:%s not exists", kvtOp.mapSource)
continue
}
proxywasm.LogDebugf("search key:%s in source:%s", fromKey, kvtOp.mapSource)
if fromValue, ok := source.search(fromKey); ok {
switch source.mapSourceType {
case "headers", "querys", "bodyKv":
kvs[toKey] = fromValue.([]string)
proxywasm.LogDebugf("map key:%s to key:%s success, value is: %v", fromKey, toKey, fromValue)
case "bodyJson":
if valueJson, ok := fromValue.(gjson.Result); ok {
valueStr := valueJson.String()
if valueStr != "" {
kvs[toKey] = []string{valueStr}
proxywasm.LogDebugf("map key:%s to key:%s success, values is:%s", fromKey, toKey, valueStr)
}
}
}
}
}
case DedupeK:
// dedupe: 根据 strategy 去重:RETAIN_UNIQUE 保留所有唯一值,RETAIN_LAST 保留最后一个值,RETAIN_FIRST 保留第一个值 (default)
for _, dedupe := range kvtOp.dedupeKvtGroup {
key, strategy := dedupe.key, dedupe.strategy
switch strings.ToUpper(strategy) {
case "RETAIN_UNIQUE":
uniSet, uniques := make(map[string]struct{}), make([]string, 0)
for _, v := range kvs[key] {
if _, ok := uniSet[v]; !ok {
uniSet[v] = struct{}{}
uniques = append(uniques, v)
}
}
kvs[key] = uniques
case "RETAIN_LAST":
if vs, ok := kvs[key]; ok && len(vs) >= 1 {
kvs[key] = vs[len(vs)-1:]
}
case "RETAIN_FIRST":
fallthrough
default:
if vs, ok := kvs[key]; ok && len(vs) >= 1 {
kvs[key] = vs[:1]
}
}
}
}
}
return nil
}