From ea5dfc8f4fb5f8d49cd9fd1bd607d0a399fb9537 Mon Sep 17 00:00:00 2001 From: "A.Unger" Date: Wed, 4 Mar 2020 10:34:18 +0100 Subject: [PATCH] move MultiHostReverseProxy logic away from the server command --- pkg/command/server.go | 83 +---------------------------------------- pkg/proxy/proxy.go | 87 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 81 deletions(-) create mode 100644 pkg/proxy/proxy.go diff --git a/pkg/command/server.go b/pkg/command/server.go index 7275ca8e1..ce809cad7 100644 --- a/pkg/command/server.go +++ b/pkg/command/server.go @@ -2,9 +2,6 @@ package command import ( "context" - gohttp "net/http" - "net/http/httputil" - "net/url" "os" "os/signal" "strings" @@ -21,18 +18,13 @@ import ( "github.com/owncloud/ocis-proxy/pkg/config" "github.com/owncloud/ocis-proxy/pkg/flagset" "github.com/owncloud/ocis-proxy/pkg/metrics" + "github.com/owncloud/ocis-proxy/pkg/proxy" "github.com/owncloud/ocis-proxy/pkg/server/debug" "github.com/owncloud/ocis-proxy/pkg/server/http" "go.opencensus.io/stats/view" "go.opencensus.io/trace" ) -// ReverseProxy extends httputil to support multiple hosts with diffent policies -type ReverseProxy struct { - httputil.ReverseProxy - Directors map[string]map[string]func(req *gohttp.Request) -} - // Server is the entrypoint for the server command. func Server(cfg *config.Config) *cli.Command { return &cli.Command{ @@ -142,7 +134,7 @@ func Server(cfg *config.Config) *cli.Command { defer cancel() - rp := NewMultiHostReverseProxy(cfg) + rp := proxy.NewMultiHostReverseProxy(cfg) { server, err := http.Server( @@ -232,74 +224,3 @@ func Server(cfg *config.Config) *cli.Command { }, } } - -// NewMultiHostReverseProxy undocummented -func NewMultiHostReverseProxy(conf *config.Config) *ReverseProxy { - reverseProxy := &ReverseProxy{Directors: make(map[string]map[string]func(req *gohttp.Request))} - - for _, policy := range conf.Policies { - for _, route := range policy.Routes { - uri, err := url.Parse(route.Backend) - if err != nil { /* do something with err */ - } - reverseProxy.AddHost(policy.Name, uri, route.Endpoint) - } - } - - return reverseProxy -} - -func singleJoiningSlash(a, b string) string { - aslash := strings.HasSuffix(a, "/") - bslash := strings.HasPrefix(b, "/") - switch { - case aslash && bslash: - return a + b[1:] - case !aslash && !bslash: - return a + "/" + b - } - return a + b -} - -// AddHost undocumented -func (p *ReverseProxy) AddHost(policy string, target *url.URL, endpoint string) { - targetQuery := target.RawQuery - if p.Directors[policy] == nil { - p.Directors[policy] = make(map[string]func(req *gohttp.Request)) - } - p.Directors[policy][endpoint] = func(req *gohttp.Request) { - req.URL.Scheme = target.Scheme - req.URL.Host = target.Host - req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path) - if targetQuery == "" || req.URL.RawQuery == "" { - req.URL.RawQuery = targetQuery + req.URL.RawQuery - } else { - req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery - } - if _, ok := req.Header["User-Agent"]; !ok { - // explicitly disable User-Agent so it's not set to default value - req.Header.Set("User-Agent", "") - } - } -} - -func (p *ReverseProxy) ServeHTTP(rw gohttp.ResponseWriter, req *gohttp.Request) { - // TODO need to fetch from the accounts service - policy := "reva" - var hit bool - - for k := range p.Directors[policy] { - if strings.HasPrefix(req.URL.Path, k) && k != "/" { - p.Director = p.Directors[policy][k] - hit = true - } - } - - // override default director with root. If any - if !hit && p.Directors[policy]["/"] != nil { - p.Director = p.Directors[policy]["/"] - } - - // Call upstream ServeHTTP - p.ReverseProxy.ServeHTTP(rw, req) -} diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go new file mode 100644 index 000000000..3ba45f39e --- /dev/null +++ b/pkg/proxy/proxy.go @@ -0,0 +1,87 @@ +package proxy + +import ( + "net/http" + "net/http/httputil" + "net/url" + "strings" + + "github.com/owncloud/ocis-proxy/pkg/config" +) + +// MultiHostReverseProxy extends httputil to support multiple hosts with diffent policies +type MultiHostReverseProxy struct { + httputil.ReverseProxy + Directors map[string]map[string]func(req *http.Request) +} + +// NewMultiHostReverseProxy undocummented +func NewMultiHostReverseProxy(conf *config.Config) *MultiHostReverseProxy { + reverseProxy := &MultiHostReverseProxy{Directors: make(map[string]map[string]func(req *http.Request))} + + for _, policy := range conf.Policies { + for _, route := range policy.Routes { + uri, err := url.Parse(route.Backend) + if err != nil { /* do something with err */ + } + reverseProxy.AddHost(policy.Name, uri, route.Endpoint) + } + } + + return reverseProxy +} + +func singleJoiningSlash(a, b string) string { + aslash := strings.HasSuffix(a, "/") + bslash := strings.HasPrefix(b, "/") + switch { + case aslash && bslash: + return a + b[1:] + case !aslash && !bslash: + return a + "/" + b + } + return a + b +} + +// AddHost undocumented +func (p *MultiHostReverseProxy) AddHost(policy string, target *url.URL, endpoint string) { + targetQuery := target.RawQuery + if p.Directors[policy] == nil { + p.Directors[policy] = make(map[string]func(req *http.Request)) + } + p.Directors[policy][endpoint] = func(req *http.Request) { + req.URL.Scheme = target.Scheme + req.URL.Host = target.Host + req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path) + if targetQuery == "" || req.URL.RawQuery == "" { + req.URL.RawQuery = targetQuery + req.URL.RawQuery + } else { + req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery + } + if _, ok := req.Header["User-Agent"]; !ok { + // explicitly disable User-Agent so it's not set to default value + req.Header.Set("User-Agent", "") + } + } +} + +func (p *MultiHostReverseProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // TODO need to fetch from the accounts service + policy := "reva" + var hit bool + + for k := range p.Directors[policy] { + if strings.HasPrefix(r.URL.Path, k) && k != "/" { + p.Director = p.Directors[policy][k] + hit = true + } + } + + // override default director with root. If any + if !hit && p.Directors[policy]["/"] != nil { + p.Director = p.Directors[policy]["/"] + } + + // Call upstream ServeHTTP + p.ReverseProxy.ServeHTTP(w, r) +}