mirror of
https://github.com/TeaOSLab/EdgeCommon.git
synced 2026-04-21 12:15:19 +08:00
服务支持fastcgi;路径规则支持匹配后缀
This commit is contained in:
167
pkg/serverconfigs/http_fastcgi_config.go
Normal file
167
pkg/serverconfigs/http_fastcgi_config.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
// HTTPFastcgiParam Fastcgi参数
|
||||
type HTTPFastcgiParam struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Value string `yaml:"value" json:"value"`
|
||||
}
|
||||
|
||||
// HTTPFastcgiConfig Fastcgi配置
|
||||
type HTTPFastcgiConfig struct {
|
||||
Id int64 `yaml:"id" json:"id"`
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
|
||||
// fastcgi地址配置
|
||||
// 支持unix:/tmp/php-fpm.sock ...
|
||||
Address string `yaml:"address" json:"address"`
|
||||
|
||||
Index string `yaml:"index" json:"index"` // @TODO
|
||||
Params []*HTTPFastcgiParam `yaml:"params" json:"params"` // 参数
|
||||
ReadTimeout *shared.TimeDuration `yaml:"readTimeout" json:"readTimeout"` // @TODO 读取超时时间
|
||||
SendTimeout *shared.TimeDuration `yaml:"sendTimeout" json:"sendTimeout"` // @TODO 发送超时时间
|
||||
ConnTimeout *shared.TimeDuration `yaml:"connTimeout" json:"connTimeout"` // @TODO 连接超时时间
|
||||
Weight int `yaml:"weight" json:"weight"` // TODO 权重
|
||||
PoolSize int `yaml:"poolSize" json:"poolSize"` // 连接池尺寸
|
||||
PathInfoPattern string `yaml:"pathInfoPattern" json:"pathInfoPattern"` // PATH_INFO匹配正则
|
||||
|
||||
network string // 协议:tcp, unix
|
||||
address string // 地址
|
||||
|
||||
paramsMap maps.Map
|
||||
readTimeout time.Duration
|
||||
connTimeout time.Duration
|
||||
pathInfoRegexp *regexp.Regexp
|
||||
}
|
||||
|
||||
// Init 初始化
|
||||
func (this *HTTPFastcgiConfig) Init() error {
|
||||
params := map[string]string{}
|
||||
for _, p := range this.Params {
|
||||
params[p.Name] = p.Value
|
||||
}
|
||||
this.paramsMap = maps.NewMap(params)
|
||||
if !this.paramsMap.Has("SCRIPT_FILENAME") {
|
||||
this.paramsMap["SCRIPT_FILENAME"] = ""
|
||||
}
|
||||
if !this.paramsMap.Has("REDIRECT_STATUS") {
|
||||
this.paramsMap["REDIRECT_STATUS"] = "200"
|
||||
}
|
||||
if !this.paramsMap.Has("GATEWAY_INTERFACE") {
|
||||
this.paramsMap["GATEWAY_INTERFACE"] = "CGI/1.1"
|
||||
}
|
||||
|
||||
// 校验地址
|
||||
if regexp.MustCompile("^\\d+$").MatchString(this.Address) {
|
||||
this.network = "tcp"
|
||||
this.address = "127.0.0.1:" + this.Address
|
||||
} else if regexp.MustCompile("^(.*):(\\d+)$").MatchString(this.Address) {
|
||||
matches := regexp.MustCompile("^(.*):(\\d+)$").FindStringSubmatch(this.Address)
|
||||
ip := matches[1]
|
||||
port := matches[2]
|
||||
if len(ip) == 0 {
|
||||
ip = "127.0.0.1"
|
||||
}
|
||||
this.network = "tcp"
|
||||
this.address = ip + ":" + port
|
||||
} else if regexp.MustCompile("^\\d+\\.\\d+.\\d+.\\d+$").MatchString(this.Address) {
|
||||
this.network = "tcp"
|
||||
this.address = this.Address + ":9000"
|
||||
} else if regexp.MustCompile("^unix:(.+)$").MatchString(this.Address) {
|
||||
matches := regexp.MustCompile("^unix:(.+)$").FindStringSubmatch(this.Address)
|
||||
path := matches[1]
|
||||
this.network = "unix"
|
||||
this.address = path
|
||||
} else if regexp.MustCompile("^[./].+$").MatchString(this.Address) {
|
||||
this.network = "unix"
|
||||
this.address = this.Address
|
||||
} else {
|
||||
return errors.New("invalid 'pass' format")
|
||||
}
|
||||
|
||||
// 超时时间
|
||||
if this.ReadTimeout != nil {
|
||||
this.readTimeout = this.ReadTimeout.Duration()
|
||||
} else {
|
||||
this.readTimeout = 3 * time.Second
|
||||
}
|
||||
|
||||
if this.ConnTimeout != nil {
|
||||
this.connTimeout = this.ConnTimeout.Duration()
|
||||
} else {
|
||||
this.connTimeout = 10 * time.Second
|
||||
}
|
||||
|
||||
// PATH_INFO
|
||||
if len(this.PathInfoPattern) > 0 {
|
||||
reg, err := regexp.Compile(this.PathInfoPattern)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.pathInfoRegexp = reg
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FilterParams 过滤参数
|
||||
func (this *HTTPFastcgiConfig) FilterParams() maps.Map {
|
||||
params := maps.NewMap(this.paramsMap)
|
||||
|
||||
// 自动添加参数
|
||||
script := params.GetString("SCRIPT_FILENAME")
|
||||
if len(script) > 0 {
|
||||
if !params.Has("SCRIPT_NAME") {
|
||||
params["SCRIPT_NAME"] = filepath.Base(script)
|
||||
}
|
||||
if !params.Has("DOCUMENT_ROOT") {
|
||||
params["DOCUMENT_ROOT"] = filepath.Dir(script)
|
||||
}
|
||||
if !params.Has("PWD") {
|
||||
params["PWD"] = filepath.Dir(script)
|
||||
}
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
// ReadTimeoutDuration 超时时间
|
||||
func (this *HTTPFastcgiConfig) ReadTimeoutDuration() time.Duration {
|
||||
if this.readTimeout <= 0 {
|
||||
this.readTimeout = 30 * time.Second
|
||||
}
|
||||
return this.readTimeout
|
||||
}
|
||||
|
||||
// Network 网络协议
|
||||
func (this *HTTPFastcgiConfig) Network() string {
|
||||
return this.network
|
||||
}
|
||||
|
||||
// RealAddress 网络地址
|
||||
func (this *HTTPFastcgiConfig) RealAddress() string {
|
||||
return this.address
|
||||
}
|
||||
|
||||
// Param 读取参数
|
||||
func (this *HTTPFastcgiConfig) Param(paramName string) string {
|
||||
for _, p := range this.Params {
|
||||
if p.Name == paramName {
|
||||
return p.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// PathInfoRegexp PATH_INFO正则
|
||||
func (this *HTTPFastcgiConfig) PathInfoRegexp() *regexp.Regexp {
|
||||
return this.pathInfoRegexp
|
||||
}
|
||||
9
pkg/serverconfigs/http_fastcgi_ref.go
Normal file
9
pkg/serverconfigs/http_fastcgi_ref.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package serverconfigs
|
||||
|
||||
type HTTPFastcgiRef struct {
|
||||
IsPrior bool `yaml:"isPrior" json:"isPrior"` // 是否覆盖
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
|
||||
FastcgiIds []int64 `yaml:"fastcgiIds" json:"fastcgiIds"` // Fastcgi ID列表
|
||||
}
|
||||
@@ -23,6 +23,7 @@ type HTTPLocationConfig struct {
|
||||
|
||||
patternType HTTPLocationPatternType // 规则类型:LocationPattern*
|
||||
prefix string // 前缀
|
||||
suffix string // 后缀
|
||||
path string // 精确的路径
|
||||
|
||||
reg *regexp.Regexp // 匹配规则
|
||||
@@ -31,7 +32,7 @@ type HTTPLocationConfig struct {
|
||||
}
|
||||
|
||||
func (this *HTTPLocationConfig) Init() error {
|
||||
err := this.parsePattern()
|
||||
err := this.ExtractPattern()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -76,7 +77,7 @@ func (this *HTTPLocationConfig) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 组合参数为一个字符串
|
||||
// SetPattern 组合参数为一个字符串
|
||||
func (this *HTTPLocationConfig) SetPattern(pattern string, patternType int, caseInsensitive bool, reverse bool) {
|
||||
op := ""
|
||||
if patternType == HTTPLocationPatternTypePrefix {
|
||||
@@ -90,6 +91,14 @@ func (this *HTTPLocationConfig) SetPattern(pattern string, patternType int, case
|
||||
op = "!"
|
||||
}
|
||||
}
|
||||
} else if patternType == HTTPLocationPatternTypeSuffix {
|
||||
op = "suffix"
|
||||
if caseInsensitive {
|
||||
op += "*"
|
||||
}
|
||||
if reverse {
|
||||
op = "!" + op
|
||||
}
|
||||
} else if patternType == HTTPLocationPatternTypeExact {
|
||||
op = "="
|
||||
if caseInsensitive {
|
||||
@@ -113,32 +122,35 @@ func (this *HTTPLocationConfig) SetPattern(pattern string, patternType int, case
|
||||
this.Pattern = pattern
|
||||
}
|
||||
|
||||
// 模式类型
|
||||
// PatternType 模式类型
|
||||
func (this *HTTPLocationConfig) PatternType() int {
|
||||
return this.patternType
|
||||
}
|
||||
|
||||
// 模式字符串
|
||||
// PatternString 模式字符串
|
||||
// 去掉了模式字符
|
||||
func (this *HTTPLocationConfig) PatternString() string {
|
||||
if this.patternType == HTTPLocationPatternTypePrefix {
|
||||
return this.prefix
|
||||
}
|
||||
if this.patternType == HTTPLocationPatternTypeSuffix {
|
||||
return this.suffix
|
||||
}
|
||||
return this.path
|
||||
}
|
||||
|
||||
// 是否翻转
|
||||
// IsReverse 是否翻转
|
||||
func (this *HTTPLocationConfig) IsReverse() bool {
|
||||
return this.reverse
|
||||
}
|
||||
|
||||
// 是否大小写非敏感
|
||||
// IsCaseInsensitive 是否大小写非敏感
|
||||
func (this *HTTPLocationConfig) IsCaseInsensitive() bool {
|
||||
return this.caseInsensitive
|
||||
}
|
||||
|
||||
// 分析匹配条件
|
||||
func (this *HTTPLocationConfig) parsePattern() error {
|
||||
// ExtractPattern 分析匹配条件
|
||||
func (this *HTTPLocationConfig) ExtractPattern() error {
|
||||
// 分析pattern
|
||||
this.reverse = false
|
||||
this.caseInsensitive = false
|
||||
@@ -215,6 +227,22 @@ func (this *HTTPLocationConfig) parsePattern() error {
|
||||
this.reverse = true
|
||||
this.caseInsensitive = true
|
||||
this.path = pattern
|
||||
} 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
|
||||
} else {
|
||||
this.patternType = HTTPLocationPatternTypePrefix
|
||||
this.prefix = pattern
|
||||
@@ -228,7 +256,7 @@ func (this *HTTPLocationConfig) parsePattern() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断是否匹配路径
|
||||
// Match 判断是否匹配路径
|
||||
// TODO 支持子Location
|
||||
func (this *HTTPLocationConfig) Match(path string, formatter func(source string) string) (vars map[string]string, isMatched bool) {
|
||||
// 判断条件
|
||||
@@ -252,6 +280,22 @@ func (this *HTTPLocationConfig) Match(path string, formatter func(source string)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if this.patternType == HTTPLocationPatternTypeExact {
|
||||
if this.reverse {
|
||||
if this.caseInsensitive {
|
||||
|
||||
@@ -27,6 +27,8 @@ type HTTPWebConfig struct {
|
||||
Websocket *HTTPWebsocketConfig `yaml:"websocket" json:"websocket"` // Websocket配置
|
||||
RewriteRefs []*HTTPRewriteRef `yaml:"rewriteRefs" json:"rewriteRefs"` // 重写规则配置
|
||||
RewriteRules []*HTTPRewriteRule `yaml:"rewriteRules" json:"rewriteRules"` // 重写规则
|
||||
FastcgiRef *HTTPFastcgiRef `yaml:"fastcgiRef" json:"fastcgiRef"` // Fastcgi引用
|
||||
FastcgiList []*HTTPFastcgiConfig `yaml:"fastcgiList" json:"fastcgiList"` // Fastcgi配置
|
||||
|
||||
RequestHeaderPolicyRef *shared.HTTPHeaderPolicyRef `yaml:"requestHeaderPolicyRef" json:"requestHeaderPolicyRef"` // 请求Header
|
||||
RequestHeaderPolicy *shared.HTTPHeaderPolicy `yaml:"requestHeaderPolicy" json:"requestHeaderPolicy"` // 请求Header策略
|
||||
@@ -214,6 +216,14 @@ func (this *HTTPWebConfig) Init() error {
|
||||
}
|
||||
}
|
||||
|
||||
// fastcgi
|
||||
for _, fastcgi := range this.FastcgiList {
|
||||
err := fastcgi.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,18 @@ package serverconfigs
|
||||
|
||||
import "github.com/iwind/TeaGo/maps"
|
||||
|
||||
// 匹配类型
|
||||
// HTTPLocationPatternType 匹配类型
|
||||
type HTTPLocationPatternType = int
|
||||
|
||||
// 内置的匹配类型定义
|
||||
const (
|
||||
HTTPLocationPatternTypePrefix HTTPLocationPatternType = 1
|
||||
HTTPLocationPatternTypeSuffix HTTPLocationPatternType = 4
|
||||
HTTPLocationPatternTypeExact HTTPLocationPatternType = 2
|
||||
HTTPLocationPatternTypeRegexp HTTPLocationPatternType = 3
|
||||
)
|
||||
|
||||
// 取得所有的匹配类型信息
|
||||
// AllLocationPatternTypes 取得所有的匹配类型信息
|
||||
func AllLocationPatternTypes() []maps.Map {
|
||||
return []maps.Map{
|
||||
{
|
||||
@@ -20,6 +21,11 @@ func AllLocationPatternTypes() []maps.Map {
|
||||
"type": HTTPLocationPatternTypePrefix,
|
||||
"description": "带有此前缀的路径才会被匹配",
|
||||
},
|
||||
{
|
||||
"name": "匹配后缀",
|
||||
"type": HTTPLocationPatternTypeSuffix,
|
||||
"description": "带有此后缀的路径才会被匹配",
|
||||
},
|
||||
{
|
||||
"name": "精准匹配",
|
||||
"type": HTTPLocationPatternTypeExact,
|
||||
@@ -33,7 +39,7 @@ func AllLocationPatternTypes() []maps.Map {
|
||||
}
|
||||
}
|
||||
|
||||
// 查找单个匹配类型信息
|
||||
// FindLocationPatternType 查找单个匹配类型信息
|
||||
func FindLocationPatternType(patternType int) maps.Map {
|
||||
for _, t := range AllLocationPatternTypes() {
|
||||
if t["type"] == patternType {
|
||||
@@ -43,7 +49,7 @@ func FindLocationPatternType(patternType int) maps.Map {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查找单个匹配类型名称
|
||||
// FindLocationPatternTypeName 查找单个匹配类型名称
|
||||
func FindLocationPatternTypeName(patternType int) string {
|
||||
t := FindLocationPatternType(patternType)
|
||||
if t == nil {
|
||||
|
||||
Reference in New Issue
Block a user