1
0
Эх сурвалжийг харах

更新代理配置和请求处理逻辑

修改了`proxyconfig.go`中的路径检查逻辑,以更准确地匹配基础路径与子前缀路径。在`api.go`中调整了对请求头的处理方式,并引入了`utils.SplitHostPort`函数来分离主机名和端口,确保转发信息的准确性。同时,在设置转发头部时增加了空格以提高可读性。
SongZihuan 3 сар өмнө
parent
commit
b7e3e81463

+ 158 - 5
src/config/proxyconfig.go

@@ -13,6 +13,9 @@ const (
 	ProxyTypeAPI  = "api"
 	ProxyTypeAPI  = "api"
 )
 )
 
 
+const XHuanProxyHeaer = "X-Huan-Proxy"
+const ViaHeader = "Via"
+
 type ProxyConfig struct {
 type ProxyConfig struct {
 	Type     string `yaml:"type"`
 	Type     string `yaml:"type"`
 	BasePath string `yaml:"basepath"`
 	BasePath string `yaml:"basepath"`
@@ -32,14 +35,49 @@ type ProxyDirConfig struct {
 	IgnoreFile []*IgnoreFile `yaml:"ignorefile"`
 	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 {
 type ProxyAPIConfig struct {
-	Address       string `yaml:"address"`
-	AddPrefixPath string `yaml:"addprefixpath"`
-	SubPrefixPath string `yaml:"subprefixpath"`
-	RewriteReg    string `yaml:"rewritereg"`
-	RewriteTarget string `yaml:"rewritetarget"`
+	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() {
 func (p *ProxyConfig) setDefault() {
 	p.BasePath = utils.ProcessPath(p.BasePath)
 	p.BasePath = utils.ProcessPath(p.BasePath)
 
 
@@ -75,6 +113,10 @@ func (p *ProxyConfig) setDefault() {
 	} else if p.Type == ProxyTypeAPI {
 	} else if p.Type == ProxyTypeAPI {
 		p.AddPrefixPath = utils.ProcessPath(p.AddPrefixPath)
 		p.AddPrefixPath = utils.ProcessPath(p.AddPrefixPath)
 		p.SubPrefixPath = utils.ProcessPath(p.SubPrefixPath)
 		p.SubPrefixPath = utils.ProcessPath(p.SubPrefixPath)
+
+		if p.Via == "" {
+			p.Via = defaultVia
+		}
 	}
 	}
 }
 }
 
 
@@ -114,8 +156,119 @@ func (p *ProxyConfig) check() ConfigError {
 		if len(p.RewriteTarget) != 0 && len(p.RewriteReg) == 0 {
 		if len(p.RewriteTarget) != 0 && len(p.RewriteReg) == 0 {
 			return NewConfigError("rewrite reg is empty")
 			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 {
 	} else {
 		return NewConfigError("proxy type must be file or dir or api")
 		return NewConfigError("proxy type must be file or dir or api")
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+func isNotGoodHeader(header string) bool {
+	for _, h := range WarningHeader {
+		if h == header {
+			return true
+		}
+	}
+
+	return false
+}

+ 31 - 0
src/server/api.go

@@ -3,6 +3,7 @@ package server
 import (
 import (
 	"fmt"
 	"fmt"
 	"github.com/SongZihuan/huan-proxy/src/config"
 	"github.com/SongZihuan/huan-proxy/src/config"
+	"github.com/SongZihuan/huan-proxy/src/logger"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"net"
 	"net"
 	"net/http"
 	"net/http"
@@ -46,6 +47,36 @@ func (s *HTTPServer) apiServer(ruleIndex int, rule *config.ProxyConfig, w http.R
 
 
 	r.URL.Path = path
 	r.URL.Path = path
 
 
+	for _, h := range rule.Header {
+		r.Header.Set(h.Header, h.Value)
+	}
+
+	for _, h := range rule.HeaderAdd {
+		r.Header.Add(h.Header, h.Value)
+	}
+
+	for _, h := range rule.HeaderDel {
+		r.Header.Del(h)
+	}
+
+	query := r.URL.Query()
+
+	for _, q := range rule.Query {
+		query.Set(q.Query, q.Value)
+	}
+
+	for _, q := range rule.QueryAdd {
+		query.Add(q.Query, q.Value)
+	}
+
+	for _, q := range rule.QueryDel {
+		logger.Tagf("A '%s'", q)
+		query.Del(q)
+	}
+
+	r.URL.RawQuery = query.Encode()
+
+	s.writeViaHeader(rule, r)
 	proxy.ServeHTTP(w, r) // 反向代理
 	proxy.ServeHTTP(w, r) // 反向代理
 }
 }
 
 

+ 17 - 3
src/server/respose.go

@@ -3,14 +3,16 @@ package server
 import (
 import (
 	"fmt"
 	"fmt"
 	resource "github.com/SongZihuan/huan-proxy"
 	resource "github.com/SongZihuan/huan-proxy"
+	"github.com/SongZihuan/huan-proxy/src/config"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
 )
 )
 
 
-const XHuanProxyHeaer = "X-Huan-Proxy"
+const XHuanProxyHeaer = config.XHuanProxyHeaer
+const ViaHeader = config.ViaHeader
 
 
-func (s *HTTPServer) writeHuanProxyHeader(w http.ResponseWriter, r *http.Request) {
+func (s *HTTPServer) writeHuanProxyHeader(r *http.Request) {
 	version := strings.TrimSpace(utils.StringToOnlyPrint(resource.Version))
 	version := strings.TrimSpace(utils.StringToOnlyPrint(resource.Version))
 	h := r.Header.Get(XHuanProxyHeaer)
 	h := r.Header.Get(XHuanProxyHeaer)
 	if h == "" {
 	if h == "" {
@@ -20,7 +22,19 @@ func (s *HTTPServer) writeHuanProxyHeader(w http.ResponseWriter, r *http.Request
 	}
 	}
 
 
 	r.Header.Set(XHuanProxyHeaer, h)
 	r.Header.Set(XHuanProxyHeaer, h)
-	w.Header().Set(XHuanProxyHeaer, h)
+}
+
+func (s *HTTPServer) writeViaHeader(rule *config.ProxyConfig, r *http.Request) {
+	info := fmt.Sprintf("%s %s", r.Proto, rule.Via)
+
+	h := r.Header.Get(ViaHeader)
+	if h == "" {
+		h = info
+	} else {
+		h = fmt.Sprintf("%s, %s", h, info)
+	}
+
+	r.Header.Set(ViaHeader, h)
 }
 }
 
 
 func (s *HTTPServer) abortForbidden(w http.ResponseWriter) {
 func (s *HTTPServer) abortForbidden(w http.ResponseWriter) {

+ 1 - 1
src/server/server.go

@@ -46,7 +46,7 @@ func (s *HTTPServer) run() error {
 }
 }
 
 
 func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	s.writeHuanProxyHeader(w, r)
+	s.writeHuanProxyHeader(r)
 	if !s.checkProxyTrust(w, r) {
 	if !s.checkProxyTrust(w, r) {
 		return
 		return
 	}
 	}

+ 12 - 0
src/utils/string.go

@@ -139,3 +139,15 @@ func StringToOnlyPrint(str string) string {
 
 
 	return string(res)
 	return string(res)
 }
 }
+
+func IsGoodQueryKey(key string) bool {
+	pattern := `^[a-zA-Z0-9\-._~]+$`
+	matched, _ := regexp.MatchString(pattern, key)
+	return matched
+}
+
+func IsValidHTTPHeaderKey(key string) bool {
+	pattern := `^[a-zA-Z0-9!#$%&'*+.^_` + "`" + `|~-]+$`
+	matched, _ := regexp.MatchString(pattern, key)
+	return matched
+}