浏览代码

添加重定向功能

新增了处理重定向请求的功能,包括配置解析和服务器处理逻辑,并更新了版本号至v1.0.0。
SongZihuan 3 月之前
父节点
当前提交
dc39940581

+ 1 - 1
VERSION

@@ -1 +1 @@
-v0.1.0
+v1.0.0

+ 1 - 1
src/config/rules/action/api/api.go

@@ -61,7 +61,7 @@ func (r *RuleAPIConfig) SetDefault() {
 func (r *RuleAPIConfig) Check() configerr.ConfigError {
 	targetURL, err := url.Parse(r.Address)
 	if err != nil {
-		return configerr.NewConfigError(fmt.Sprintf("Failed to parse target URL: %v", err))
+		return configerr.NewConfigError(fmt.Sprintf("Failed to parse target URL: %s", err.Error()))
 	}
 
 	if targetURL.Opaque != "" {

+ 41 - 0
src/config/rules/action/redirect/redirectconfig.go

@@ -0,0 +1,41 @@
+package redirect
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/rewrite"
+	"net/http"
+	"net/url"
+)
+
+type RuleRedirectConfig struct {
+	Address string                `yaml:"address"`
+	Rewrite rewrite.RewriteConfig `yaml:"rewrite"`
+	Code    int                   `yaml:"code"`
+}
+
+func (r *RuleRedirectConfig) SetDefault() {
+	if r.Code == 0 {
+		r.Code = http.StatusMovedPermanently
+	}
+
+	r.Rewrite.SetDefault()
+}
+
+func (r *RuleRedirectConfig) Check() configerr.ConfigError {
+	_, err := url.Parse(r.Address)
+	if err != nil {
+		return configerr.NewConfigError(fmt.Sprintf("Failed to parse target URL: %s", err.Error()))
+	}
+
+	cfgErr := r.Rewrite.Check()
+	if cfgErr != nil && cfgErr.IsError() {
+		return cfgErr
+	}
+
+	if r.Code != http.StatusMovedPermanently && r.Code != http.StatusMultipleChoices {
+		return configerr.NewConfigError(fmt.Sprintf("Redirect code must be %d %d: you use %d", http.StatusMovedPermanently, http.StatusMultipleChoices, r.Code))
+	}
+
+	return nil
+}

+ 16 - 6
src/config/rules/ruleconfig.go

@@ -5,14 +5,16 @@ import (
 	"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/redirect"
 	"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"
+	ProxyTypeFile     = "file"
+	ProxyTypeDir      = "dir"
+	ProxyTypeAPI      = "api"
+	ProxyTypeRedirect = "redirect"
 )
 
 type RuleConfig struct {
@@ -21,9 +23,10 @@ type RuleConfig struct {
 	match.MatchConfig             `yaml:",inline"`
 	remotetrust.RemoteTrustConfig `yaml:",inline"`
 
-	File file.RuleFileConfig `yaml:"file"`
-	Dir  dir.RuleDirConfig   `yaml:"dir"`
-	Api  api.RuleAPIConfig   `yaml:"api"`
+	File     file.RuleFileConfig         `yaml:"file"`
+	Dir      dir.RuleDirConfig           `yaml:"dir"`
+	Api      api.RuleAPIConfig           `yaml:"api"`
+	Redirect redirect.RuleRedirectConfig `yaml:"redirect"`
 }
 
 func (p *RuleConfig) SetDefault() {
@@ -36,6 +39,8 @@ func (p *RuleConfig) SetDefault() {
 		p.Dir.SetDefault()
 	} else if p.Type == ProxyTypeAPI {
 		p.Api.SetDefault()
+	} else if p.Type == ProxyTypeRedirect {
+		p.Redirect.SetDefault()
 	}
 }
 
@@ -65,6 +70,11 @@ func (p *RuleConfig) Check() configerr.ConfigError {
 		if err != nil && err.IsError() {
 			return err
 		}
+	} else if p.Type == ProxyTypeRedirect {
+		err := p.Redirect.Check()
+		if err != nil && err.IsError() {
+			return err
+		}
 	} else {
 		return configerr.NewConfigError("proxy type must be file or dir or api")
 	}

+ 33 - 0
src/config/rulescompile/actioncompile/redirectcompile/redirectcompile.go

@@ -0,0 +1,33 @@
+package redirectcompile
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config/rules/action/redirect"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/rewritecompile"
+	"net/url"
+)
+
+type RuleRedirectCompileConfig struct {
+	Address   string
+	TargetURL *url.URL
+	Rewrite   *rewritecompile.RewriteCompileConfig
+	Code      int
+}
+
+func NewRuleAPICompileConfig(r *redirect.RuleRedirectConfig) (*RuleRedirectCompileConfig, error) {
+	rewrite, err := rewritecompile.NewRewriteCompileConfig(&r.Rewrite)
+	if err != nil {
+		return nil, err
+	}
+
+	targetURL, err := url.Parse(r.Address)
+	if err != nil {
+		return nil, err
+	}
+
+	return &RuleRedirectCompileConfig{
+		Address:   r.Address,
+		TargetURL: targetURL,
+		Rewrite:   rewrite,
+		Code:      r.Code,
+	}, nil
+}

+ 26 - 9
src/config/rulescompile/ruleconfig.go

@@ -6,26 +6,30 @@ import (
 	"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/redirectcompile"
 	"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
+	RulesProxyTypeFile     = rules.ProxyTypeFile
+	RulesProxyTypeDir      = rules.ProxyTypeDir
+	RulesProxyTypeAPI      = rules.ProxyTypeAPI
+	RulesProxyTypeRedirect = rules.ProxyTypeRedirect
 )
 
 const (
 	ProxyTypeFile = iota
 	ProxyTypeDir
 	ProxyTypeAPI
+	ProxyTypeRedirect
 )
 
 var ProxyTypeMap = map[string]int{
-	RulesProxyTypeFile: ProxyTypeFile,
-	RulesProxyTypeDir:  ProxyTypeDir,
-	RulesProxyTypeAPI:  ProxyTypeAPI,
+	RulesProxyTypeFile:     ProxyTypeFile,
+	RulesProxyTypeDir:      ProxyTypeDir,
+	RulesProxyTypeAPI:      ProxyTypeAPI,
+	RulesProxyTypeRedirect: ProxyTypeRedirect,
 }
 
 type RuleCompileConfig struct {
@@ -34,9 +38,10 @@ type RuleCompileConfig struct {
 	*matchcompile.MatchCompileConfig
 	*remotetrustcompile.RemoteTrustCompileConfig
 
-	File *filecompile.RuleFileCompileConfig
-	Dir  *dircompile.RuleDirCompileConfig
-	Api  *apicompile.RuleAPICompileConfig
+	File     *filecompile.RuleFileCompileConfig
+	Dir      *dircompile.RuleDirCompileConfig
+	Api      *apicompile.RuleAPICompileConfig
+	Redirect *redirectcompile.RuleRedirectCompileConfig
 }
 
 func NewRuleCompileConfig(r *rules.RuleConfig) (*RuleCompileConfig, error) {
@@ -91,6 +96,18 @@ func NewRuleCompileConfig(r *rules.RuleConfig) (*RuleCompileConfig, error) {
 			RemoteTrustCompileConfig: remoteTrusts,
 			Api:                      api,
 		}, nil
+	} else if typeID == ProxyTypeRedirect {
+		redirect, err := redirectcompile.NewRuleAPICompileConfig(&r.Redirect)
+		if err != nil {
+			return nil, err
+		}
+
+		return &RuleCompileConfig{
+			Type:                     typeID,
+			MatchCompileConfig:       match,
+			RemoteTrustCompileConfig: remoteTrusts,
+			Redirect:                 redirect,
+		}, nil
 	} else {
 		return nil, fmt.Errorf("error rule type")
 	}

+ 11 - 15
src/mainfunc/v1.go

@@ -65,27 +65,23 @@ func MainV1() int {
 
 	ser := server.NewServer()
 
-	serstop := make(chan bool)
-	sererror := make(chan error)
+	httpchan := make(chan error)
 
 	go func() {
-		err := ser.Run()
-		if errors.Is(err, server.ServerStop) {
-			serstop <- true
-		} else if err != nil {
-			sererror <- err
-		} else {
-			serstop <- false
-		}
+		httpchan <- ser.RunHttp()
 	}()
 
 	select {
 	case <-config.GetSignalChan():
-		break
-	case err := <-sererror:
-		return utils.ExitByError(err)
-	case <-serstop:
-		break
+		return 0
+	case err := <-httpchan:
+		if errors.Is(err, server.ServerStop) {
+			return 0
+		} else if err != nil {
+			return utils.ExitByError(err)
+		} else {
+			return 0
+		}
 	}
 
 	return 0

+ 29 - 0
src/server/redirect.go

@@ -0,0 +1,29 @@
+package server
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/rewritecompile"
+	"net/http"
+	"net/url"
+)
+
+func (s *HTTPServer) redirectServer(rule *rulescompile.RuleCompileConfig, w http.ResponseWriter, r *http.Request) {
+	target := s.redirectRewrite(rule.Redirect.Address, rule.Redirect.Rewrite)
+
+	if _, err := url.Parse(target); err != nil {
+		s.abortServerError(w)
+		return
+	}
+
+	fmt.Printf("target: %s\n", target)
+	s.statusRedirect(w, r, target, rule.Redirect.Code)
+}
+
+func (s *HTTPServer) redirectRewrite(address string, rewrite *rewritecompile.RewriteCompileConfig) string {
+	if rewrite.Use && rewrite.Regex != nil {
+		rewrite.Regex.ReplaceAllString(address, rewrite.Target)
+	}
+
+	return address
+}

+ 4 - 0
src/server/respose.go

@@ -65,3 +65,7 @@ func (s *HTTPServer) abortNoContent(w http.ResponseWriter) {
 func (s *HTTPServer) statusOK(w http.ResponseWriter) {
 	w.WriteHeader(http.StatusOK)
 }
+
+func (s *HTTPServer) statusRedirect(w http.ResponseWriter, r *http.Request, url string, code int) {
+	http.Redirect(w, r, url, code)
+}

+ 3 - 3
src/server/server.go

@@ -49,8 +49,8 @@ func (s *HTTPServer) GetRulesList() []*rulescompile.RuleCompileConfig {
 	return s.GetRules().Rules
 }
 
-func (s *HTTPServer) Run() error {
-	err := s.run()
+func (s *HTTPServer) RunHttp() error {
+	err := s.runHttp()
 	if errors.Is(err, http.ErrServerClosed) {
 		return ServerStop
 	} else if err != nil {
@@ -60,7 +60,7 @@ func (s *HTTPServer) Run() error {
 	return nil
 }
 
-func (s *HTTPServer) run() error {
+func (s *HTTPServer) runHttp() error {
 	logger.Infof("start server in %s", s.address)
 	return http.ListenAndServe(s.address, s)
 }

+ 6 - 0
src/server/serverhttp.go

@@ -1,6 +1,7 @@
 package server
 
 import (
+	"fmt"
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
 	"net/http"
 )
@@ -18,6 +19,8 @@ func (s *HTTPServer) NormalServeHTTP(w http.ResponseWriter, r *http.Request) {
 				return
 			}
 
+			fmt.Printf("rule.Type: %d\n", rule.Type)
+
 			if rule.Type == rulescompile.ProxyTypeFile {
 				s.fileServer(rule, w, r)
 				return
@@ -27,6 +30,9 @@ func (s *HTTPServer) NormalServeHTTP(w http.ResponseWriter, r *http.Request) {
 			} else if rule.Type == rulescompile.ProxyTypeAPI {
 				s.apiServer(rule, w, r)
 				return
+			} else if rule.Type == rulescompile.ProxyTypeRedirect {
+				s.redirectServer(rule, w, r)
+				return
 			} else {
 				s.abortServerError(w)
 				return