Files
EdgeCommon/pkg/serverconfigs/http_rewrite_rule.go

131 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package serverconfigs
import (
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"regexp"
)
type HTTPRewriteMode = string
const (
HTTPRewriteTargetProxy = 1
HTTPRewriteTargetURL = 2
)
const (
HTTPRewriteModeRedirect HTTPRewriteMode = "redirect" // 跳转
HTTPRewriteModeProxy HTTPRewriteMode = "proxy" // 代理
)
// HTTPRewriteRule 重写规则定义
// TODO 实现对其他代理服务的引用
type HTTPRewriteRule struct {
Id int64 `yaml:"id" json:"id"` // ID
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
// 开启的条件
// 语法为cond param operator value 比如:
// - cond ${status} gte 200
// - cond ${arg.name} eq lily
// - cond ${requestPath} regexp .*\.png
Conds *shared.HTTPRequestCondsConfig `yaml:"conds" json:"conds"` // 匹配条件
// 规则
// 语法为pattern regexp 比如:
// - pattern ^/article/(\d+).html
Pattern string `yaml:"pattern" json:"pattern"`
// 模式
Mode HTTPRewriteMode `yaml:"mode" json:"mode"`
RedirectStatus int `yaml:"redirectStatus" json:"redirectStatus"` // 跳转的状态码
ProxyHost string `yaml:"proxyHost" json:"proxyHost"` // 代理模式下的Host
// 要替换成的URL
// 支持反向引用:${0}, ${1}, ...,也支持?P<NAME>语法
// - 如果以 proxy:// 开头表示目标为代理首先会尝试作为代理ID请求如果找不到会尝试作为代理Host请求
Replace string `yaml:"replace" json:"replace"`
// 其他选项
IsBreak bool `yaml:"isBreak" json:"isBreak"` // 终止向下解析
WithQuery bool `yaml:"withQuery" json:"withQuery"` // 是否保留QueryString
reg *regexp.Regexp
replaceHasVariables bool
proxyHostHasVariables bool
}
// Init 校验
func (this *HTTPRewriteRule) Init() error {
this.replaceHasVariables = configutils.HasVariables(this.Replace)
this.proxyHostHasVariables = configutils.HasVariables(this.ProxyHost)
reg, err := regexp.Compile(this.Pattern)
if err != nil {
return err
}
this.reg = reg
// 校验条件
if this.Conds != nil {
err := this.Conds.Init()
if err != nil {
return err
}
}
return nil
}
// MatchRequest 对某个请求执行规则
func (this *HTTPRewriteRule) MatchRequest(requestPath string, formatter func(source string) string) (replace string, varMapping map[string]string, matched bool) {
if this.reg == nil {
return "", nil, false
}
matches := this.reg.FindStringSubmatch(requestPath)
if len(matches) == 0 {
return "", nil, false
}
// 判断条件
if this.Conds != nil && this.Conds.HasRequestConds() && !this.Conds.MatchRequest(formatter) {
return "", nil, false
}
varMapping = map[string]string{}
subNames := this.reg.SubexpNames()
for index, match := range matches {
varMapping[fmt.Sprintf("%d", index)] = match
subName := subNames[index]
if len(subName) > 0 {
varMapping[subName] = match
}
}
replace = configutils.ParseVariables(this.Replace, func(varName string) string {
v, ok := varMapping[varName]
if ok {
return v
}
return "${" + varName + "}"
})
if this.replaceHasVariables {
replace = formatter(replace)
}
return replace, varMapping, true
}
// IsExternalURL 判断是否是外部URL
func (this *HTTPRewriteRule) IsExternalURL(url string) bool {
return shared.RegexpExternalURL.MatchString(url)
}
// ProxyHostHasVariables 判断ProxyHost是否有变量
func (this *HTTPRewriteRule) ProxyHostHasVariables() bool {
return this.proxyHostHasVariables
}