Files
higress/plugins/wasm-go/extensions/nginx-rewrite-compatible/pkg/config.go
2026-05-14 11:24:58 +08:00

110 lines
2.9 KiB
Go

package pkg
import (
"errors"
"fmt"
"regexp"
"strings"
"github.com/tidwall/gjson"
)
const (
ModeBreak = "break"
ModeLast = "last"
)
type PluginConfig struct {
Rules []Rule `json:"rules"`
}
type Rule struct {
Regex string `json:"regex"`
Replacement string `json:"replacement"`
QueryAppend string `json:"query_append,omitempty"`
QueryTemplate string `json:"query_template,omitempty"`
SetVars []SetVar `json:"set_vars,omitempty"`
PassToUpstream bool `json:"pass_to_upstream,omitempty"`
Mode string `json:"mode,omitempty"`
compiled *regexp.Regexp
}
type SetVar struct {
Name string `json:"name"`
CaptureGroup int `json:"capture_group"`
}
func (c *PluginConfig) FromJson(json gjson.Result) error {
rules := json.Get("rules")
if !rules.Exists() || !rules.IsArray() || len(rules.Array()) == 0 {
return errors.New("rules must be a non-empty array")
}
c.Rules = make([]Rule, 0, len(rules.Array()))
for i, item := range rules.Array() {
rule, err := parseRule(item)
if err != nil {
return fmt.Errorf("invalid rule %d: %w", i, err)
}
c.Rules = append(c.Rules, rule)
}
return nil
}
func parseRule(item gjson.Result) (Rule, error) {
rule := Rule{
Regex: item.Get("regex").String(),
Replacement: item.Get("replacement").String(),
QueryAppend: item.Get("query_append").String(),
QueryTemplate: item.Get("query_template").String(),
PassToUpstream: item.Get("pass_to_upstream").Bool(),
Mode: strings.ToLower(item.Get("mode").String()),
}
if rule.Regex == "" {
return Rule{}, errors.New("regex is required")
}
if rule.Replacement == "" {
return Rule{}, errors.New("replacement is required")
}
if rule.QueryAppend != "" && rule.QueryTemplate != "" {
return Rule{}, errors.New("query_append and query_template cannot be used together")
}
if rule.Mode == "" {
rule.Mode = ModeLast
}
if rule.Mode != ModeBreak && rule.Mode != ModeLast {
return Rule{}, fmt.Errorf("unsupported mode %q", rule.Mode)
}
compiled, err := regexp.Compile(rule.Regex)
if err != nil {
return Rule{}, fmt.Errorf("failed to compile regex: %w", err)
}
rule.compiled = compiled
setVars := item.Get("set_vars")
if setVars.Exists() {
if !setVars.IsArray() {
return Rule{}, errors.New("set_vars must be an array")
}
rule.SetVars = make([]SetVar, 0, len(setVars.Array()))
for i, setVarItem := range setVars.Array() {
setVar := SetVar{
Name: setVarItem.Get("name").String(),
CaptureGroup: int(setVarItem.Get("capture_group").Int()),
}
if setVar.Name == "" {
return Rule{}, fmt.Errorf("set_vars[%d].name is required", i)
}
if setVar.CaptureGroup < 0 || setVar.CaptureGroup > compiled.NumSubexp() {
return Rule{}, fmt.Errorf("set_vars[%d].capture_group=%d out of range", i, setVar.CaptureGroup)
}
rule.SetVars = append(rule.SetVars, setVar)
}
}
return rule, nil
}