2020-09-28 16:25:49 +08:00
|
|
|
|
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" // 代理
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2021-06-09 21:43:58 +08:00
|
|
|
|
// HTTPRewriteRule 重写规则定义
|
2020-09-28 18:22:37 +08:00
|
|
|
|
// TODO 实现对其他代理服务的引用
|
2020-09-28 16:25:49 +08:00
|
|
|
|
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
|
2021-06-09 21:43:58 +08:00
|
|
|
|
Conds *shared.HTTPRequestCondsConfig `yaml:"conds" json:"conds"` // 匹配条件
|
2020-09-28 16:25:49 +08:00
|
|
|
|
|
|
|
|
|
|
// 规则
|
|
|
|
|
|
// 语法为: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"`
|
|
|
|
|
|
|
2020-09-28 18:22:37 +08:00
|
|
|
|
// 其他选项
|
|
|
|
|
|
IsBreak bool `yaml:"isBreak" json:"isBreak"` // 终止向下解析
|
|
|
|
|
|
WithQuery bool `yaml:"withQuery" json:"withQuery"` // 是否保留QueryString
|
2020-09-28 16:25:49 +08:00
|
|
|
|
|
2020-09-28 18:22:37 +08:00
|
|
|
|
reg *regexp.Regexp
|
|
|
|
|
|
replaceHasVariables bool
|
|
|
|
|
|
proxyHostHasVariables bool
|
2020-09-28 16:25:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-06-09 21:43:58 +08:00
|
|
|
|
// Init 校验
|
2020-09-28 16:25:49 +08:00
|
|
|
|
func (this *HTTPRewriteRule) Init() error {
|
2020-09-28 18:22:37 +08:00
|
|
|
|
this.replaceHasVariables = configutils.HasVariables(this.Replace)
|
|
|
|
|
|
this.proxyHostHasVariables = configutils.HasVariables(this.ProxyHost)
|
|
|
|
|
|
|
2020-09-28 16:25:49 +08:00
|
|
|
|
reg, err := regexp.Compile(this.Pattern)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
this.reg = reg
|
|
|
|
|
|
|
|
|
|
|
|
// 校验条件
|
2020-09-29 17:23:11 +08:00
|
|
|
|
if this.Conds != nil {
|
|
|
|
|
|
err := this.Conds.Init()
|
2020-09-28 16:25:49 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-06-09 21:43:58 +08:00
|
|
|
|
// MatchRequest 对某个请求执行规则
|
2020-09-29 17:23:11 +08:00
|
|
|
|
func (this *HTTPRewriteRule) MatchRequest(requestPath string, formatter func(source string) string) (replace string, varMapping map[string]string, matched bool) {
|
2020-09-28 16:25:49 +08:00
|
|
|
|
if this.reg == nil {
|
|
|
|
|
|
return "", nil, false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
matches := this.reg.FindStringSubmatch(requestPath)
|
|
|
|
|
|
if len(matches) == 0 {
|
|
|
|
|
|
return "", nil, false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 判断条件
|
2021-06-19 20:52:54 +08:00
|
|
|
|
if this.Conds != nil && this.Conds.HasRequestConds() && !this.Conds.MatchRequest(formatter) {
|
2020-09-29 17:23:11 +08:00
|
|
|
|
return "", nil, false
|
2020-09-28 16:25:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 + "}"
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2020-09-28 18:22:37 +08:00
|
|
|
|
if this.replaceHasVariables {
|
|
|
|
|
|
replace = formatter(replace)
|
|
|
|
|
|
}
|
2020-09-28 16:25:49 +08:00
|
|
|
|
|
|
|
|
|
|
return replace, varMapping, true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-06-09 21:43:58 +08:00
|
|
|
|
// IsExternalURL 判断是否是外部URL
|
2020-09-28 16:25:49 +08:00
|
|
|
|
func (this *HTTPRewriteRule) IsExternalURL(url string) bool {
|
|
|
|
|
|
return shared.RegexpExternalURL.MatchString(url)
|
|
|
|
|
|
}
|
2020-09-28 18:22:37 +08:00
|
|
|
|
|
2021-06-09 21:43:58 +08:00
|
|
|
|
// ProxyHostHasVariables 判断ProxyHost是否有变量
|
2020-09-28 18:22:37 +08:00
|
|
|
|
func (this *HTTPRewriteRule) ProxyHostHasVariables() bool {
|
|
|
|
|
|
return this.proxyHostHasVariables
|
|
|
|
|
|
}
|