2020-09-21 11:37:09 +08:00
|
|
|
|
package serverconfigs
|
|
|
|
|
|
|
2020-09-22 11:36:40 +08:00
|
|
|
|
import (
|
2023-03-18 22:15:13 +08:00
|
|
|
|
"context"
|
2020-09-26 08:07:24 +08:00
|
|
|
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
2020-09-22 11:36:40 +08:00
|
|
|
|
"regexp"
|
2020-09-26 08:07:24 +08:00
|
|
|
|
"strconv"
|
2020-09-22 11:36:40 +08:00
|
|
|
|
"strings"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2020-09-21 11:37:09 +08:00
|
|
|
|
type HTTPLocationConfig struct {
|
2020-09-26 08:07:24 +08:00
|
|
|
|
Id int64 `yaml:"id" json:"id"` // ID
|
|
|
|
|
|
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
|
|
|
|
|
|
Pattern string `yaml:"pattern" json:"pattern"` // 匹配规则 TODO 未来支持更多样的匹配规则
|
|
|
|
|
|
Name string `yaml:"name" json:"name"` // 名称
|
|
|
|
|
|
Web *HTTPWebConfig `yaml:"web" json:"web"` // Web配置
|
|
|
|
|
|
URLPrefix string `yaml:"urlPrefix" json:"urlPrefix"` // 实际的URL前缀,TODO 未来支持变量
|
|
|
|
|
|
Description string `yaml:"description" json:"description"` // 描述
|
|
|
|
|
|
ReverseProxyRef *ReverseProxyRef `yaml:"reverseProxyRef" json:"reverseProxyRef"` // 反向代理引用
|
|
|
|
|
|
ReverseProxy *ReverseProxyConfig `yaml:"reverseProxy" json:"reverseProxy"` // 反向代理设置
|
|
|
|
|
|
IsBreak bool `yaml:"isBreak" json:"isBreak"` // 终止向下解析
|
|
|
|
|
|
Children []*HTTPLocationConfig `yaml:"children" json:"children"` // 子规则
|
2021-06-09 21:43:58 +08:00
|
|
|
|
Conds *shared.HTTPRequestCondsConfig `yaml:"conds" json:"conds"` // 匹配条件
|
2021-12-12 16:38:18 +08:00
|
|
|
|
Domains []string `yaml:"domains" json:"domains"` // 所属域名
|
2020-09-22 11:36:40 +08:00
|
|
|
|
|
|
|
|
|
|
patternType HTTPLocationPatternType // 规则类型:LocationPattern*
|
|
|
|
|
|
prefix string // 前缀
|
2021-05-10 21:13:47 +08:00
|
|
|
|
suffix string // 后缀
|
2020-09-22 11:36:40 +08:00
|
|
|
|
path string // 精确的路径
|
|
|
|
|
|
|
|
|
|
|
|
reg *regexp.Regexp // 匹配规则
|
|
|
|
|
|
caseInsensitive bool // 大小写不敏感
|
|
|
|
|
|
reverse bool // 是否翻转规则,比如非前缀,非路径
|
2020-09-21 11:37:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-18 22:15:13 +08:00
|
|
|
|
func (this *HTTPLocationConfig) Init(ctx context.Context) error {
|
2021-05-10 21:13:47 +08:00
|
|
|
|
err := this.ExtractPattern()
|
2020-09-22 11:36:40 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-21 11:37:09 +08:00
|
|
|
|
if this.Web != nil {
|
2023-03-18 22:15:13 +08:00
|
|
|
|
err := this.Web.Init(ctx)
|
2020-09-21 11:37:09 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-26 19:54:20 +08:00
|
|
|
|
if this.ReverseProxyRef != nil {
|
|
|
|
|
|
err := this.ReverseProxyRef.Init()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-21 11:37:09 +08:00
|
|
|
|
if this.ReverseProxy != nil {
|
2023-03-18 22:15:13 +08:00
|
|
|
|
err := this.ReverseProxy.Init(ctx)
|
2020-09-21 11:37:09 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-22 11:36:40 +08:00
|
|
|
|
// Children
|
|
|
|
|
|
for _, child := range this.Children {
|
2023-03-18 22:15:13 +08:00
|
|
|
|
err := child.Init(ctx)
|
2020-09-22 11:36:40 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-26 08:07:24 +08:00
|
|
|
|
// conds
|
2020-09-29 17:23:11 +08:00
|
|
|
|
if this.Conds != nil {
|
|
|
|
|
|
err := this.Conds.Init()
|
2020-09-26 08:07:24 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-21 11:37:09 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2020-09-21 19:52:10 +08:00
|
|
|
|
|
2021-05-10 21:13:47 +08:00
|
|
|
|
// SetPattern 组合参数为一个字符串
|
2020-09-21 19:52:10 +08:00
|
|
|
|
func (this *HTTPLocationConfig) SetPattern(pattern string, patternType int, caseInsensitive bool, reverse bool) {
|
|
|
|
|
|
op := ""
|
|
|
|
|
|
if patternType == HTTPLocationPatternTypePrefix {
|
|
|
|
|
|
if caseInsensitive {
|
|
|
|
|
|
op = "*"
|
|
|
|
|
|
if reverse {
|
|
|
|
|
|
op = "!*"
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if reverse {
|
|
|
|
|
|
op = "!"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-05-10 21:13:47 +08:00
|
|
|
|
} else if patternType == HTTPLocationPatternTypeSuffix {
|
|
|
|
|
|
op = "suffix"
|
|
|
|
|
|
if caseInsensitive {
|
|
|
|
|
|
op += "*"
|
|
|
|
|
|
}
|
|
|
|
|
|
if reverse {
|
|
|
|
|
|
op = "!" + op
|
|
|
|
|
|
}
|
2020-09-21 19:52:10 +08:00
|
|
|
|
} else if patternType == HTTPLocationPatternTypeExact {
|
|
|
|
|
|
op = "="
|
|
|
|
|
|
if caseInsensitive {
|
|
|
|
|
|
op += "*"
|
|
|
|
|
|
}
|
|
|
|
|
|
if reverse {
|
|
|
|
|
|
op = "!" + op
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if patternType == HTTPLocationPatternTypeRegexp {
|
|
|
|
|
|
op = "~"
|
|
|
|
|
|
if caseInsensitive {
|
|
|
|
|
|
op += "*"
|
|
|
|
|
|
}
|
|
|
|
|
|
if reverse {
|
|
|
|
|
|
op = "!" + op
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(op) > 0 {
|
|
|
|
|
|
pattern = op + " " + pattern
|
|
|
|
|
|
}
|
|
|
|
|
|
this.Pattern = pattern
|
|
|
|
|
|
}
|
2020-09-22 11:36:40 +08:00
|
|
|
|
|
2021-05-10 21:13:47 +08:00
|
|
|
|
// PatternType 模式类型
|
2020-09-22 11:36:40 +08:00
|
|
|
|
func (this *HTTPLocationConfig) PatternType() int {
|
|
|
|
|
|
return this.patternType
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-10 21:13:47 +08:00
|
|
|
|
// PatternString 模式字符串
|
2020-09-22 11:36:40 +08:00
|
|
|
|
// 去掉了模式字符
|
|
|
|
|
|
func (this *HTTPLocationConfig) PatternString() string {
|
|
|
|
|
|
if this.patternType == HTTPLocationPatternTypePrefix {
|
|
|
|
|
|
return this.prefix
|
|
|
|
|
|
}
|
2021-05-10 21:13:47 +08:00
|
|
|
|
if this.patternType == HTTPLocationPatternTypeSuffix {
|
|
|
|
|
|
return this.suffix
|
|
|
|
|
|
}
|
2020-09-22 11:36:40 +08:00
|
|
|
|
return this.path
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-10 21:13:47 +08:00
|
|
|
|
// IsReverse 是否翻转
|
2020-09-22 11:36:40 +08:00
|
|
|
|
func (this *HTTPLocationConfig) IsReverse() bool {
|
|
|
|
|
|
return this.reverse
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-10 21:13:47 +08:00
|
|
|
|
// IsCaseInsensitive 是否大小写非敏感
|
2020-09-22 11:36:40 +08:00
|
|
|
|
func (this *HTTPLocationConfig) IsCaseInsensitive() bool {
|
|
|
|
|
|
return this.caseInsensitive
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-10 21:13:47 +08:00
|
|
|
|
// ExtractPattern 分析匹配条件
|
|
|
|
|
|
func (this *HTTPLocationConfig) ExtractPattern() error {
|
2020-09-22 11:36:40 +08:00
|
|
|
|
// 分析pattern
|
|
|
|
|
|
this.reverse = false
|
|
|
|
|
|
this.caseInsensitive = false
|
|
|
|
|
|
if len(this.Pattern) > 0 {
|
|
|
|
|
|
spaceIndex := strings.Index(this.Pattern, " ")
|
|
|
|
|
|
if spaceIndex < 0 {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypePrefix
|
|
|
|
|
|
this.prefix = this.Pattern
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cmd := this.Pattern[:spaceIndex]
|
|
|
|
|
|
pattern := strings.TrimSpace(this.Pattern[spaceIndex+1:])
|
|
|
|
|
|
if cmd == "*" { // 大小写非敏感
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypePrefix
|
|
|
|
|
|
this.prefix = pattern
|
|
|
|
|
|
this.caseInsensitive = true
|
|
|
|
|
|
} else if cmd == "!*" { // 大小写非敏感,翻转
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypePrefix
|
|
|
|
|
|
this.prefix = pattern
|
|
|
|
|
|
this.caseInsensitive = true
|
|
|
|
|
|
this.reverse = true
|
|
|
|
|
|
} else if cmd == "!" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypePrefix
|
|
|
|
|
|
this.prefix = pattern
|
|
|
|
|
|
this.reverse = true
|
|
|
|
|
|
} else if cmd == "=" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeExact
|
|
|
|
|
|
this.path = pattern
|
|
|
|
|
|
} else if cmd == "=*" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeExact
|
|
|
|
|
|
this.path = pattern
|
|
|
|
|
|
this.caseInsensitive = true
|
|
|
|
|
|
} else if cmd == "!=" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeExact
|
|
|
|
|
|
this.path = pattern
|
|
|
|
|
|
this.reverse = true
|
|
|
|
|
|
} else if cmd == "!=*" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeExact
|
|
|
|
|
|
this.path = pattern
|
|
|
|
|
|
this.reverse = true
|
|
|
|
|
|
this.caseInsensitive = true
|
|
|
|
|
|
} else if cmd == "~" { // 正则
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeRegexp
|
|
|
|
|
|
reg, err := regexp.Compile(pattern)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
this.reg = reg
|
|
|
|
|
|
this.path = pattern
|
|
|
|
|
|
} else if cmd == "!~" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeRegexp
|
|
|
|
|
|
reg, err := regexp.Compile(pattern)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
this.reg = reg
|
|
|
|
|
|
this.reverse = true
|
|
|
|
|
|
this.path = pattern
|
|
|
|
|
|
} else if cmd == "~*" { // 大小写非敏感小写
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeRegexp
|
|
|
|
|
|
reg, err := regexp.Compile("(?i)" + pattern)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
this.reg = reg
|
|
|
|
|
|
this.caseInsensitive = true
|
|
|
|
|
|
this.path = pattern
|
|
|
|
|
|
} else if cmd == "!~*" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeRegexp
|
|
|
|
|
|
reg, err := regexp.Compile("(?i)" + pattern)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
this.reg = reg
|
|
|
|
|
|
this.reverse = true
|
|
|
|
|
|
this.caseInsensitive = true
|
|
|
|
|
|
this.path = pattern
|
2021-05-10 21:13:47 +08:00
|
|
|
|
} else if cmd == "suffix" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeSuffix
|
|
|
|
|
|
this.suffix = pattern
|
|
|
|
|
|
} else if cmd == "suffix*" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeSuffix
|
|
|
|
|
|
this.caseInsensitive = true
|
|
|
|
|
|
this.suffix = pattern
|
|
|
|
|
|
} else if cmd == "!suffix" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeSuffix
|
|
|
|
|
|
this.reverse = true
|
|
|
|
|
|
this.suffix = pattern
|
|
|
|
|
|
} else if cmd == "!suffix*" {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypeSuffix
|
|
|
|
|
|
this.caseInsensitive = true
|
|
|
|
|
|
this.reverse = true
|
|
|
|
|
|
this.suffix = pattern
|
2020-09-22 11:36:40 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypePrefix
|
|
|
|
|
|
this.prefix = pattern
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.patternType = HTTPLocationPatternTypePrefix
|
|
|
|
|
|
this.prefix = this.Pattern
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2020-09-26 08:07:24 +08:00
|
|
|
|
|
2021-05-10 21:13:47 +08:00
|
|
|
|
// Match 判断是否匹配路径
|
2020-09-26 08:07:24 +08:00
|
|
|
|
// TODO 支持子Location
|
|
|
|
|
|
func (this *HTTPLocationConfig) Match(path string, formatter func(source string) string) (vars map[string]string, isMatched bool) {
|
|
|
|
|
|
// 判断条件
|
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
|
2020-09-26 08:07:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if this.patternType == HTTPLocationPatternTypePrefix {
|
|
|
|
|
|
if this.reverse {
|
|
|
|
|
|
if this.caseInsensitive {
|
|
|
|
|
|
return nil, !strings.HasPrefix(strings.ToLower(path), strings.ToLower(this.prefix))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return nil, !strings.HasPrefix(path, this.prefix)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if this.caseInsensitive {
|
|
|
|
|
|
return nil, strings.HasPrefix(strings.ToLower(path), strings.ToLower(this.prefix))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return nil, strings.HasPrefix(path, this.prefix)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-10 21:13:47 +08:00
|
|
|
|
if this.patternType == HTTPLocationPatternTypeSuffix {
|
|
|
|
|
|
if this.reverse {
|
|
|
|
|
|
if this.caseInsensitive {
|
|
|
|
|
|
return nil, !strings.HasSuffix(strings.ToLower(path), strings.ToLower(this.suffix))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return nil, !strings.HasSuffix(path, this.suffix)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if this.caseInsensitive {
|
|
|
|
|
|
return nil, strings.HasSuffix(strings.ToLower(path), strings.ToLower(this.suffix))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return nil, strings.HasSuffix(path, this.suffix)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-26 08:07:24 +08:00
|
|
|
|
if this.patternType == HTTPLocationPatternTypeExact {
|
|
|
|
|
|
if this.reverse {
|
|
|
|
|
|
if this.caseInsensitive {
|
2023-08-08 15:12:28 +08:00
|
|
|
|
return nil, !strings.EqualFold(path, this.path)
|
2020-09-26 08:07:24 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
return nil, path != this.path
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if this.caseInsensitive {
|
2023-08-08 15:12:28 +08:00
|
|
|
|
return nil, strings.EqualFold(path, this.path)
|
2020-09-26 08:07:24 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
return nil, path == this.path
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO 正则表达式匹配会让请求延迟0.01-0.02ms,可以使用缓存加速正则匹配,因为大部分路径都是不变的
|
|
|
|
|
|
if this.patternType == HTTPLocationPatternTypeRegexp {
|
|
|
|
|
|
if this.reg != nil {
|
|
|
|
|
|
if this.reverse {
|
|
|
|
|
|
return nil, !this.reg.MatchString(path)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
b := this.reg.MatchString(path)
|
|
|
|
|
|
if b {
|
|
|
|
|
|
result := map[string]string{}
|
|
|
|
|
|
matches := this.reg.FindStringSubmatch(path)
|
|
|
|
|
|
subNames := this.reg.SubexpNames()
|
|
|
|
|
|
for index, value := range matches {
|
|
|
|
|
|
result[strconv.Itoa(index)] = value
|
|
|
|
|
|
subName := subNames[index]
|
|
|
|
|
|
if len(subName) > 0 {
|
|
|
|
|
|
result[subName] = value
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result, true
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil, b
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil, this.reverse
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil, false
|
|
|
|
|
|
}
|