From 618a1862985ee84ebf031869613eecf5fe5910c6 Mon Sep 17 00:00:00 2001 From: kingecg Date: Thu, 14 Dec 2023 23:47:04 +0800 Subject: [PATCH] make proxy yse directive and forbidden get/set admin by api --- admin/admin.go | 12 +++++++ gohttp.go | 30 +++------------- hander/proxy.go | 56 +++++++++++++----------------- {server => hander}/proxyupdater.go | 16 +++++++-- model/model.go | 22 ++++-------- server/directive.go | 2 ++ server/server.go | 32 +++++++++++++++++ 7 files changed, 95 insertions(+), 75 deletions(-) rename {server => hander}/proxyupdater.go (77%) diff --git a/admin/admin.go b/admin/admin.go index 898e205..04a2699 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -1,6 +1,7 @@ package admin import ( + "errors" "net/http" "os" "runtime" @@ -28,6 +29,11 @@ func setConfig(w http.ResponseWriter, r *http.Request) { return } t := data.(model.HttpServerConfig) + if t.Name == "admin" { + w.WriteHeader(http.StatusForbidden) + resp := server.NewErrorResult(errors.New("不能通过api设置管理服务器")) + w.Write(resp) + } err := model.SetServerConfig(&t) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -46,6 +52,12 @@ func getServerConfigure(w http.ResponseWriter, r *http.Request) { ctxData := ctx.Value(server.RequestCtxKey("data")).(map[string]interface{}) id, ok := ctxData["id"] if ok { + if id.(string) == "admin" { + w.WriteHeader(http.StatusForbidden) + resp := server.NewErrorResult(errors.New("不能通过api获取管理服务器配置信息")) + w.Write(resp) + return + } data := model.GetServerConfig(id.(string)) /// configContent, _ := json.Marshal(data) w.WriteHeader(http.StatusOK) diff --git a/gohttp.go b/gohttp.go index 8f6b154..c14c348 100644 --- a/gohttp.go +++ b/gohttp.go @@ -6,7 +6,6 @@ import ( "os" "git.pyer.club/kingecg/gohttpd/admin" - handler "git.pyer.club/kingecg/gohttpd/hander" "git.pyer.club/kingecg/gohttpd/model" "git.pyer.club/kingecg/gohttpd/server" "git.pyer.club/kingecg/gohttpd/utils" @@ -22,13 +21,13 @@ func (g *GoHttp) Start() { g.logger = gologger.GetLogger("Server") g.logger.Info("start gohttpd") // if g.conf != nil { - adminHandler := g.assembleServerMux(conf.Admin.Paths) - adminHandler.(*http.ServeMux).Handle("/api/", http.StripPrefix("/api", admin.AdminServerMux)) + adminHandler := server.NewServeMux(conf.Admin) + adminHandler.Handle("/api/", http.StripPrefix("/api", admin.AdminServerMux)) g.makeServer(conf.Admin, adminHandler) - for _, server := range conf.Servers { - sHandler := g.assembleServerMux(server.Paths) - g.makeServer(server, sHandler) + for _, s := range conf.Servers { + sHandler := server.NewServeMux(s) + g.makeServer(s, sHandler) } for _, listener := range server.ServerManager { @@ -52,25 +51,6 @@ func (g *GoHttp) makeServer(conf *model.HttpServerConfig, mux http.Handler) { server.AddServer(name, ss, port) } -func (g *GoHttp) assembleServerMux(p []model.HttpPath) http.Handler { - s := http.NewServeMux() - for _, httpPath := range p { - if httpPath.Root != "" { - fileHandler := handler.NewFileHandler(handler.FileHandler{ - Root: httpPath.Root, - Default: httpPath.Default, - }) - s.Handle(httpPath.Path, fileHandler) - } else if len(httpPath.Upstreams) != 0 { - proxyHandler := handler.NewProxyHandler(&httpPath) - s.Handle(httpPath.Path, proxyHandler) - } else { - g.logger.Error("Not supportted server path type :", httpPath.Path) - } - } - return s -} - func (g *GoHttp) Stop() {} func LoadConfig() { diff --git a/hander/proxy.go b/hander/proxy.go index fbb6db0..f1f63dd 100644 --- a/hander/proxy.go +++ b/hander/proxy.go @@ -3,7 +3,6 @@ package handler import ( "net/http" "net/http/httputil" - "net/url" "strconv" "strings" @@ -30,39 +29,34 @@ func (p *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { p.proxy[proxyIndex].ServeHTTP(w, r) } -// init httputil.ReverseProxy instance and add path rewrite and add session-sticky cookie to response +/* +* +init httputil.ReverseProxy instance and add path rewrite and add session-sticky cookie to response +@param upstream upstream server url +@param path http path config +@param index the proxy index in upstreams + +@return httputil.ReverseProxy instance + +what is the directive? its stands for update of request, like HostSchemas, Path, RemoveCookie, etc. +eg: HostSchemas $target +it stande for replace req url host and schema according to $target url. $target == upstream +*/ func makeProxy(upstream string, path *model.HttpPath, index int) *httputil.ReverseProxy { p := &httputil.ReverseProxy{} + directiveHandlers := []func(r *http.Request){} + if len(path.Directives) > 0 { + for _, directive := range path.Directives { + d := strings.Replace(string(directive), "$target", upstream, 1) + dh := GetUpdaterFn(d) + if dh != nil { + directiveHandlers = append(directiveHandlers, dh) + } + } + } p.Director = func(req *http.Request) { - turl, _ := url.Parse(upstream) - req.URL.Host = turl.Host - req.URL.Scheme = turl.Scheme - pw := path.Rewrite - if pw.Replace != "" { - req.URL.Path = strings.TrimPrefix(req.URL.Path, pw.Replace) - if req.URL.RawPath != "" { - req.URL.RawPath = strings.TrimPrefix(req.URL.RawPath, pw.Replace) - } - } - if pw.With != "" { - req.URL.Path = strings.TrimSuffix(pw.With, "/") + "/" + req.URL.Path - if req.URL.RawPath != "" { - req.URL.RawPath = strings.TrimSuffix(pw.With, "/") + "/" + req.URL.RawPath - } - } - - if len(path.Headers) > 0 { - for _, header := range path.Headers { - //req.Header.Add(header.Name, header.Value) - value := "" - switch header.Value { - case string(model.ProxyHost): - value = turl.Host - default: - value = header.Value - } - req.Header.Set(header.Name, value) - } + for _, handler := range directiveHandlers { + handler(req) } } diff --git a/server/proxyupdater.go b/hander/proxyupdater.go similarity index 77% rename from server/proxyupdater.go rename to hander/proxyupdater.go index d3ccaf6..6a0ef47 100644 --- a/server/proxyupdater.go +++ b/hander/proxyupdater.go @@ -1,7 +1,8 @@ -package server +package handler import ( "net/http" + "net/url" "strings" "github.com/samber/lo" @@ -10,9 +11,18 @@ import ( type ProxyRequestUpdater func(arg ...string) func(r *http.Request) var ProxyRequestUpdateMap = map[string]ProxyRequestUpdater{ - "Host": func(arg ...string) func(r *http.Request) { + "HostSchemas": func(arg ...string) func(r *http.Request) { + targetUrl := arg[0] return func(r *http.Request) { - r.Host = arg[0] + turl, _ := url.Parse(targetUrl) + r.URL.Host = turl.Host + r.URL.Scheme = turl.Scheme + } + }, + "HeaderOrigin": func(arg ...string) func(r *http.Request) { + + return func(r *http.Request) { + r.Header.Set("Origin", r.URL.Scheme+"://"+r.URL.Host) } }, "Path": func(arg ...string) func(r *http.Request) { diff --git a/model/model.go b/model/model.go index eed9738..90ad34e 100644 --- a/model/model.go +++ b/model/model.go @@ -9,22 +9,11 @@ import ( ) type HttpPath struct { - Path string `json:"path"` - Root string `json:"root"` - Default string `json:"default"` - Upstreams []string `json:"upstreams"` - Rewrite PathRewrite `json:"pathrewrite"` - Headers []HeaderDefine `json:"headers"` -} - -type PathRewrite struct { - Replace string `json:"replace"` - With string `json:"with"` -} - -type HeaderDefine struct { - Name string `json:"name"` - Value string `json:"value"` + Path string `json:"path"` + Root string `json:"root"` + Default string `json:"default"` + Upstreams []string `json:"upstreams"` + Directives string `json:"directives"` } type HeaderValueConst string @@ -43,6 +32,7 @@ type HttpServerConfig struct { Password string `json:"password"` CertFile string `json:"certfile"` KeyFile string `json:"keyfile"` + Directives string `json:"directives"` } type GoHttpdConfig struct { diff --git a/server/directive.go b/server/directive.go index c5d5538..2ef03eb 100644 --- a/server/directive.go +++ b/server/directive.go @@ -7,12 +7,14 @@ type Directive func(args ...string) Middleware var Add_Header Directive = func(args ...string) Middleware { return func(w http.ResponseWriter, r *http.Request, next func()) { w.Header().Add(args[0], args[1]) + next() } } var Set_Header Directive = func(args ...string) Middleware { return func(w http.ResponseWriter, r *http.Request, next func()) { w.Header().Set(args[0], args[1]) + next() } } diff --git a/server/server.go b/server/server.go index 2efcad0..e369b11 100644 --- a/server/server.go +++ b/server/server.go @@ -7,7 +7,10 @@ import ( "sort" "strings" + handler "git.pyer.club/kingecg/gohttpd/hander" + "git.pyer.club/kingecg/gohttpd/model" "git.pyer.club/kingecg/gologger" + logger "git.pyer.club/kingecg/gologger" ) type RequestCtxKey string @@ -228,3 +231,32 @@ func (s *ServerMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { } http.NotFound(w, r) } + +func NewServeMux(c *model.HttpServerConfig) *ServerMux { + l := logger.GetLogger("ServerMux") + l.Debug("NewServeMux") + s := &ServerMux{ + directiveHandlers: NewMiddlewareLink(), + handlers: make(map[string]http.Handler), + paths: []string{}, + } + + for _, directive := range c.Directives { + s.AddDirective(string(directive)) + } + for _, httpPath := range c.Paths { + if httpPath.Root != "" { + fileHandler := handler.NewFileHandler(handler.FileHandler{ + Root: httpPath.Root, + Default: httpPath.Default, + }) + s.Handle(httpPath.Path, fileHandler) + } else if len(httpPath.Upstreams) != 0 { + proxyHandler := handler.NewProxyHandler(&httpPath) + s.Handle(httpPath.Path, proxyHandler) + } else { + l.Error("Not supportted server path type :", httpPath.Path) + } + } + return s +}