Jelajahi Sumber

删除配置文件和相关代码

移除了与忽略文件、索引文件、代理规则、代理服务器、远程IP信任、重写配置相关的配置文件及其实现代码,同时更新了服务器处理逻辑以适配新的规则编译结构。
SongZihuan 3 bulan lalu
induk
melakukan
a5bb88a50b
63 mengubah file dengan 1597 tambahan dan 1073 penghapusan
  1. 1 0
      VIA
  2. 3 0
      resource.go
  3. 111 57
      src/config/config.go
  4. 1 1
      src/config/configerr/error.go
  5. 0 49
      src/config/corsconfig.go
  6. 0 52
      src/config/corsorigin.go
  7. 5 4
      src/config/ctrl.go
  8. 8 7
      src/config/globalconfig.go
  9. 12 18
      src/config/httpconfig.go
  10. 0 114
      src/config/ignorefileconfig.go
  11. 0 114
      src/config/indexfileconfig.go
  12. 0 274
      src/config/proxyconfig.go
  13. 0 58
      src/config/proxyrule.go
  14. 0 44
      src/config/proxyserverconfig.go
  15. 0 45
      src/config/remoteiptrustsconfig.go
  16. 0 61
      src/config/rewriteconfig.go
  17. 73 0
      src/config/rules/action/api/api.go
  18. 40 0
      src/config/rules/action/api/headerconfig.go
  19. 35 0
      src/config/rules/action/api/headerdelconfig.go
  20. 30 0
      src/config/rules/action/api/protectheader.go
  21. 32 0
      src/config/rules/action/api/queryconfig.go
  22. 27 0
      src/config/rules/action/api/querydelconfig.go
  23. 1 0
      src/config/rules/action/cors/README
  24. 33 0
      src/config/rules/action/cors/corsconfig.go
  25. 85 0
      src/config/rules/action/dir/dirconfig.go
  26. 23 0
      src/config/rules/action/dir/ignorefileconfig.go
  27. 23 0
      src/config/rules/action/dir/indexfileconfig.go
  28. 33 0
      src/config/rules/action/file/fileconfig.go
  29. 1 0
      src/config/rules/action/remotetrust/README
  30. 31 0
      src/config/rules/action/remotetrust/remotetrustconfig.go
  31. 1 0
      src/config/rules/action/rewrite/README
  32. 20 0
      src/config/rules/action/rewrite/rewriteconfig.go
  33. 1 0
      src/config/rules/match/README
  34. 28 0
      src/config/rules/match/matchconfig.go
  35. 73 0
      src/config/rules/ruleconfig.go
  36. 26 0
      src/config/rules/rulelistconfig.go
  37. 110 0
      src/config/rulescompile/actioncompile/apicompile/api.go
  38. 15 0
      src/config/rulescompile/actioncompile/apicompile/headerconfig.go
  39. 13 0
      src/config/rulescompile/actioncompile/apicompile/headerdelconfig.go
  40. 15 0
      src/config/rulescompile/actioncompile/apicompile/queryconfig.go
  41. 13 0
      src/config/rulescompile/actioncompile/apicompile/querydelconfig.go
  42. 77 0
      src/config/rulescompile/actioncompile/corscompile/corsconfig.go
  43. 65 0
      src/config/rulescompile/actioncompile/dircompile/dirconfig.go
  44. 32 0
      src/config/rulescompile/actioncompile/dircompile/ignorefileconfig.go
  45. 40 0
      src/config/rulescompile/actioncompile/dircompile/indexfileconfig.go
  46. 23 0
      src/config/rulescompile/actioncompile/filecompile/fileconfig.go
  47. 24 0
      src/config/rulescompile/actioncompile/remotetrustcompile/remotetrustcompileconfig.go
  48. 33 0
      src/config/rulescompile/actioncompile/rewritecompile/rewriteconfig.go
  49. 61 0
      src/config/rulescompile/matchcompile/matchconfig.go
  50. 97 0
      src/config/rulescompile/ruleconfig.go
  51. 22 0
      src/config/rulescompile/rulelistconfig.go
  52. 0 0
      src/config/signalconfig.go
  53. 16 14
      src/config/yamlconfig.go
  54. 13 37
      src/server/api.go
  55. 9 6
      src/server/cors.go
  56. 74 64
      src/server/dir.go
  57. 7 3
      src/server/file.go
  58. 0 0
      src/server/loggerserver.go
  59. 29 0
      src/server/match.go
  60. 8 5
      src/server/proxytrust.go
  61. 6 5
      src/server/respose.go
  62. 0 41
      src/server/server.go
  63. 38 0
      src/server/serverhttp.go

+ 1 - 0
VIA

@@ -0,0 +1 @@
+Huan-Proxy

+ 3 - 0
resource.go

@@ -12,3 +12,6 @@ var License string
 
 //go:embed REEPORT
 var Report string
+
+//go:embed VIA
+var Via string

+ 111 - 57
src/config/config.go

@@ -1,109 +1,123 @@
 package config
 
-import "os"
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"os"
+)
 
 type ConfigStruct struct {
 	configReady   bool
 	yamlHasParser bool
 	sigChan       chan os.Signal
 
-	Yaml        YamlConfig
-	CoreOrigin  CorsOrigin
-	ProxyServer ProxyServerConfig
-	IndexFile   IndexFileCompileList
-	IgnoreFile  IgnoreFileCompileList
-	Rewrite     RewriteConfigCompileList
+	Yaml  YamlConfig
+	Rules *rulescompile.RuleListCompileConfig
 }
 
-func (c *ConfigStruct) init() error {
-	c.configReady = false
-	c.yamlHasParser = false
-
-	c.sigChan = make(chan os.Signal)
-	err := initSignal(c.sigChan)
-	if err != nil {
-		return err
-	}
-
-	err = c.Yaml.init()
+func (c *ConfigStruct) Parser() configerr.ParserError {
+	err := c.Yaml.parser()
 	if err != nil {
 		return err
 	}
 
-	err = c.CoreOrigin.init()
-	if err != nil {
-		return err
-	}
+	c.yamlHasParser = true
+	return nil
+}
 
-	err = c.ProxyServer.init()
-	if err != nil {
-		return err
+func (c *ConfigStruct) SetDefault() {
+	if !c.yamlHasParser {
+		panic("yaml must parser first")
 	}
 
-	err = c.IndexFile.init()
-	if err != nil {
-		return err
-	}
+	c.Yaml.SetDefault()
+}
 
-	err = c.IgnoreFile.init()
-	if err != nil {
+func (c *ConfigStruct) Check() (err configerr.ConfigError) {
+	err = c.Yaml.Check()
+	if err != nil && err.IsError() {
 		return err
 	}
 
-	err = c.Rewrite.init()
-	if err != nil {
-		return err
-	}
 	return nil
 }
 
-func (c *ConfigStruct) parser() ParserError {
-	err := c.Yaml.parser()
+func (c *ConfigStruct) CompileRule() configerr.ConfigError {
+	res, err := rulescompile.NewRuleListConfig(&c.Yaml.RuleListConfig)
 	if err != nil {
-		return err
+		return configerr.NewConfigError("compile rule error: " + err.Error())
 	}
 
-	c.yamlHasParser = true
+	c.Rules = res
 	return nil
 }
 
-func (c *ConfigStruct) setDefault() {
-	if !c.yamlHasParser {
-		panic("yaml must parser first")
+func (c *ConfigStruct) Init() (err configerr.ConfigError) {
+	if c.configReady {
+		return c.Reload()
 	}
 
-	c.Yaml.setDefault()
-}
+	initErr := c.init()
+	if initErr != nil {
+		return configerr.NewConfigError("init error: " + initErr.Error())
+	}
+
+	parserErr := c.Parser()
+	if parserErr != nil {
+		return configerr.NewConfigError("parser error: " + parserErr.Error())
+	} else if !c.yamlHasParser {
+		return configerr.NewConfigError("parser error: unknown")
+	}
 
-func (c *ConfigStruct) check() (err ConfigError) {
-	err = c.Yaml.check(&c.CoreOrigin, &c.ProxyServer, &c.IndexFile, &c.IgnoreFile, &c.Rewrite)
+	c.SetDefault()
+
+	err = c.Check()
 	if err != nil && err.IsError() {
 		return err
 	}
 
+	err = c.CompileRule()
+	if err != nil && err.IsError() {
+		return err
+	}
+
+	c.configReady = true
 	return nil
 }
 
-func (c *ConfigStruct) ready() (err ConfigError) {
-	if c.configReady {
-		return nil
+func (c *ConfigStruct) Reload() (err configerr.ConfigError) {
+	if !c.configReady {
+		return c.Init()
 	}
 
-	initErr := c.init()
-	if initErr != nil {
-		return NewConfigError("init error: " + initErr.Error())
+	bak := *c
+
+	defer func() {
+		if err != nil {
+			*c = bak
+		}
+	}()
+
+	reloadErr := c.reload()
+	if reloadErr != nil {
+		return configerr.NewConfigError("reload error: " + reloadErr.Error())
 	}
 
-	parserErr := c.parser()
+	parserErr := c.Parser()
 	if parserErr != nil {
-		return NewConfigError("parser error: " + parserErr.Error())
+		return configerr.NewConfigError("reload parser error: " + parserErr.Error())
 	} else if !c.yamlHasParser {
-		return NewConfigError("parser error: unknown")
+		return configerr.NewConfigError("reload parser error: unknown")
 	}
 
-	c.setDefault()
+	c.SetDefault()
+
+	err = c.Check()
+	if err != nil && err.IsError() {
+		return err
+	}
 
-	err = c.check()
+	err = c.CompileRule()
 	if err != nil && err.IsError() {
 		return err
 	}
@@ -112,6 +126,46 @@ func (c *ConfigStruct) ready() (err ConfigError) {
 	return nil
 }
 
+func (c *ConfigStruct) clear() error {
+	c.configReady = false
+	c.yamlHasParser = false
+	// sigChan 不变
+	c.Yaml = YamlConfig{}
+	return nil
+}
+
+func (c *ConfigStruct) init() error {
+	c.configReady = false
+	c.yamlHasParser = false
+
+	c.sigChan = make(chan os.Signal)
+	err := initSignal(c.sigChan)
+	if err != nil {
+		return err
+	}
+
+	err = c.Yaml.init()
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *ConfigStruct) reload() error {
+	err := c.clear()
+	if err != nil {
+		return err
+	}
+
+	err = c.Yaml.init()
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 func (c *ConfigStruct) GetSignalChan() chan os.Signal {
 	return c.sigChan
 }

+ 1 - 1
src/config/error.go → src/config/configerr/error.go

@@ -1,4 +1,4 @@
-package config
+package configerr
 
 import (
 	"fmt"

+ 0 - 49
src/config/corsconfig.go

@@ -1,49 +0,0 @@
-package config
-
-import (
-	"fmt"
-	"github.com/SongZihuan/huan-proxy/src/utils"
-)
-
-const CorsMaxAgeSec = 86400
-const CorsDefaultMaxAgeSec = CorsMaxAgeSec
-
-type CorsConfig struct {
-	AllowCors      utils.StringBool `json:"allowcors"`
-	AllowOrigin    []string         `json:"alloworigin"`
-	AllowOriginReg []string         `json:"alloworiginres"`
-	MaxAgeSec      int              `json:"maxagesec"`
-}
-
-func (c *CorsConfig) setDefault() {
-	c.AllowCors.SetDefaultDisable()
-	if c.AllowCors.IsEnable() && c.MaxAgeSec == 0 {
-		c.MaxAgeSec = CorsMaxAgeSec
-	}
-}
-
-func (c *CorsConfig) check(co *CorsOrigin) ConfigError {
-	if c.AllowCors.IsEnable() {
-		if c.MaxAgeSec <= 0 || c.MaxAgeSec > CorsMaxAgeSec {
-			return NewConfigError(fmt.Sprintf("cors maxagesec %d is invalid", c.MaxAgeSec))
-		}
-
-		err := co.SetString(c.AllowOrigin)
-		if err != nil {
-			return NewConfigError("cors allowcors is invalid")
-		}
-
-		for _, r := range c.AllowOriginReg {
-			_ = co.ApplyReg(r)
-		}
-	}
-	return nil
-}
-
-func (c *CorsConfig) Enable() bool {
-	return c.AllowCors.IsEnable()
-}
-
-func (c *CorsConfig) Disable() bool {
-	return c.AllowCors.IsDisable()
-}

+ 0 - 52
src/config/corsorigin.go

@@ -1,52 +0,0 @@
-package config
-
-import "regexp"
-
-const DefaultOriginListSize = 10
-const AllowAllOrigin = "*"
-
-type CorsOrigin struct {
-	OriginReg    []*regexp.Regexp
-	OriginString []string
-}
-
-func (c *CorsOrigin) init() error {
-	c.OriginReg = make([]*regexp.Regexp, 0, DefaultOriginListSize)
-	c.OriginString = nil
-	return nil
-}
-
-func (c *CorsOrigin) ApplyReg(origin string) error {
-	reg, err := regexp.Compile(origin)
-	if err != nil {
-		return err
-	}
-	c.OriginReg = append(c.OriginReg, reg)
-	return nil
-}
-
-func (c *CorsOrigin) SetString(origins []string) error {
-	c.OriginString = origins
-	return nil
-}
-
-func (c *CorsOrigin) InOriginList(origin string) bool {
-	if (c.OriginString == nil || len(c.OriginString) == 0) && len(c.OriginReg) == 0 {
-		return true
-	}
-
-	for _, org := range c.OriginString {
-		if org == AllowAllOrigin {
-			return true
-		} else if org == origin {
-			return true
-		}
-	}
-
-	for _, reg := range c.OriginReg {
-		if reg != nil && reg.MatchString(origin) {
-			return true
-		}
-	}
-	return false
-}

+ 5 - 4
src/config/ctrl.go

@@ -1,6 +1,7 @@
 package config
 
 import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
 	"github.com/SongZihuan/huan-proxy/src/flagparser"
 )
 
@@ -11,19 +12,19 @@ func newConfig() ConfigStruct {
 	}
 }
 
-func InitConfig() ConfigError {
+func InitConfig() configerr.ConfigError {
 	if !flagparser.IsReady() {
-		return NewConfigError("flag not ready")
+		return configerr.NewConfigError("flag not ready")
 	}
 
 	config = newConfig()
-	err := config.ready()
+	err := config.Init()
 	if err != nil && err.IsError() {
 		return err
 	}
 
 	if !config.configReady {
-		return NewConfigError("config not ready")
+		return configerr.NewConfigError("config not ready")
 	}
 
 	return nil

+ 8 - 7
src/config/globalconfig.go

@@ -1,6 +1,7 @@
 package config
 
 import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"os"
 )
@@ -25,12 +26,12 @@ var levelMap = map[string]bool{
 }
 
 type GlobalConfig struct {
-	Mode     string           `json:"mode"`
-	LogLevel string           `json:"loglevel"`
-	LogTag   utils.StringBool `json:"logtag"`
+	Mode     string           `yaml:"mode"`
+	LogLevel string           `yaml:"loglevel"`
+	LogTag   utils.StringBool `yaml:"logtag"`
 }
 
-func (g *GlobalConfig) setDefault() {
+func (g *GlobalConfig) SetDefault() {
 	if g.Mode == "" {
 		g.Mode = os.Getenv(EnvModeName)
 	}
@@ -56,13 +57,13 @@ func (g *GlobalConfig) setDefault() {
 	return
 }
 
-func (g *GlobalConfig) check() ConfigError {
+func (g *GlobalConfig) Check() configerr.ConfigError {
 	if g.Mode != DebugMode && g.Mode != ReleaseMode && g.Mode != TestMode {
-		return NewConfigError("bad mode")
+		return configerr.NewConfigError("bad mode")
 	}
 
 	if _, ok := levelMap[g.LogLevel]; !ok {
-		return NewConfigError("log level error")
+		return configerr.NewConfigError("log level error")
 	}
 
 	return nil

+ 12 - 18
src/config/httpconfig.go

@@ -1,13 +1,17 @@
 package config
 
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"net/url"
+)
+
 type HttpConfig struct {
-	Address        string            `yaml:"address"`
-	RemoteTrust    RemoteTrustConfig `yaml:"remotetrust"`
-	StopWaitSecond int               `yaml:"stopwaitsecond"`
-	Cors           CorsConfig        `yaml:"cors"`
+	Address        string `yaml:"address"`
+	StopWaitSecond int    `yaml:"stopwaitsecond"`
 }
 
-func (h *HttpConfig) setDefault(global *GlobalConfig) {
+func (h *HttpConfig) SetDefault(global *GlobalConfig) {
 	if h.Address == "" {
 		h.Address = "localhost:2689"
 	}
@@ -15,21 +19,11 @@ func (h *HttpConfig) setDefault(global *GlobalConfig) {
 	if h.StopWaitSecond <= 0 {
 		h.StopWaitSecond = 10
 	}
-
-	h.RemoteTrust.setDefault(global)
-	h.Cors.setDefault()
 }
 
-func (h *HttpConfig) check(co *CorsOrigin) ConfigError {
-	err := h.RemoteTrust.check()
-	if err != nil && err.IsError() {
-		return err
+func (h *HttpConfig) Check() configerr.ConfigError {
+	if _, err := url.Parse(h.Address); err != nil {
+		return configerr.NewConfigError(fmt.Sprintf("http address error: %s", err.Error()))
 	}
-
-	err = h.Cors.check(co)
-	if err != nil && err.IsError() {
-		return err
-	}
-
 	return nil
 }

+ 0 - 114
src/config/ignorefileconfig.go

@@ -1,114 +0,0 @@
-package config
-
-import (
-	"fmt"
-	"github.com/SongZihuan/huan-proxy/src/utils"
-	"os"
-	"regexp"
-)
-
-const DefaultIgnoreFileListSize = 20
-const DefaultIgnoreFileMapSize = 20
-
-type IgnoreFile struct {
-	Regex utils.StringBool `yaml:"regex"`
-	File  string           `yaml:"file"`
-}
-
-func (i *IgnoreFile) setDefault() {
-	i.Regex.SetDefaultDisable()
-}
-
-func (i *IgnoreFile) check() ConfigError {
-	if i.File == "" {
-		return NewConfigError("file is empty")
-	}
-
-	return nil
-}
-
-type IgnoreFileCompile struct {
-	Index      int
-	IsRegex    bool
-	StringFile string
-	RegexFile  *regexp.Regexp
-}
-
-func (i *IgnoreFileCompile) CheckDirEntry(dir os.DirEntry) bool {
-	return i.CheckName(dir.Name())
-}
-
-func (i *IgnoreFileCompile) CheckName(name string) bool {
-	if i.IsRegex {
-		return i.RegexFile.MatchString(name)
-	} else {
-		return name == i.StringFile
-	}
-}
-
-func NewIgnoreFileCompile(index int, i *IgnoreFile) (*IgnoreFileCompile, error) {
-	if i.Regex.IsEnable() {
-		reg, err := regexp.Compile(i.File)
-		if err != nil {
-			return nil, err
-		}
-
-		return &IgnoreFileCompile{
-			Index:      index,
-			IsRegex:    true,
-			StringFile: "",
-			RegexFile:  reg,
-		}, nil
-	} else {
-		return &IgnoreFileCompile{
-			Index:      index,
-			IsRegex:    false,
-			StringFile: i.File,
-			RegexFile:  nil,
-		}, nil
-	}
-}
-
-type IgnoreFileCompileList struct {
-	Map map[int][]*IgnoreFileCompile
-}
-
-func (i *IgnoreFileCompileList) init() error {
-	i.Map = make(map[int][]*IgnoreFileCompile, DefaultIgnoreFileMapSize)
-	return nil
-}
-
-func (i *IgnoreFileCompileList) Add(ruleIndex int, fileIgnore int, ifile *IgnoreFile) error {
-	ignoreFile, err := NewIgnoreFileCompile(fileIgnore, ifile)
-	if err != nil {
-		return err
-	}
-
-	lst, ok := i.Map[ruleIndex]
-	if !ok || lst == nil {
-		lst = make([]*IgnoreFileCompile, 0, DefaultIgnoreFileListSize)
-	}
-
-	lst = append(lst, ignoreFile)
-	i.Map[ruleIndex] = lst
-	return nil
-}
-
-type IgnoreForEachFunc func(ignoreFile *IgnoreFileCompile) (any, error)
-
-func (i *IgnoreFileCompileList) ForEach(ruleIgnore int, fn IgnoreForEachFunc) (any, error) {
-	lst, ok := i.Map[ruleIgnore]
-	if !ok || lst == nil {
-		return nil, fmt.Errorf("rule not found")
-	}
-
-	for _, ignoreFile := range lst {
-		res, err := fn(ignoreFile)
-		if err != nil {
-			return nil, err
-		} else if res != nil {
-			return res, nil
-		}
-	}
-	return nil, nil
-}

+ 0 - 114
src/config/indexfileconfig.go

@@ -1,114 +0,0 @@
-package config
-
-import (
-	"fmt"
-	"github.com/SongZihuan/huan-proxy/src/utils"
-	"os"
-	"regexp"
-)
-
-const DefaultIndexFileListSize = 20
-const DefaultIndexFileMapSize = 20
-
-type IndexFile struct {
-	Regex utils.StringBool `yaml:"regex"`
-	File  string           `yaml:"file"`
-}
-
-func (i *IndexFile) setDefault() {
-	i.Regex.SetDefaultDisable()
-}
-
-func (i *IndexFile) check() ConfigError {
-	if i.File == "" {
-		return NewConfigError("file is empty")
-	}
-
-	return nil
-}
-
-type IndexFileCompile struct {
-	Index      int
-	IsRegex    bool
-	StringFile string
-	RegexFile  *regexp.Regexp
-}
-
-func (i *IndexFileCompile) CheckDirEntry(dir os.DirEntry) bool {
-	return i.CheckName(dir.Name())
-}
-
-func (i *IndexFileCompile) CheckName(name string) bool {
-	if i.IsRegex {
-		return i.RegexFile.MatchString(name)
-	} else {
-		return name == i.StringFile
-	}
-}
-
-func NewIndexFileCompile(index int, i *IndexFile) (*IndexFileCompile, error) {
-	if i.Regex.IsEnable() {
-		reg, err := regexp.Compile(i.File)
-		if err != nil {
-			return nil, err
-		}
-
-		return &IndexFileCompile{
-			Index:      index,
-			IsRegex:    true,
-			StringFile: "",
-			RegexFile:  reg,
-		}, nil
-	} else {
-		return &IndexFileCompile{
-			Index:      index,
-			IsRegex:    false,
-			StringFile: i.File,
-			RegexFile:  nil,
-		}, nil
-	}
-}
-
-type IndexFileCompileList struct {
-	Map map[int][]*IndexFileCompile
-}
-
-func (i *IndexFileCompileList) init() error {
-	i.Map = make(map[int][]*IndexFileCompile, DefaultIndexFileMapSize)
-	return nil
-}
-
-func (i *IndexFileCompileList) Add(ruleIndex int, fileIndex int, ifile *IndexFile) error {
-	indexFile, err := NewIndexFileCompile(fileIndex, ifile)
-	if err != nil {
-		return err
-	}
-
-	lst, ok := i.Map[ruleIndex]
-	if !ok || lst == nil {
-		lst = make([]*IndexFileCompile, 0, DefaultIndexFileListSize)
-	}
-
-	lst = append(lst, indexFile)
-	i.Map[ruleIndex] = lst
-	return nil
-}
-
-type IndexForEachFunc func(indexFile *IndexFileCompile) (any, error)
-
-func (i *IndexFileCompileList) ForEach(ruleIndex int, fn IndexForEachFunc) (any, error) {
-	lst, ok := i.Map[ruleIndex]
-	if !ok || lst == nil {
-		return nil, fmt.Errorf("rule not found")
-	}
-
-	for _, indexFile := range lst {
-		res, err := fn(indexFile)
-		if err != nil {
-			return nil, err
-		} else if res != nil {
-			return res, nil
-		}
-	}
-	return nil, nil
-}

+ 0 - 274
src/config/proxyconfig.go

@@ -1,274 +0,0 @@
-package config
-
-import (
-	"fmt"
-	"github.com/SongZihuan/huan-proxy/src/utils"
-	"net/url"
-	"strings"
-)
-
-const (
-	ProxyTypeFile = "file"
-	ProxyTypeDir  = "dir"
-	ProxyTypeAPI  = "api"
-)
-
-const XHuanProxyHeaer = "X-Huan-Proxy"
-const ViaHeader = "Via"
-
-type ProxyConfig struct {
-	Type     string `yaml:"type"`
-	BasePath string `yaml:"basepath"`
-
-	ProxyFileConfig `yaml:",inline"`
-	ProxyDirConfig  `yaml:",inline"`
-	ProxyAPIConfig  `yaml:",inline"`
-}
-
-type ProxyFileConfig struct {
-	File string `yaml:"file"`
-}
-
-type ProxyDirConfig struct {
-	Dir        string        `yaml:"dir"`
-	IndexFile  []*IndexFile  `yaml:"indexfile"`
-	IgnoreFile []*IgnoreFile `yaml:"ignorefile"`
-}
-
-type HeaderConfig struct {
-	Header string `yaml:"header"`
-	Value  string `yaml:"value"`
-}
-
-type QueryConfig struct {
-	Query string `yaml:"query"`
-	Value string `yaml:"value"`
-}
-
-var WarningHeader = []string{
-	"Host",
-	"Referer",
-	"User-Agent",
-	"Forwarded",
-	"Content-Length",
-	"Transfer-Encoding",
-	"Upgrade",
-	"Connection",
-	"X-Forwarded-For",
-	"X-Forwarded-Host",
-	"X-Forwarded-Proto",
-	"X-Real-Ip",
-	"X-Real-Port",
-}
-
-type ProxyAPIConfig struct {
-	Address       string         `yaml:"address"`
-	AddPrefixPath string         `yaml:"addprefixpath"`
-	SubPrefixPath string         `yaml:"subprefixpath"`
-	RewriteReg    string         `yaml:"rewritereg"`
-	RewriteTarget string         `yaml:"rewritetarget"`
-	Header        []HeaderConfig `yaml:"header"`
-	HeaderAdd     []HeaderConfig `yaml:"headeradd"`
-	HeaderDel     []string       `yaml:"headerdel"`
-	Query         []QueryConfig  `yaml:"query"`
-	QueryAdd      []QueryConfig  `yaml:"queryadd"`
-	QueryDel      []string       `yaml:"querydel"`
-	Via           string         `yaml:"via"`
-}
-
-const defaultVia = "huan-proxy"
-
-func (p *ProxyConfig) setDefault() {
-	p.BasePath = utils.ProcessPath(p.BasePath)
-
-	if p.Type == ProxyTypeDir {
-		if len(p.IndexFile) == 0 {
-			p.IndexFile = []*IndexFile{
-				{
-					Regex: "disable",
-					File:  "index.html",
-				},
-				{
-					Regex: "disable",
-					File:  "index.xml",
-				},
-				{
-					Regex: "disable",
-					File:  "index.txtzzz",
-				},
-				{
-					Regex: "enable",
-					File:  `^index\.\S+$`,
-				},
-			}
-		}
-
-		for _, i := range p.IndexFile {
-			i.setDefault()
-		}
-
-		for _, i := range p.IgnoreFile {
-			i.setDefault()
-		}
-	} else if p.Type == ProxyTypeAPI {
-		p.AddPrefixPath = utils.ProcessPath(p.AddPrefixPath)
-		p.SubPrefixPath = utils.ProcessPath(p.SubPrefixPath)
-
-		if p.Via == "" {
-			p.Via = defaultVia
-		}
-	}
-}
-
-func (p *ProxyConfig) check() ConfigError {
-	if p.Type == ProxyTypeFile {
-		if !utils.IsFile(p.File) {
-			return NewConfigError(fmt.Sprintf("file path %s not exist", p.File))
-		}
-	} else if p.Type == ProxyTypeDir {
-		if !utils.IsDir(p.Dir) {
-			return NewConfigError(fmt.Sprintf("dir path %s not exist", p.Dir))
-		}
-
-		for _, i := range p.IndexFile {
-			err := i.check()
-			if err != nil && err.IsError() {
-				return err
-			}
-		}
-
-		for _, i := range p.IgnoreFile {
-			err := i.check()
-			if err != nil && err.IsError() {
-				return err
-			}
-		}
-	} else if p.Type == ProxyTypeAPI {
-		_, err := url.Parse(p.Address)
-		if err != nil {
-			return NewConfigError(fmt.Sprintf("Failed to parse target URL: %v", err))
-		}
-
-		if p.BasePath != p.SubPrefixPath && !strings.HasPrefix(p.BasePath, p.SubPrefixPath+"/") {
-			return NewConfigError("sub prefix path error")
-		}
-
-		if len(p.RewriteTarget) != 0 && len(p.RewriteReg) == 0 {
-			return NewConfigError("rewrite reg is empty")
-		}
-
-		for _, h := range p.Header {
-			if h.Header == "" {
-				return NewConfigError("header name is empty")
-			}
-
-			if h.Header == ViaHeader || h.Header == XHuanProxyHeaer {
-				return NewConfigError(fmt.Sprintf("header %s use by http system", h.Header))
-			}
-
-			if !utils.IsValidHTTPHeaderKey(h.Header) {
-				return NewConfigError(fmt.Sprintf("header %s is not valid", h.Header))
-			}
-
-			if isNotGoodHeader(h.Header) {
-				_ = NewConfigWarning(fmt.Sprintf("header %s use by http system", h.Header))
-			}
-
-			if h.Value == "" {
-				_ = NewConfigWarning(fmt.Sprintf("the value of header %s is empty, but maybe it is not delete from requests", h.Header))
-			}
-		}
-
-		for _, h := range p.HeaderAdd {
-			if h.Header == "" {
-				return NewConfigError("header name is empty")
-			}
-
-			if h.Header == ViaHeader || h.Header == XHuanProxyHeaer {
-				return NewConfigError(fmt.Sprintf("header %s use by http system", h.Header))
-			}
-
-			if !utils.IsValidHTTPHeaderKey(h.Header) {
-				return NewConfigError(fmt.Sprintf("header %s is not valid", h.Header))
-			}
-
-			if isNotGoodHeader(h.Header) {
-				_ = NewConfigWarning(fmt.Sprintf("header %s use by http system", h.Header))
-			}
-
-			if h.Value == "" {
-				_ = NewConfigWarning(fmt.Sprintf("the value of header %s is empty, but maybe it is not delete from requests", h.Header))
-			}
-		}
-
-		for _, h := range p.HeaderDel {
-			if h == "" {
-				return NewConfigError("header name is empty")
-			}
-
-			if h == ViaHeader || h == XHuanProxyHeaer {
-				return NewConfigError(fmt.Sprintf("header %s use by http system", h))
-			}
-
-			if !utils.IsValidHTTPHeaderKey(h) {
-				return NewConfigError(fmt.Sprintf("header %s is not valid", h))
-			}
-
-			if isNotGoodHeader(h) {
-				_ = NewConfigWarning(fmt.Sprintf("header %s use by http system", h))
-			}
-		}
-
-		for _, q := range p.Query {
-			if q.Query == "" {
-				return NewConfigError("query key is empty")
-			}
-
-			if !utils.IsGoodQueryKey(q.Query) {
-				_ = NewConfigWarning(fmt.Sprintf("query %s is not good", q.Query))
-			}
-
-			if q.Value == "" {
-				_ = NewConfigWarning(fmt.Sprintf("the value of query %s is empty, but maybe it is not delete from requests", q.Query))
-			}
-		}
-
-		for _, q := range p.QueryAdd {
-			if q.Query == "" {
-				return NewConfigError("query key is empty")
-			}
-
-			if !utils.IsGoodQueryKey(q.Query) {
-				_ = NewConfigWarning(fmt.Sprintf("query %s is not good", q.Query))
-			}
-
-			if q.Value == "" {
-				_ = NewConfigWarning(fmt.Sprintf("the value of query %s is empty, but maybe it is not delete from requests", q.Query))
-			}
-		}
-
-		for _, q := range p.QueryDel {
-			if q == "" {
-				return NewConfigError("query key is empty")
-			}
-
-			if !utils.IsGoodQueryKey(q) {
-				_ = NewConfigWarning(fmt.Sprintf("query %s is not good", q))
-			}
-		}
-
-	} else {
-		return NewConfigError("proxy type must be file or dir or api")
-	}
-	return nil
-}
-
-func isNotGoodHeader(header string) bool {
-	for _, h := range WarningHeader {
-		if h == header {
-			return true
-		}
-	}
-
-	return false
-}

+ 0 - 58
src/config/proxyrule.go

@@ -1,58 +0,0 @@
-package config
-
-import (
-	"fmt"
-)
-
-type ProxyRuleConfig struct {
-	Rules []*ProxyConfig `yaml:"rules"`
-}
-
-func (r *ProxyRuleConfig) setDefault() {
-	for _, rule := range r.Rules {
-		rule.setDefault()
-	}
-}
-
-func (r *ProxyRuleConfig) check(ps *ProxyServerConfig, ixfile *IndexFileCompileList, igfile *IgnoreFileCompileList, re *RewriteConfigCompileList) ConfigError {
-	if len(r.Rules) == 0 {
-		return NewConfigError("proxy rule is empty")
-	}
-
-	for ruleIndex, rule := range r.Rules {
-		err := rule.check()
-		if err != nil && err.IsError() {
-			return err
-		}
-
-		if rule.Type == ProxyTypeDir {
-			for fileIndex, file := range rule.IndexFile {
-				err := ixfile.Add(ruleIndex, fileIndex, file)
-				if err != nil {
-					return NewConfigError(fmt.Sprintf("index file %s error", err.Error()))
-				}
-			}
-
-			for fileIndex, file := range rule.IgnoreFile {
-				err := igfile.Add(ruleIndex, fileIndex, file)
-				if err != nil {
-					return NewConfigError(fmt.Sprintf("ignore file %s error", err.Error()))
-				}
-			}
-		} else if rule.Type == ProxyTypeAPI {
-			err := ps.Add(ruleIndex, rule)
-			if err != nil {
-				return NewConfigError(fmt.Sprintf("proxy server can not create: %s", err.Error()))
-			}
-
-			if rule.RewriteReg != "" {
-				err = re.Add(ruleIndex, rule.RewriteReg, rule.RewriteTarget)
-				if err != nil {
-					return NewConfigError(fmt.Sprintf("rewrite %s error", err.Error()))
-				}
-			}
-		}
-	}
-
-	return nil
-}

+ 0 - 44
src/config/proxyserverconfig.go

@@ -1,44 +0,0 @@
-package config
-
-import (
-	"fmt"
-	"net/http/httputil"
-	"net/url"
-)
-
-const defaultServerPort = 10
-
-type ProxyServerConfig struct {
-	Server map[int]*httputil.ReverseProxy
-}
-
-func (p *ProxyServerConfig) init() error {
-	p.Server = make(map[int]*httputil.ReverseProxy, defaultServerPort)
-	return nil
-}
-
-func (p *ProxyServerConfig) Add(index int, rule *ProxyConfig) error {
-	if rule.Type != ProxyTypeAPI {
-		return nil
-	}
-
-	if _, ok := p.Server[index]; ok {
-		return fmt.Errorf("proxy server %d already exists", index)
-	}
-
-	targetURL, err := url.Parse(rule.Address)
-	if err != nil {
-		return err
-	}
-
-	p.Server[index] = httputil.NewSingleHostReverseProxy(targetURL)
-
-	return nil
-}
-
-func (p *ProxyServerConfig) Get(index int) *httputil.ReverseProxy {
-	if proxy, ok := p.Server[index]; ok {
-		return proxy
-	}
-	return nil
-}

+ 0 - 45
src/config/remoteiptrustsconfig.go

@@ -1,45 +0,0 @@
-package config
-
-import (
-	"fmt"
-	"github.com/SongZihuan/huan-proxy/src/utils"
-)
-
-type RemoteTrustConfig struct {
-	RemoteTrust utils.StringBool `json:"remotetrust"`
-	TrustedIPs  []string         `json:"trustedips"`
-}
-
-func (p *RemoteTrustConfig) setDefault(global *GlobalConfig) {
-	if global.IsDebug() || global.IsTest() {
-		p.RemoteTrust.SetDefaultEnable()
-	} else {
-		p.RemoteTrust.SetDefaultDisable()
-	}
-
-	if p.RemoteTrust.IsEnable() && len(p.TrustedIPs) == 0 {
-		p.TrustedIPs = []string{"127.0.0.0/8", "::1"}
-	}
-}
-
-func (p *RemoteTrustConfig) check() ConfigError {
-	if p.RemoteTrust.IsEnable() {
-		if len(p.TrustedIPs) == 0 {
-			_ = NewConfigWarning("proxy trusts ips will be ignore because proxy is disabled")
-		} else {
-			for _, ip := range p.TrustedIPs {
-				if !utils.ValidIPv4(ip) && !utils.ValidIPv6(ip) && !utils.IsValidIPv4CIDR(ip) && !utils.IsValidIPv6CIDR(ip) {
-					return NewConfigError(fmt.Sprintf("bad proxy trusts ip address: %s", ip))
-				}
-			}
-		}
-	} else {
-		_ = NewConfigWarning("You trusted all proxies, this is NOT safe. We recommend you to set a value.")
-	}
-
-	return nil
-}
-
-func (p *RemoteTrustConfig) Enable() bool {
-	return p.RemoteTrust.IsEnable()
-}

+ 0 - 61
src/config/rewriteconfig.go

@@ -1,61 +0,0 @@
-package config
-
-import (
-	"fmt"
-	"regexp"
-)
-
-const DefaultRewriteConfigMapSize = 20
-
-type RewriteConfigCompile struct {
-	Index  int
-	Reg    *regexp.Regexp
-	Target string
-}
-
-func NewRewriteConfigCompile(index int, r string, target string) (*RewriteConfigCompile, error) {
-	reg, err := regexp.Compile(r)
-	if err != nil {
-		return nil, err
-	}
-
-	return &RewriteConfigCompile{
-		Index:  index,
-		Reg:    reg,
-		Target: target,
-	}, nil
-}
-
-type RewriteConfigCompileList struct {
-	Map map[int]*RewriteConfigCompile
-}
-
-func (i *RewriteConfigCompileList) init() error {
-	i.Map = make(map[int]*RewriteConfigCompile, DefaultRewriteConfigMapSize)
-	return nil
-}
-
-func (i *RewriteConfigCompileList) Add(ruleIndex int, r string, target string) error {
-	rewrite, err := NewRewriteConfigCompile(ruleIndex, r, target)
-	if err != nil {
-		return err
-	}
-
-	res, ok := i.Map[ruleIndex]
-	if ok || res != nil {
-		return fmt.Errorf("rule exists")
-	}
-
-	i.Map[ruleIndex] = rewrite
-	return nil
-}
-
-func (i *RewriteConfigCompileList) Rewrite(ruleIndex int, path string) (string, error) {
-	rule, ok := i.Map[ruleIndex]
-	if !ok || rule == nil {
-		return "", fmt.Errorf("rule not found")
-	}
-
-	res := rule.Reg.ReplaceAllString(path, rule.Target)
-	return res, nil
-}

+ 73 - 0
src/config/rules/action/api/api.go

@@ -0,0 +1,73 @@
+package api
+
+import (
+	"fmt"
+	resource "github.com/SongZihuan/huan-proxy"
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/rewrite"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+	"net/url"
+)
+
+type RuleAPIConfig struct {
+	Address          string                `yaml:"address"`
+	ApiAddPrefixPath string                `yaml:"addprefixpath"` // Api前缀避免重名(yaml键忽略)
+	ApiSubPrefixPath string                `yaml:"subprefixpath"` // Api前缀避免重名(yaml键忽略)
+	ApiRewrite       rewrite.RewriteConfig `yaml:"rewrite"`
+	HeaderSet        []HeaderConfig        `yaml:"headerset"`
+	HeaderAdd        []HeaderConfig        `yaml:"headeradd"`
+	HeaderDel        []HeaderDelConfig     `yaml:"headerdel"`
+	QuerySet         []QueryConfig         `yaml:"queryset"`
+	QueryAdd         []QueryConfig         `yaml:"queryadd"`
+	QueryDel         []QueryDelConfig      `yaml:"querydel"`
+	Via              string                `yaml:"via"`
+}
+
+func (r *RuleAPIConfig) SetDefault() {
+	r.ApiAddPrefixPath = utils.ProcessPath(r.ApiAddPrefixPath)
+	r.ApiSubPrefixPath = utils.ProcessPath(r.ApiSubPrefixPath)
+
+	r.ApiRewrite.SetDefault()
+
+	for _, h := range r.HeaderSet {
+		h.SetDefault()
+	}
+
+	for _, h := range r.HeaderAdd {
+		h.SetDefault()
+	}
+
+	for _, h := range r.HeaderDel {
+		h.SetDefault()
+	}
+
+	for _, q := range r.QuerySet {
+		q.SetDefault()
+	}
+
+	for _, q := range r.QueryAdd {
+		q.SetDefault()
+	}
+
+	for _, q := range r.QueryDel {
+		q.SetDefault()
+	}
+
+	if r.Via == "" {
+		r.Via = resource.Via
+	}
+}
+
+func (r *RuleAPIConfig) Check() configerr.ConfigError {
+	_, err := url.Parse(r.Address)
+	if err != nil {
+		return configerr.NewConfigError(fmt.Sprintf("Failed to parse target URL: %v", err))
+	}
+
+	cfgErr := r.ApiRewrite.Check()
+	if cfgErr != nil && cfgErr.IsError() {
+		return cfgErr
+	}
+
+	return nil
+}

+ 40 - 0
src/config/rules/action/api/headerconfig.go

@@ -0,0 +1,40 @@
+package api
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+type HeaderConfig struct {
+	Header string `yaml:"header"`
+	Value  string `yaml:"value"`
+}
+
+func (h *HeaderConfig) SetDefault() {
+
+}
+
+func (h *HeaderConfig) Check() configerr.ConfigError {
+	if h.Header == "" {
+		return configerr.NewConfigError("header name is empty")
+	}
+
+	if h.Header == ViaHeader || h.Header == XHuanProxyHeaer {
+		return configerr.NewConfigError(fmt.Sprintf("header %s use by http system", h.Header))
+	}
+
+	if !utils.IsValidHTTPHeaderKey(h.Header) {
+		return configerr.NewConfigError(fmt.Sprintf("header %s is not valid", h.Header))
+	}
+
+	if isNotGoodHeader(h.Header) {
+		_ = configerr.NewConfigWarning(fmt.Sprintf("header %s use by http system", h.Header))
+	}
+
+	if h.Value == "" {
+		_ = configerr.NewConfigWarning(fmt.Sprintf("the value of header %s is empty, but maybe it is not delete from requests", h.Header))
+	}
+
+	return nil
+}

+ 35 - 0
src/config/rules/action/api/headerdelconfig.go

@@ -0,0 +1,35 @@
+package api
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+type HeaderDelConfig struct {
+	Header string `yaml:"header"`
+}
+
+func (h *HeaderDelConfig) SetDefault() {
+
+}
+
+func (h *HeaderDelConfig) Check() configerr.ConfigError {
+	if h.Header == "" {
+		return configerr.NewConfigError("header name is empty")
+	}
+
+	if h.Header == ViaHeader || h.Header == XHuanProxyHeaer {
+		return configerr.NewConfigError(fmt.Sprintf("header %s use by http system", h.Header))
+	}
+
+	if !utils.IsValidHTTPHeaderKey(h.Header) {
+		return configerr.NewConfigError(fmt.Sprintf("header %s is not valid", h.Header))
+	}
+
+	if isNotGoodHeader(h.Header) {
+		_ = configerr.NewConfigWarning(fmt.Sprintf("header %s use by http system", h.Header))
+	}
+
+	return nil
+}

+ 30 - 0
src/config/rules/action/api/protectheader.go

@@ -0,0 +1,30 @@
+package api
+
+const XHuanProxyHeaer = "X-Huan-Proxy"
+const ViaHeader = "Via"
+
+var WarningHeader = []string{
+	"Host",
+	"Referer",
+	"User-Agent",
+	"Forwarded",
+	"Content-Length",
+	"Transfer-Encoding",
+	"Upgrade",
+	"Connection",
+	"X-Forwarded-For",
+	"X-Forwarded-Host",
+	"X-Forwarded-Proto",
+	"X-Real-Ip",
+	"X-Real-Port",
+}
+
+func isNotGoodHeader(header string) bool {
+	for _, h := range WarningHeader {
+		if h == header {
+			return true
+		}
+	}
+
+	return false
+}

+ 32 - 0
src/config/rules/action/api/queryconfig.go

@@ -0,0 +1,32 @@
+package api
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+type QueryConfig struct {
+	Query string `yaml:"query"`
+	Value string `yaml:"value"`
+}
+
+func (q *QueryConfig) SetDefault() {
+
+}
+
+func (q *QueryConfig) Check() configerr.ConfigError {
+	if q.Query == "" {
+		return configerr.NewConfigError("query key is empty")
+	}
+
+	if !utils.IsGoodQueryKey(q.Query) {
+		_ = configerr.NewConfigWarning(fmt.Sprintf("query %s is not good", q.Query))
+	}
+
+	if q.Value == "" {
+		_ = configerr.NewConfigWarning(fmt.Sprintf("the value of query %s is empty, but maybe it is not delete from requests", q.Query))
+	}
+
+	return nil
+}

+ 27 - 0
src/config/rules/action/api/querydelconfig.go

@@ -0,0 +1,27 @@
+package api
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+type QueryDelConfig struct {
+	Query string `yaml:"query"`
+}
+
+func (q *QueryDelConfig) SetDefault() {
+
+}
+
+func (q *QueryDelConfig) Check() configerr.ConfigError {
+	if q.Query == "" {
+		return configerr.NewConfigError("query key is empty")
+	}
+
+	if !utils.IsGoodQueryKey(q.Query) {
+		_ = configerr.NewConfigWarning(fmt.Sprintf("query %s is not good", q.Query))
+	}
+
+	return nil
+}

+ 1 - 0
src/config/rules/action/cors/README

@@ -0,0 +1 @@
+所有模式均有

+ 33 - 0
src/config/rules/action/cors/corsconfig.go

@@ -0,0 +1,33 @@
+package cors
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+const CorsMaxAgeSec = 86400
+const CorsDefaultMaxAgeSec = CorsMaxAgeSec
+
+type CorsConfig struct {
+	AllowCors      utils.StringBool `yaml:"allowcors"`
+	AllowOrigin    []string         `yaml:"alloworigin"`
+	AllowOriginReg []string         `yaml:"alloworiginres"`
+	MaxAgeSec      int              `yaml:"maxagesec"`
+}
+
+func (c *CorsConfig) SetDefault() {
+	c.AllowCors.SetDefaultDisable()
+	if c.AllowCors.IsEnable() && c.MaxAgeSec == 0 {
+		c.MaxAgeSec = CorsDefaultMaxAgeSec
+	}
+}
+
+func (c *CorsConfig) Check() configerr.ConfigError {
+	if c.AllowCors.IsEnable() {
+		if c.MaxAgeSec <= 0 || c.MaxAgeSec > CorsMaxAgeSec {
+			return configerr.NewConfigError(fmt.Sprintf("cors maxagesec %d is invalid", c.MaxAgeSec))
+		}
+	}
+	return nil
+}

+ 85 - 0
src/config/rules/action/dir/dirconfig.go

@@ -0,0 +1,85 @@
+package dir
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/cors"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/rewrite"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+type RuleDirConfig struct {
+	Dir              string                `yaml:"dir"`
+	IndexFile        []IndexFileConfig     `yaml:"indexfile"`
+	IgnoreFile       []IgnoreFileConfig    `yaml:"ignorefile"`
+	DirAddPrefixPath string                `yaml:"addprefixpath"` // Dir前缀避免充满(yaaml忽略)
+	DirSubPrefixPath string                `yaml:"subprefixpath"` // Dir前缀避免充满(yaaml忽略)
+	DirRewrite       rewrite.RewriteConfig `yaml:"rewrite"`       // Dir前缀避免充满(yaaml忽略)
+	DirCors          cors.CorsConfig       `yaml:"cors"`          // Dir前缀避免充满(yaaml忽略)
+}
+
+func (r *RuleDirConfig) SetDefault() {
+	r.Dir = utils.ProcessPath(r.Dir)
+	r.DirAddPrefixPath = utils.ProcessPath(r.DirAddPrefixPath)
+	r.DirSubPrefixPath = utils.ProcessPath(r.DirSubPrefixPath)
+
+	if len(r.IndexFile) == 0 {
+		r.IndexFile = []IndexFileConfig{
+			{
+				Regex: "disable",
+				File:  "index.html",
+			},
+			{
+				Regex: "disable",
+				File:  "index.xml",
+			},
+			{
+				Regex: "disable",
+				File:  "index",
+			},
+			{
+				Regex: "enable",
+				File:  `^index\.\S+$`,
+			},
+		}
+	}
+
+	for _, i := range r.IndexFile {
+		i.SetDefault()
+	}
+
+	for _, i := range r.IgnoreFile {
+		i.SetDefault()
+	}
+
+	r.DirRewrite.SetDefault()
+	r.DirCors.SetDefault()
+}
+
+func (r *RuleDirConfig) Check() configerr.ConfigError {
+	// 不用检查目录是否存在,因为可能被rewrite
+	for _, i := range r.IndexFile {
+		err := i.Check()
+		if err != nil && err.IsError() {
+			return err
+		}
+	}
+
+	for _, i := range r.IgnoreFile {
+		err := i.Check()
+		if err != nil && err.IsError() {
+			return err
+		}
+	}
+
+	err := r.DirRewrite.Check()
+	if err != nil && err.IsError() {
+		return err
+	}
+
+	err = r.DirCors.Check()
+	if err != nil && err.IsError() {
+		return err
+	}
+
+	return nil
+}

+ 23 - 0
src/config/rules/action/dir/ignorefileconfig.go

@@ -0,0 +1,23 @@
+package dir
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+type IgnoreFileConfig struct {
+	Regex utils.StringBool `yaml:"regex"`
+	File  string           `yaml:"file"`
+}
+
+func (i *IgnoreFileConfig) SetDefault() {
+	i.Regex.SetDefaultDisable()
+}
+
+func (i *IgnoreFileConfig) Check() configerr.ConfigError {
+	if i.File == "" {
+		return configerr.NewConfigError("file is empty")
+	}
+
+	return nil
+}

+ 23 - 0
src/config/rules/action/dir/indexfileconfig.go

@@ -0,0 +1,23 @@
+package dir
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+type IndexFileConfig struct {
+	Regex utils.StringBool `yaml:"regex"`
+	File  string           `yaml:"file"`
+}
+
+func (i *IndexFileConfig) SetDefault() {
+	i.Regex.SetDefaultDisable()
+}
+
+func (i *IndexFileConfig) Check() configerr.ConfigError {
+	if i.File == "" {
+		return configerr.NewConfigError("file is empty")
+	}
+
+	return nil
+}

+ 33 - 0
src/config/rules/action/file/fileconfig.go

@@ -0,0 +1,33 @@
+package file
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/cors"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+type RuleFileConfig struct {
+	File     string          `yaml:"file"`
+	FileCors cors.CorsConfig `yaml:"cors"` // File前缀避免重名,(yaml键忽略)
+}
+
+func (r *RuleFileConfig) SetDefault() {
+	r.FileCors.SetDefault()
+}
+
+func (r *RuleFileConfig) Check() configerr.ConfigError {
+	if r.File == "" {
+		return configerr.NewConfigError("file is empty")
+	}
+
+	if utils.IsFile(r.File) {
+		return configerr.NewConfigError("file is not exists")
+	}
+
+	err := r.FileCors.Check()
+	if err != nil && err.IsError() {
+		return err
+	}
+
+	return nil
+}

+ 1 - 0
src/config/rules/action/remotetrust/README

@@ -0,0 +1 @@
+File和Dir模式独有

+ 31 - 0
src/config/rules/action/remotetrust/remotetrustconfig.go

@@ -0,0 +1,31 @@
+package remotetrust
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+type RemoteTrustConfig struct {
+	RemoteTrust utils.StringBool `yaml:"remotetrust"`
+	TrustedIPs  []string         `yaml:"trustedips"`
+}
+
+func (p *RemoteTrustConfig) SetDefault() {
+	p.RemoteTrust.SetDefaultDisable()
+
+	if p.RemoteTrust.IsEnable() && len(p.TrustedIPs) == 0 {
+		p.TrustedIPs = []string{"127.0.0.0/8", "::1"}
+	}
+}
+
+func (p *RemoteTrustConfig) Check() configerr.ConfigError {
+	if p.RemoteTrust.IsEnable() {
+		for _, ip := range p.TrustedIPs {
+			if !utils.ValidIPv4(ip) && !utils.ValidIPv6(ip) && !utils.IsValidIPv4CIDR(ip) && !utils.IsValidIPv6CIDR(ip) {
+				return configerr.NewConfigError(fmt.Sprintf("bad proxy trusts ip address: %s", ip))
+			}
+		}
+	}
+	return nil
+}

+ 1 - 0
src/config/rules/action/rewrite/README

@@ -0,0 +1 @@
+File和Dir模式独有

+ 20 - 0
src/config/rules/action/rewrite/rewriteconfig.go

@@ -0,0 +1,20 @@
+package rewrite
+
+import "github.com/SongZihuan/huan-proxy/src/config/configerr"
+
+type RewriteConfig struct {
+	Regex  string `yaml:"regex"`
+	Target string `yaml:"target"`
+}
+
+func (r *RewriteConfig) SetDefault() {
+
+}
+
+func (r *RewriteConfig) Check() configerr.ConfigError {
+	if len(r.Target) != 0 && len(r.Regex) == 0 {
+		return configerr.NewConfigError("rewrite reg is empty")
+	}
+
+	return nil
+}

+ 1 - 0
src/config/rules/match/README

@@ -0,0 +1 @@
+File和Dir模式独有

+ 28 - 0
src/config/rules/match/matchconfig.go

@@ -0,0 +1,28 @@
+package match
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+)
+
+const (
+	PrefixMatch    = "prefix"    // 前缀匹配
+	RegexMatch     = "regex"     // 正则匹配
+	PrecisionMatch = "precision" // 精准匹配
+)
+
+type MatchConfig struct {
+	MatchType string `yaml:"matchtype"`
+	Path      string `yaml:"path"`
+}
+
+func (m *MatchConfig) SetDefault() {
+	m.Path = utils.ProcessPath(m.Path)
+}
+
+func (m *MatchConfig) Check() configerr.ConfigError {
+	if m.MatchType != PrefixMatch && m.MatchType != RegexMatch && m.MatchType != PrecisionMatch {
+		return configerr.NewConfigError("proxy mutch type must be prefix or regex or precision")
+	}
+	return nil
+}

+ 73 - 0
src/config/rules/ruleconfig.go

@@ -0,0 +1,73 @@
+package rules
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/api"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/dir"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/file"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/remotetrust"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/match"
+)
+
+const (
+	ProxyTypeFile = "file"
+	ProxyTypeDir  = "dir"
+	ProxyTypeAPI  = "api"
+)
+
+type RuleConfig struct {
+	Type string `yaml:"type"`
+
+	match.MatchConfig             `yaml:",inline"`
+	remotetrust.RemoteTrustConfig `yaml:",inline"`
+
+	file.RuleFileConfig `yaml:",inline"`
+	dir.RuleDirConfig   `yaml:",inline"`
+	api.RuleAPIConfig   `yaml:",inline"`
+}
+
+func (p *RuleConfig) SetDefault() {
+	p.MatchConfig.SetDefault()
+	p.RemoteTrustConfig.SetDefault()
+
+	if p.Type == ProxyTypeFile {
+		p.RuleFileConfig.SetDefault()
+	} else if p.Type == ProxyTypeDir {
+		p.RuleDirConfig.SetDefault()
+	} else if p.Type == ProxyTypeAPI {
+		p.RuleAPIConfig.SetDefault()
+	}
+}
+
+func (p *RuleConfig) Check() configerr.ConfigError {
+	err := p.MatchConfig.Check()
+	if err != nil && err.IsError() {
+		return err
+	}
+
+	err = p.RemoteTrustConfig.Check()
+	if err != nil && err.IsError() {
+		return err
+	}
+
+	if p.Type == ProxyTypeFile {
+		err := p.RuleFileConfig.Check()
+		if err != nil && err.IsError() {
+			return err
+		}
+	} else if p.Type == ProxyTypeDir {
+		err := p.RuleDirConfig.Check()
+		if err != nil && err.IsError() {
+			return err
+		}
+	} else if p.Type == ProxyTypeAPI {
+		err := p.RuleAPIConfig.Check()
+		if err != nil && err.IsError() {
+			return err
+		}
+	} else {
+		return configerr.NewConfigError("proxy type must be file or dir or api")
+	}
+
+	return nil
+}

+ 26 - 0
src/config/rules/rulelistconfig.go

@@ -0,0 +1,26 @@
+package rules
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+)
+
+type RuleListConfig struct {
+	Rules []RuleConfig `yaml:"rules"`
+}
+
+func (r *RuleListConfig) SetDefault() {
+	for _, rule := range r.Rules {
+		rule.SetDefault()
+	}
+}
+
+func (r *RuleListConfig) Check() configerr.ConfigError {
+	for _, rule := range r.Rules {
+		err := rule.Check()
+		if err != nil && err.IsError() {
+			return err
+		}
+	}
+
+	return nil
+}

+ 110 - 0
src/config/rulescompile/actioncompile/apicompile/api.go

@@ -0,0 +1,110 @@
+package apicompile
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/api"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/rewritecompile"
+	"net/http/httputil"
+	"net/url"
+)
+
+const XHuanProxyHeaer = api.XHuanProxyHeaer
+const ViaHeader = api.ViaHeader
+
+type RuleAPICompileConfig struct {
+	Address       string
+	TargetURL     *url.URL
+	Server        *httputil.ReverseProxy
+	AddPrefixPath string
+	SubPrefixPath string
+	Rewrite       *rewritecompile.RewriteCompileConfig
+	HeaderSet     []*HeaderCompileConfig
+	HeaderAdd     []*HeaderCompileConfig
+	HeaderDel     []*HeaderDelCompileConfig
+	QuerySet      []*QueryCompileConfig
+	QueryAdd      []*QueryCompileConfig
+	QueryDel      []*QueryDelCompileConfig
+	Via           string
+}
+
+func NewRuleAPICompileConfig(r *api.RuleAPIConfig) (*RuleAPICompileConfig, error) {
+	rewrite, err := rewritecompile.NewRewriteCompileConfig(&r.ApiRewrite)
+	if err != nil {
+		return nil, err
+	}
+
+	targetURL, err := url.Parse(r.Address)
+	if err != nil {
+		return nil, err
+	}
+
+	server := httputil.NewSingleHostReverseProxy(targetURL)
+
+	HeaderSet := make([]*HeaderCompileConfig, 0, len(r.HeaderSet))
+	for _, v := range r.HeaderSet {
+		h, err := NewHeaderCompileConfig(&v)
+		if err != nil {
+			return nil, err
+		}
+		HeaderSet = append(HeaderSet, h)
+	}
+
+	HeaderAdd := make([]*HeaderCompileConfig, 0, len(r.HeaderAdd))
+	for _, v := range r.HeaderAdd {
+		h, err := NewHeaderCompileConfig(&v)
+		if err != nil {
+			return nil, err
+		}
+		HeaderAdd = append(HeaderAdd, h)
+	}
+
+	HeaderDel := make([]*HeaderDelCompileConfig, 0, len(r.HeaderDel))
+	for _, v := range r.HeaderDel {
+		h, err := NewHeaderDelCompileConfig(&v)
+		if err != nil {
+			return nil, err
+		}
+		HeaderDel = append(HeaderDel, h)
+	}
+
+	QuerySet := make([]*QueryCompileConfig, 0, len(r.QuerySet))
+	for _, v := range r.QuerySet {
+		q, err := NewQueryCompileConfig(&v)
+		if err != nil {
+			return nil, err
+		}
+		QuerySet = append(QuerySet, q)
+	}
+
+	QueryAdd := make([]*QueryCompileConfig, 0, len(r.QueryAdd))
+	for _, v := range r.QueryAdd {
+		q, err := NewQueryCompileConfig(&v)
+		if err != nil {
+			return nil, err
+		}
+		QueryAdd = append(QueryAdd, q)
+	}
+
+	QueryDel := make([]*QueryDelCompileConfig, 0, len(r.QueryDel))
+	for _, v := range r.QueryDel {
+		q, err := NewQueryDelCompileConfig(&v)
+		if err != nil {
+			return nil, err
+		}
+		QueryDel = append(QueryDel, q)
+	}
+
+	return &RuleAPICompileConfig{
+		Address:       r.Address,
+		TargetURL:     targetURL,
+		Server:        server,
+		AddPrefixPath: r.ApiAddPrefixPath,
+		SubPrefixPath: r.ApiSubPrefixPath,
+		Rewrite:       rewrite,
+		HeaderSet:     HeaderSet,
+		HeaderAdd:     HeaderAdd,
+		HeaderDel:     HeaderDel,
+		QuerySet:      QuerySet,
+		QueryAdd:      QueryAdd,
+		Via:           r.Via,
+	}, nil
+}

+ 15 - 0
src/config/rulescompile/actioncompile/apicompile/headerconfig.go

@@ -0,0 +1,15 @@
+package apicompile
+
+import "github.com/SongZihuan/huan-proxy/src/config/rules/action/api"
+
+type HeaderCompileConfig struct {
+	Header string `yaml:"header"`
+	Value  string `yaml:"value"`
+}
+
+func NewHeaderCompileConfig(h *api.HeaderConfig) (*HeaderCompileConfig, error) {
+	return &HeaderCompileConfig{
+		Header: h.Header,
+		Value:  h.Value,
+	}, nil
+}

+ 13 - 0
src/config/rulescompile/actioncompile/apicompile/headerdelconfig.go

@@ -0,0 +1,13 @@
+package apicompile
+
+import "github.com/SongZihuan/huan-proxy/src/config/rules/action/api"
+
+type HeaderDelCompileConfig struct {
+	Header string `yaml:"header"`
+}
+
+func NewHeaderDelCompileConfig(h *api.HeaderDelConfig) (*HeaderDelCompileConfig, error) {
+	return &HeaderDelCompileConfig{
+		Header: h.Header,
+	}, nil
+}

+ 15 - 0
src/config/rulescompile/actioncompile/apicompile/queryconfig.go

@@ -0,0 +1,15 @@
+package apicompile
+
+import "github.com/SongZihuan/huan-proxy/src/config/rules/action/api"
+
+type QueryCompileConfig struct {
+	Query string `yaml:"query"`
+	Value string `yaml:"value"`
+}
+
+func NewQueryCompileConfig(q *api.QueryConfig) (*QueryCompileConfig, error) {
+	return &QueryCompileConfig{
+		Query: q.Query,
+		Value: q.Value,
+	}, nil
+}

+ 13 - 0
src/config/rulescompile/actioncompile/apicompile/querydelconfig.go

@@ -0,0 +1,13 @@
+package apicompile
+
+import "github.com/SongZihuan/huan-proxy/src/config/rules/action/api"
+
+type QueryDelCompileConfig struct {
+	Query string `yaml:"query"`
+}
+
+func NewQueryDelCompileConfig(q *api.QueryDelConfig) (*QueryDelCompileConfig, error) {
+	return &QueryDelCompileConfig{
+		Query: q.Query,
+	}, nil
+}

+ 77 - 0
src/config/rulescompile/actioncompile/corscompile/corsconfig.go

@@ -0,0 +1,77 @@
+package corscompile
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/cors"
+	"regexp"
+	"strings"
+)
+
+const CorsMaxAgeSec = cors.CorsMaxAgeSec
+const CorsDefaultMaxAgeSec = CorsMaxAgeSec
+const AllowAllOrigin = "*"
+
+type CorsCompileConfig struct {
+	Ignore         bool
+	AllowOrigin    []string
+	AllowOriginReg []*regexp.Regexp
+	MaxAgeSec      int
+}
+
+func NewCorsCompileConfig(c *cors.CorsConfig) (*CorsCompileConfig, error) {
+	if c.AllowCors.IsDisable(false) {
+		return &CorsCompileConfig{
+			Ignore:         true,
+			AllowOrigin:    make([]string, 0),
+			AllowOriginReg: make([]*regexp.Regexp, 0),
+			MaxAgeSec:      0,
+		}, nil
+	}
+
+	regexps := make([]*regexp.Regexp, 0, len(c.AllowOriginReg))
+	for _, v := range c.AllowOriginReg {
+		reg, err := regexp.Compile(v)
+		if err != nil {
+			return nil, err
+		}
+		regexps = append(regexps, reg)
+	}
+
+	res := &CorsCompileConfig{
+		Ignore:         false,
+		AllowOrigin:    c.AllowOrigin,
+		AllowOriginReg: regexps,
+		MaxAgeSec:      c.MaxAgeSec,
+	}
+
+	if res.MaxAgeSec >= CorsMaxAgeSec {
+		res.MaxAgeSec = CorsMaxAgeSec
+	} else if res.MaxAgeSec < 0 {
+		res.MaxAgeSec = CorsDefaultMaxAgeSec
+	}
+
+	return res, nil
+}
+
+func (c *CorsCompileConfig) InOriginList(origin string) bool {
+	if len(c.AllowOrigin) == 0 && len(c.AllowOriginReg) == 0 {
+		return false
+	}
+
+	origin = strings.TrimSpace(origin)
+
+	for _, org := range c.AllowOrigin {
+		org = strings.TrimSpace(org)
+		if org == AllowAllOrigin {
+			return true
+		} else if org == origin {
+			return true
+		}
+	}
+
+	for _, reg := range c.AllowOriginReg {
+		if reg != nil && reg.MatchString(origin) {
+			return true
+		}
+	}
+	return false
+}

+ 65 - 0
src/config/rulescompile/actioncompile/dircompile/dirconfig.go

@@ -0,0 +1,65 @@
+package dircompile
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/dir"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/corscompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/rewritecompile"
+)
+
+type RuleDirCompileConfig struct {
+	Dir           string
+	IndexFile     []*IndexFileCompileConfig
+	IgnoreFile    []*IgnoreFileCompileConfig
+	AddPrefixPath string
+	SubPrefixPath string
+	Rewrite       *rewritecompile.RewriteCompileConfig
+	Cors          *corscompile.CorsCompileConfig
+}
+
+func NewRuleDirCompileConfig(r *dir.RuleDirConfig) (*RuleDirCompileConfig, error) {
+	Index := make([]*IndexFileCompileConfig, 0, len(r.IndexFile))
+	for _, i := range r.IndexFile {
+		file, err := NewIndexFileCompileConfig(&i)
+		if err != nil {
+			return nil, err
+		}
+		Index = append(Index, file)
+	}
+
+	Ignore := make([]*IgnoreFileCompileConfig, 0, len(r.IgnoreFile))
+	for _, i := range r.IgnoreFile {
+		file, err := NewIgnoreFileCompileConfig(&i)
+		if err != nil {
+			return nil, err
+		}
+		Ignore = append(Ignore, file)
+	}
+
+	rewrite, err := rewritecompile.NewRewriteCompileConfig(&r.DirRewrite)
+	if err != nil {
+		return nil, err
+	}
+
+	cors, err := corscompile.NewCorsCompileConfig(&r.DirCors)
+	if err != nil {
+		return nil, err
+	}
+
+	return &RuleDirCompileConfig{
+		Dir:           r.Dir,
+		IndexFile:     Index,
+		IgnoreFile:    Ignore,
+		AddPrefixPath: r.DirAddPrefixPath,
+		SubPrefixPath: r.DirSubPrefixPath,
+		Rewrite:       rewrite,
+		Cors:          cors,
+	}, nil
+}
+
+func (i *IgnoreFileCompileConfig) CheckName(name string) bool {
+	if i.IsRegex {
+		return i.Regex.MatchString(name)
+	} else {
+		return name == i.File
+	}
+}

+ 32 - 0
src/config/rulescompile/actioncompile/dircompile/ignorefileconfig.go

@@ -0,0 +1,32 @@
+package dircompile
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/dir"
+	"regexp"
+)
+
+type IgnoreFileCompileConfig struct {
+	IsRegex bool
+	File    string
+	Regex   *regexp.Regexp
+}
+
+func NewIgnoreFileCompileConfig(i *dir.IgnoreFileConfig) (*IgnoreFileCompileConfig, error) {
+	if i.Regex.IsEnable(true) {
+		reg, err := regexp.Compile(i.File)
+		if err != nil {
+			return nil, err
+		}
+		return &IgnoreFileCompileConfig{
+			IsRegex: true,
+			File:    "",
+			Regex:   reg,
+		}, nil
+	} else {
+		return &IgnoreFileCompileConfig{
+			IsRegex: false,
+			File:    i.File,
+			Regex:   nil,
+		}, nil
+	}
+}

+ 40 - 0
src/config/rulescompile/actioncompile/dircompile/indexfileconfig.go

@@ -0,0 +1,40 @@
+package dircompile
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/dir"
+	"regexp"
+)
+
+type IndexFileCompileConfig struct {
+	IsRegex bool
+	File    string
+	Regex   *regexp.Regexp
+}
+
+func NewIndexFileCompileConfig(i *dir.IndexFileConfig) (*IndexFileCompileConfig, error) {
+	if i.Regex.IsEnable(true) {
+		reg, err := regexp.Compile(i.File)
+		if err != nil {
+			return nil, err
+		}
+		return &IndexFileCompileConfig{
+			IsRegex: true,
+			File:    "",
+			Regex:   reg,
+		}, nil
+	} else {
+		return &IndexFileCompileConfig{
+			IsRegex: false,
+			File:    i.File,
+			Regex:   nil,
+		}, nil
+	}
+}
+
+func (i *IndexFileCompileConfig) CheckName(name string) bool {
+	if i.IsRegex {
+		return i.Regex.MatchString(name)
+	} else {
+		return name == i.File
+	}
+}

+ 23 - 0
src/config/rulescompile/actioncompile/filecompile/fileconfig.go

@@ -0,0 +1,23 @@
+package filecompile
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/file"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/corscompile"
+)
+
+type RuleFileCompileConfig struct {
+	File string
+	Cors *corscompile.CorsCompileConfig
+}
+
+func NewRuleFileCompileConfig(f *file.RuleFileConfig) (*RuleFileCompileConfig, error) {
+	cors, err := corscompile.NewCorsCompileConfig(&f.FileCors)
+	if err != nil {
+		return nil, err
+	}
+
+	return &RuleFileCompileConfig{
+		File: f.File,
+		Cors: cors,
+	}, nil
+}

+ 24 - 0
src/config/rulescompile/actioncompile/remotetrustcompile/remotetrustcompileconfig.go

@@ -0,0 +1,24 @@
+package remotetrustcompile
+
+import "github.com/SongZihuan/huan-proxy/src/config/rules/action/remotetrust"
+
+type RemoteTrustCompileConfig struct {
+	UseTrustedIPs bool
+	TrustedIPs    []string
+}
+
+func NewRemoteTrustCompileConfig(r *remotetrust.RemoteTrustConfig) (*RemoteTrustCompileConfig, error) {
+	if r.RemoteTrust.IsDisable(false) {
+		return &RemoteTrustCompileConfig{
+			UseTrustedIPs: false,
+			TrustedIPs:    make([]string, 0),
+		}, nil
+	} else {
+		trustedIPs := make([]string, len(r.TrustedIPs))
+		copy(trustedIPs, r.TrustedIPs)
+		return &RemoteTrustCompileConfig{
+			UseTrustedIPs: true,
+			TrustedIPs:    trustedIPs,
+		}, nil
+	}
+}

+ 33 - 0
src/config/rulescompile/actioncompile/rewritecompile/rewriteconfig.go

@@ -0,0 +1,33 @@
+package rewritecompile
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/rewrite"
+	"regexp"
+)
+
+type RewriteCompileConfig struct {
+	Use    bool
+	Regex  *regexp.Regexp
+	Target string
+}
+
+func NewRewriteCompileConfig(r *rewrite.RewriteConfig) (*RewriteCompileConfig, error) {
+	if r.Regex == "" {
+		return &RewriteCompileConfig{
+			Use:    false,
+			Regex:  nil,
+			Target: "",
+		}, nil
+	}
+
+	reg, err := regexp.Compile(r.Regex)
+	if err != nil {
+		return nil, err
+	}
+
+	return &RewriteCompileConfig{
+		Use:    true,
+		Regex:  reg,
+		Target: r.Target,
+	}, nil
+}

+ 61 - 0
src/config/rulescompile/matchcompile/matchconfig.go

@@ -0,0 +1,61 @@
+package matchcompile
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/match"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+	"regexp"
+)
+
+const (
+	RulesPrefixMatch    = match.PrefixMatch    // 前缀匹配
+	RulesRegexMatch     = match.RegexMatch     // 正则匹配
+	RulesPrecisionMatch = match.PrecisionMatch // 精准匹配
+)
+
+const (
+	PrefixMatch    = iota // 前缀匹配
+	RegexMatch            // 正则匹配
+	PrecisionMatch        // 精准匹配
+)
+
+var MatchTypeMap = map[string]int{
+	RulesPrefixMatch:    PrefixMatch,
+	RulesRegexMatch:     RegexMatch,
+	RulesPrecisionMatch: PrecisionMatch,
+}
+
+type MatchCompileConfig struct {
+	MatchType  int
+	MatchPath  string         // Prefix和Precision使用
+	MatchRegex *regexp.Regexp // regex使用
+}
+
+func NewMatchConfig(m *match.MatchConfig) (*MatchCompileConfig, error) {
+	res := new(MatchCompileConfig)
+
+	matchType, ok := MatchTypeMap[m.MatchType]
+	if !ok {
+		return nil, fmt.Errorf("bad match type")
+	}
+
+	res.MatchType = matchType
+
+	if matchType == RegexMatch {
+		reg, err := regexp.Compile(m.Path)
+		if err != nil {
+			return nil, err
+		}
+		res.MatchRegex = reg
+	} else if matchType == PrefixMatch || matchType == PrecisionMatch {
+		if !utils.IsValidURLPath(m.Path) {
+			return nil, fmt.Errorf("bad path")
+		}
+
+		res.MatchPath = utils.ProcessPath(m.Path)
+	} else {
+		return nil, fmt.Errorf("bad match type")
+	}
+
+	return res, nil
+}

+ 97 - 0
src/config/rulescompile/ruleconfig.go

@@ -0,0 +1,97 @@
+package rulescompile
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/rules"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/apicompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/dircompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/filecompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/remotetrustcompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/matchcompile"
+)
+
+const (
+	RulesProxyTypeFile = rules.ProxyTypeFile
+	RulesProxyTypeDir  = rules.ProxyTypeDir
+	RulesProxyTypeAPI  = rules.ProxyTypeAPI
+)
+
+const (
+	ProxyTypeFile = iota
+	ProxyTypeDir
+	ProxyTypeAPI
+)
+
+var ProxyTypeMap = map[string]int{
+	RulesProxyTypeFile: ProxyTypeFile,
+	RulesProxyTypeDir:  ProxyTypeDir,
+	RulesProxyTypeAPI:  ProxyTypeAPI,
+}
+
+type RuleCompileConfig struct {
+	Type int
+
+	*matchcompile.MatchCompileConfig
+	*remotetrustcompile.RemoteTrustCompileConfig
+
+	File *filecompile.RuleFileCompileConfig
+	Dir  *dircompile.RuleDirCompileConfig
+	Api  *apicompile.RuleAPICompileConfig
+}
+
+func NewRuleCompileConfig(r *rules.RuleConfig) (*RuleCompileConfig, error) {
+	typeID, ok := ProxyTypeMap[r.Type]
+	if !ok {
+		return nil, fmt.Errorf("error rule type")
+	}
+
+	match, err := matchcompile.NewMatchConfig(&r.MatchConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	remoteTrusts, err := remotetrustcompile.NewRemoteTrustCompileConfig(&r.RemoteTrustConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	if typeID == ProxyTypeFile {
+		file, err := filecompile.NewRuleFileCompileConfig(&r.RuleFileConfig)
+		if err != nil {
+			return nil, err
+		}
+
+		return &RuleCompileConfig{
+			Type:                     typeID,
+			MatchCompileConfig:       match,
+			RemoteTrustCompileConfig: remoteTrusts,
+			File:                     file,
+		}, nil
+	} else if typeID == ProxyTypeDir {
+		dir, err := dircompile.NewRuleDirCompileConfig(&r.RuleDirConfig)
+		if err != nil {
+			return nil, err
+		}
+
+		return &RuleCompileConfig{
+			Type:                     typeID,
+			MatchCompileConfig:       match,
+			RemoteTrustCompileConfig: remoteTrusts,
+			Dir:                      dir,
+		}, nil
+	} else if typeID == ProxyTypeAPI {
+		api, err := apicompile.NewRuleAPICompileConfig(&r.RuleAPIConfig)
+		if err != nil {
+			return nil, err
+		}
+
+		return &RuleCompileConfig{
+			Type:                     typeID,
+			MatchCompileConfig:       match,
+			RemoteTrustCompileConfig: remoteTrusts,
+			Api:                      api,
+		}, nil
+	} else {
+		return nil, fmt.Errorf("error rule type")
+	}
+}

+ 22 - 0
src/config/rulescompile/rulelistconfig.go

@@ -0,0 +1,22 @@
+package rulescompile
+
+import "github.com/SongZihuan/huan-proxy/src/config/rules"
+
+type RuleListCompileConfig struct {
+	Rules []*RuleCompileConfig `yaml:"rules"`
+}
+
+func NewRuleListConfig(rs *rules.RuleListConfig) (*RuleListCompileConfig, error) {
+	res := make([]*RuleCompileConfig, 0, len(rs.Rules))
+	for _, v := range rs.Rules {
+		r, err := NewRuleCompileConfig(&v)
+		if err != nil {
+			return nil, err
+		}
+		res = append(res, r)
+	}
+
+	return &RuleListCompileConfig{
+		Rules: res,
+	}, nil
+}

+ 0 - 0
src/config/signal.go → src/config/signalconfig.go


+ 16 - 14
src/config/yamlconfig.go

@@ -1,39 +1,41 @@
 package config
 
 import (
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/config/rules"
 	"github.com/SongZihuan/huan-proxy/src/flagparser"
 	"gopkg.in/yaml.v3"
 	"os"
 )
 
 type YamlConfig struct {
-	GlobalConfig `yaml:",inline"`
-	Http         HttpConfig      `yaml:"http"`
-	Rules        ProxyRuleConfig `yaml:"rules"`
+	GlobalConfig         `yaml:",inline"`
+	Http                 HttpConfig `yaml:"http"`
+	rules.RuleListConfig `yaml:",inline"`
 }
 
 func (y *YamlConfig) init() error {
 	return nil
 }
 
-func (y *YamlConfig) setDefault() {
-	y.GlobalConfig.setDefault()
-	y.Http.setDefault(&y.GlobalConfig)
-	y.Rules.setDefault()
+func (y *YamlConfig) SetDefault() {
+	y.GlobalConfig.SetDefault()
+	y.Http.SetDefault(&y.GlobalConfig)
+	y.RuleListConfig.SetDefault()
 }
 
-func (y *YamlConfig) check(co *CorsOrigin, ps *ProxyServerConfig, ifile *IndexFileCompileList, igfile *IgnoreFileCompileList, re *RewriteConfigCompileList) (err ConfigError) {
-	err = y.GlobalConfig.check()
+func (y *YamlConfig) Check() (err configerr.ConfigError) {
+	err = y.GlobalConfig.Check()
 	if err != nil && err.IsError() {
 		return err
 	}
 
-	err = y.Http.check(co)
+	err = y.Http.Check()
 	if err != nil && err.IsError() {
 		return err
 	}
 
-	err = y.Rules.check(ps, ifile, igfile, re)
+	err = y.RuleListConfig.Check()
 	if err != nil && err.IsError() {
 		return err
 	}
@@ -41,15 +43,15 @@ func (y *YamlConfig) check(co *CorsOrigin, ps *ProxyServerConfig, ifile *IndexFi
 	return nil
 }
 
-func (y *YamlConfig) parser() ParserError {
+func (y *YamlConfig) parser() configerr.ParserError {
 	file, err := os.ReadFile(flagparser.ConfigFile())
 	if err != nil {
-		return NewParserError(err, err.Error())
+		return configerr.NewParserError(err, err.Error())
 	}
 
 	err = yaml.Unmarshal(file, y)
 	if err != nil {
-		return NewParserError(err, err.Error())
+		return configerr.NewParserError(err, err.Error())
 	}
 
 	return nil

+ 13 - 37
src/server/api.go

@@ -2,76 +2,52 @@ package server
 
 import (
 	"fmt"
-	"github.com/SongZihuan/huan-proxy/src/config"
-	"github.com/SongZihuan/huan-proxy/src/logger"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"net"
 	"net/http"
-	"net/url"
 	"strings"
 )
 
-func (s *HTTPServer) apiServer(ruleIndex int, rule *config.ProxyConfig, w http.ResponseWriter, r *http.Request) {
-	proxy := s.cfg.ProxyServer.Get(ruleIndex)
+func (s *HTTPServer) apiServer(rule *rulescompile.RuleCompileConfig, w http.ResponseWriter, r *http.Request) {
+	proxy := rule.Api.Server
 	if proxy == nil {
 		s.abortServerError(w)
 		return
 	}
 
-	targetURL, err := url.Parse(rule.Address)
-	if err != nil {
-		s.abortServerError(w)
-		return
-	}
-
+	targetURL := rule.Api.TargetURL
 	r.URL.Scheme = targetURL.Scheme
 	r.URL.Host = targetURL.Host
 
 	s.processProxyHeader(r)
 
-	path := r.URL.Path
-
-	if strings.HasPrefix(path, rule.SubPrefixPath) {
-		path = path[len(rule.SubPrefixPath):]
-	}
-
-	path = rule.AddPrefixPath + path
-
-	if rule.RewriteReg != "" {
-		path, err = s.cfg.Rewrite.Rewrite(ruleIndex, path)
-		if err != nil {
-			s.abortServerError(w)
-			return
-		}
-	}
-
-	r.URL.Path = path
+	r.URL.Path = s.rewrite(utils.ProcessPath(r.URL.Path), rule.Api.AddPrefixPath, rule.Api.SubPrefixPath, rule.Api.Rewrite)
 
-	for _, h := range rule.Header {
+	for _, h := range rule.Api.HeaderSet {
 		r.Header.Set(h.Header, h.Value)
 	}
 
-	for _, h := range rule.HeaderAdd {
+	for _, h := range rule.Api.HeaderAdd {
 		r.Header.Add(h.Header, h.Value)
 	}
 
-	for _, h := range rule.HeaderDel {
-		r.Header.Del(h)
+	for _, h := range rule.Api.HeaderDel {
+		r.Header.Del(h.Header)
 	}
 
 	query := r.URL.Query()
 
-	for _, q := range rule.Query {
+	for _, q := range rule.Api.QuerySet {
 		query.Set(q.Query, q.Value)
 	}
 
-	for _, q := range rule.QueryAdd {
+	for _, q := range rule.Api.QueryAdd {
 		query.Add(q.Query, q.Value)
 	}
 
-	for _, q := range rule.QueryDel {
-		logger.Tagf("A '%s'", q)
-		query.Del(q)
+	for _, q := range rule.Api.QueryDel {
+		query.Del(q.Query)
 	}
 
 	r.URL.RawQuery = query.Encode()

+ 9 - 6
src/server/cors.go

@@ -2,15 +2,18 @@ package server
 
 import (
 	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/corscompile"
 	"net/http"
 )
 
-func (s *HTTPServer) corsHandler(w http.ResponseWriter, r *http.Request) bool {
-	if s.cfg.Yaml.Http.Cors.Disable() {
+func (s *HTTPServer) cors(corsRule *corscompile.CorsCompileConfig, w http.ResponseWriter, r *http.Request) bool {
+	if corsRule.Ignore {
 		if r.Method == http.MethodOptions {
-			s.abortNoContent(w)
+			s.abortMethodNotAllowed(w)
+			return false
+		} else {
+			return true
 		}
-		return true
 	}
 
 	origin := r.Header.Get("Origin")
@@ -19,14 +22,14 @@ func (s *HTTPServer) corsHandler(w http.ResponseWriter, r *http.Request) bool {
 		return false
 	}
 
-	if !s.cfg.CoreOrigin.InOriginList(origin) {
+	if !corsRule.InOriginList(origin) {
 		s.abortForbidden(w)
 		return false
 	}
 
 	w.Header().Set("Access-Control-Allow-Origin", origin)
 	w.Header().Set("Access-Control-Allow-Methods", "GET,OPTIONS")
-	w.Header().Set("Access-Control-Max-Age", fmt.Sprintf("%d", s.cfg.Yaml.Http.Cors.MaxAgeSec))
+	w.Header().Set("Access-Control-Max-Age", fmt.Sprintf("%d", corsRule.MaxAgeSec))
 
 	return true
 }

+ 74 - 64
src/server/dir.go

@@ -1,7 +1,9 @@
 package server
 
 import (
-	"github.com/SongZihuan/huan-proxy/src/config"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/rewritecompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/matchcompile"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"github.com/gabriel-vasile/mimetype"
 	"net/http"
@@ -13,62 +15,61 @@ import (
 const IndexMaxDeep = 5
 const DefaultIgnoreFileMap = 20
 
-func (s *HTTPServer) dirServer(ruleIndex int, rule *config.ProxyConfig, w http.ResponseWriter, r *http.Request) {
+func (s *HTTPServer) dirServer(rule *rulescompile.RuleCompileConfig, w http.ResponseWriter, r *http.Request) {
+	if !s.cors(rule.File.Cors, w, r) {
+		return
+	}
+
 	if r.Method != http.MethodGet {
 		s.abortMethodNotAllowed(w)
 		return
 	}
 
-	dirBasePath := rule.Dir
-	fileBase := ""
-	filePath := ""
+	dirBasePath := rule.Dir.Dir // 根部目录
+	fileAccess := ""            // 访问目录
+	filePath := ""              // 根部目录+访问目录=实际目录
 
 	url := utils.ProcessPath(r.URL.Path)
-	if url == rule.BasePath {
-		filePath = dirBasePath
-		fileBase = ""
-	} else if strings.HasPrefix(url, rule.BasePath+"/") {
-		fileBase = url[len(rule.BasePath+"/"):]
-		filePath = path.Join(dirBasePath, fileBase)
+	if rule.MatchType == matchcompile.RegexMatch {
+		fileAccess = s.rewrite("", rule.Dir.AddPrefixPath, rule.Dir.SubPrefixPath, rule.Dir.Rewrite)
+		filePath = path.Join(dirBasePath, fileAccess)
 	} else {
-		s.abortNotFound(w)
-		return
+		if url == rule.MatchPath {
+			fileAccess = s.rewrite("", rule.Dir.AddPrefixPath, rule.Dir.SubPrefixPath, rule.Dir.Rewrite)
+			filePath = path.Join(dirBasePath, fileAccess)
+		} else if strings.HasPrefix(url, rule.MatchPath+"/") {
+			fileAccess = s.rewrite(url[len(rule.MatchPath+"/"):], rule.Dir.AddPrefixPath, rule.Dir.SubPrefixPath, rule.Dir.Rewrite)
+			filePath = path.Join(dirBasePath, fileAccess)
+		} else {
+			s.abortNotFound(w)
+			return
+		}
 	}
 
 	if filePath == "" {
-		s.abortNotFound(w)
+		s.abortNotFound(w) // 正常清空不会走到这个流程
 		return
 	}
 
-	if !utils.IsFile(filePath) {
-		filePath = s.getIndexFile(ruleIndex, filePath)
-		fileBase = filePath[len(rule.BasePath+"/"):len(filePath)]
-	} else if fileBase != "" {
-		ignore, err := s.cfg.IgnoreFile.ForEach(ruleIndex, func(file *config.IgnoreFileCompile) (any, error) {
-			if file.CheckName(fileBase) {
-				return true, nil
+	if utils.IsFile(filePath) {
+		// 判断这个文件是否被ignore,因为ignore是从dirBasePath写起,也可以是完整路径,因此filePath和fileAccess都要判断
+		for _, ignore := range rule.Dir.IgnoreFile {
+			if ignore.CheckName(fileAccess) || ignore.CheckName(filePath) {
+				s.abortNotFound(w)
+				return
 			}
-			return nil, nil
-		})
-		if err != nil {
+		}
+	} else {
+		filePath = s.getIndexFile(rule, filePath)
+		if filePath == "" || !utils.IsFile(filePath) {
 			s.abortNotFound(w)
 			return
-		} else if ig, ok := ignore.(bool); ok && ig {
-			filePath = s.getIndexFile(ruleIndex, filePath)
-			fileBase = filePath[len(rule.BasePath+"/"):len(filePath)]
 		}
 	}
 
-	// 接下来的部分不在使用fileBase
-
-	if filePath == "" || !utils.IsFile(filePath) {
-		s.abortNotFound(w)
-		return
-	}
-
 	file, err := os.ReadFile(filePath)
 	if err != nil {
-		s.abortServerError(w)
+		s.abortNotFound(w)
 		return
 	}
 
@@ -88,11 +89,29 @@ func (s *HTTPServer) dirServer(ruleIndex int, rule *config.ProxyConfig, w http.R
 	s.statusOK(w)
 }
 
-func (s *HTTPServer) getIndexFile(ruleIndex int, dir string) string {
-	return s._getIndexFile(ruleIndex, dir, "", IndexMaxDeep)
+func (s *HTTPServer) rewrite(srcpath string, prefix string, suffix string, rewrite *rewritecompile.RewriteCompileConfig) string {
+	srcpath = utils.ProcessPath(srcpath)
+	prefix = utils.ProcessPath(prefix)
+	suffix = utils.ProcessPath(suffix)
+
+	if strings.HasPrefix(srcpath, suffix) {
+		srcpath = srcpath[len(suffix):]
+	}
+
+	srcpath = prefix + srcpath
+
+	if rewrite.Use && rewrite.Regex != nil {
+		rewrite.Regex.ReplaceAllString(srcpath, rewrite.Target)
+	}
+
+	return srcpath
 }
 
-func (s *HTTPServer) _getIndexFile(ruleIndex int, baseDir string, nextDir string, deep int) string {
+func (s *HTTPServer) getIndexFile(rule *rulescompile.RuleCompileConfig, dir string) string {
+	return s._getIndexFile(rule, dir, "", IndexMaxDeep)
+}
+
+func (s *HTTPServer) _getIndexFile(rule *rulescompile.RuleCompileConfig, baseDir string, nextDir string, deep int) string {
 	if deep == 0 {
 		return ""
 	}
@@ -102,24 +121,19 @@ func (s *HTTPServer) _getIndexFile(ruleIndex int, baseDir string, nextDir string
 		return ""
 	}
 
-	lst, err := os.ReadDir(dir)
+	fileList, err := os.ReadDir(dir)
 	if err != nil {
 		return ""
 	}
 
 	var ignoreFileMap = make(map[string]bool, DefaultIgnoreFileMap)
-
-	_, err = s.cfg.IgnoreFile.ForEach(ruleIndex, func(file *config.IgnoreFileCompile) (any, error) {
-		for _, i := range lst {
-			fileName := path.Join(nextDir, i.Name())
-			if file.CheckName(fileName) {
+	for _, ignore := range rule.Dir.IgnoreFile {
+		for _, file := range fileList {
+			fileName := path.Join(nextDir, file.Name())
+			if ignore.CheckName(fileName) {
 				ignoreFileMap[fileName] = true
 			}
 		}
-		return nil, nil
-	})
-	if err != nil {
-		return ""
 	}
 
 	var indexDirNum = -1
@@ -128,38 +142,34 @@ func (s *HTTPServer) _getIndexFile(ruleIndex int, baseDir string, nextDir string
 	var indexFileNum = -1
 	var indexFile os.DirEntry = nil
 
-	_, err = s.cfg.IndexFile.ForEach(ruleIndex, func(file *config.IndexFileCompile) (any, error) {
-		for _, i := range lst {
-			fileName := path.Join(nextDir, i.Name())
+	for indexID, index := range rule.Dir.IndexFile {
+		for _, file := range fileList {
+			fileName := path.Join(nextDir, file.Name())
 
 			if _, ok := ignoreFileMap[fileName]; ok {
 				continue
 			}
 
-			if file.CheckDirEntry(i) {
-				if i.IsDir() {
-					if indexDirNum == -1 || file.Index < indexDirNum {
-						indexDirNum = file.Index
-						indexDir = i
+			if index.CheckName(file.Name()) {
+				if file.IsDir() {
+					if indexDirNum == -1 || indexID < indexDirNum {
+						indexDirNum = indexID
+						indexDir = file
 					}
 				} else {
-					if indexFileNum == -1 || file.Index < indexFileNum {
-						indexFileNum = file.Index
-						indexFile = i
+					if indexFileNum == -1 || indexID < indexFileNum {
+						indexFileNum = indexID
+						indexFile = file
 					}
 				}
 			}
 		}
-		return nil, nil
-	})
-	if err != nil {
-		return ""
 	}
 
 	if indexFile != nil {
 		return path.Join(dir, indexFile.Name())
 	} else if indexDir != nil {
-		return s._getIndexFile(ruleIndex, dir, indexDir.Name(), deep-1)
+		return s._getIndexFile(rule, dir, indexDir.Name(), deep-1)
 	} else {
 		return ""
 	}

+ 7 - 3
src/server/file.go

@@ -1,20 +1,24 @@
 package server
 
 import (
-	"github.com/SongZihuan/huan-proxy/src/config"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"github.com/gabriel-vasile/mimetype"
 	"net/http"
 	"os"
 )
 
-func (s *HTTPServer) fileServer(rule *config.ProxyConfig, w http.ResponseWriter, r *http.Request) {
+func (s *HTTPServer) fileServer(rule *rulescompile.RuleCompileConfig, w http.ResponseWriter, r *http.Request) {
+	if !s.cors(rule.File.Cors, w, r) {
+		return
+	}
+
 	if r.Method != http.MethodGet {
 		s.abortMethodNotAllowed(w)
 		return
 	}
 
-	file, err := os.ReadFile(rule.File)
+	file, err := os.ReadFile(rule.File.File)
 	if err != nil {
 		s.abortServerError(w)
 		return

+ 0 - 0
src/server/logger.go → src/server/loggerserver.go


+ 29 - 0
src/server/match.go

@@ -0,0 +1,29 @@
+package server
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/matchcompile"
+	"github.com/SongZihuan/huan-proxy/src/utils"
+	"net/http"
+	"strings"
+)
+
+func (s *HTTPServer) matchURL(rule *rulescompile.RuleCompileConfig, r *http.Request) bool {
+	url := utils.ProcessPath(r.URL.Path)
+	if rule.MatchType == matchcompile.RegexMatch {
+		if rule.MatchRegex.MatchString(url) || rule.MatchRegex.MatchString(url+"/") {
+			return true
+		}
+	} else if rule.MatchType == matchcompile.PrefixMatch {
+		path := utils.ProcessPath(rule.MatchPath)
+		if url == path || strings.HasPrefix(url, path+"/") {
+			return true
+		}
+	} else if rule.MatchType == matchcompile.PrecisionMatch {
+		path := utils.ProcessPath(rule.MatchPath)
+		if url == path {
+			return true
+		}
+	}
+	return true
+}

+ 8 - 5
src/server/proxytrust.go

@@ -1,13 +1,14 @@
 package server
 
 import (
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"net"
 	"net/http"
 )
 
-func (s *HTTPServer) checkProxyTrust(w http.ResponseWriter, r *http.Request) bool {
-	if !s.cfg.Yaml.Http.RemoteTrust.Enable() {
+func (s *HTTPServer) checkProxyTrust(rule *rulescompile.RuleCompileConfig, w http.ResponseWriter, r *http.Request) bool {
+	if !rule.UseTrustedIPs {
 		return true
 	}
 
@@ -23,10 +24,12 @@ func (s *HTTPServer) checkProxyTrust(w http.ResponseWriter, r *http.Request) boo
 	}
 
 	remoteIP := net.ParseIP(remoteIPStr)
+	if remoteIP == nil {
+		s.abortForbidden(w)
+		return false
+	}
 
-	trust := s.cfg.Yaml.Http.RemoteTrust.TrustedIPs
-
-	for _, t := range trust {
+	for _, t := range rule.TrustedIPs {
 		if utils.ValidIPv4(t) || utils.ValidIPv6(t) {
 			trustIP := net.ParseIP(t)
 			if trustIP == nil {

+ 6 - 5
src/server/respose.go

@@ -3,14 +3,15 @@ package server
 import (
 	"fmt"
 	resource "github.com/SongZihuan/huan-proxy"
-	"github.com/SongZihuan/huan-proxy/src/config"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/apicompile"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"net/http"
 	"strings"
 )
 
-const XHuanProxyHeaer = config.XHuanProxyHeaer
-const ViaHeader = config.ViaHeader
+const XHuanProxyHeaer = apicompile.XHuanProxyHeaer
+const ViaHeader = apicompile.ViaHeader
 
 func (s *HTTPServer) writeHuanProxyHeader(r *http.Request) {
 	version := strings.TrimSpace(utils.StringToOnlyPrint(resource.Version))
@@ -24,8 +25,8 @@ func (s *HTTPServer) writeHuanProxyHeader(r *http.Request) {
 	r.Header.Set(XHuanProxyHeaer, h)
 }
 
-func (s *HTTPServer) writeViaHeader(rule *config.ProxyConfig, r *http.Request) {
-	info := fmt.Sprintf("%s %s", r.Proto, rule.Via)
+func (s *HTTPServer) writeViaHeader(rule *rulescompile.RuleCompileConfig, r *http.Request) {
+	info := fmt.Sprintf("%s %s", r.Proto, rule.Api.Via)
 
 	h := r.Header.Get(ViaHeader)
 	if h == "" {

+ 0 - 41
src/server/server.go

@@ -6,9 +6,7 @@ import (
 	"github.com/SongZihuan/huan-proxy/src/config"
 	"github.com/SongZihuan/huan-proxy/src/flagparser"
 	"github.com/SongZihuan/huan-proxy/src/logger"
-	"github.com/SongZihuan/huan-proxy/src/utils"
 	"net/http"
-	"strings"
 )
 
 var ServerStop = fmt.Errorf("server stop")
@@ -56,42 +54,3 @@ func (s *HTTPServer) run() error {
 func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	s.LoggerServerHTTP(w, r, s.NormalServeHTTP)
 }
-
-func (s *HTTPServer) NormalServeHTTP(w http.ResponseWriter, r *http.Request) {
-	s.writeHuanProxyHeader(r)
-	if !s.checkProxyTrust(w, r) {
-		return
-	}
-
-	func() {
-		for ruleIndex, rule := range s.cfg.Yaml.Rules.Rules {
-			if rule.Type == config.ProxyTypeFile {
-				url := utils.ProcessPath(r.URL.Path)
-				if url == rule.BasePath {
-					if s.corsHandler(w, r) {
-						s.fileServer(rule, w, r)
-					}
-					return
-				}
-			} else if rule.Type == config.ProxyTypeDir {
-				if r.Method == http.MethodGet {
-					urlpath := utils.ProcessPath(r.URL.Path)
-					if urlpath == rule.BasePath || strings.HasPrefix(urlpath, rule.BasePath+"/") {
-						if s.corsHandler(w, r) {
-							s.dirServer(ruleIndex, rule, w, r)
-						}
-						return
-					}
-				}
-			} else if rule.Type == config.ProxyTypeAPI {
-				urlpath := utils.ProcessPath(r.URL.Path)
-				if urlpath == rule.BasePath || strings.HasPrefix(urlpath, rule.BasePath+"/") {
-					s.apiServer(ruleIndex, rule, w, r)
-					return
-				}
-			}
-		}
-
-		s.abortNotFound(w)
-	}()
-}

+ 38 - 0
src/server/serverhttp.go

@@ -0,0 +1,38 @@
+package server
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"net/http"
+)
+
+func (s *HTTPServer) NormalServeHTTP(w http.ResponseWriter, r *http.Request) {
+	s.writeHuanProxyHeader(r)
+
+	func() {
+		for _, rule := range s.cfg.Rules.Rules {
+			if !s.matchURL(rule, r) {
+				continue
+			}
+
+			if !s.checkProxyTrust(rule, w, r) {
+				return
+			}
+
+			if rule.Type == rulescompile.ProxyTypeFile {
+				s.fileServer(rule, w, r)
+				return
+			} else if rule.Type == rulescompile.ProxyTypeDir {
+				s.dirServer(rule, w, r)
+				return
+			} else if rule.Type == rulescompile.ProxyTypeAPI {
+				s.apiServer(rule, w, r)
+				return
+			} else {
+				s.abortServerError(w)
+				return
+			}
+		}
+
+		s.abortNotFound(w)
+	}()
+}