package proxy import ( "net/http" "net/http/httputil" "net/url" "path" "strings" ) // NewReverseProxy builds a reverse proxy to target base URL with path rewriting: // stripPrefix (/api/{alias}) + pathPrefix (/v1) + remainder, prepended to target.Path // (so base_url https://host/api/ yields upstream /api/v1/...). func NewReverseProxy(target *url.URL, stripPrefix, pathPrefix string, setAuth string) *httputil.ReverseProxy { proxy := httputil.NewSingleHostReverseProxy(target) orig := proxy.Director targetQuery := target.RawQuery proxy.Director = func(req *http.Request) { p := req.URL.Path if !strings.HasPrefix(p, stripPrefix) { orig(req) if setAuth != "" { req.Header.Set("Authorization", setAuth) } return } rest := strings.TrimPrefix(p, stripPrefix) rest = strings.TrimPrefix(rest, "/") upPath := buildUpstreamPath(target.Path, pathPrefix, rest) req.URL.Scheme = target.Scheme req.URL.Host = target.Host req.URL.Path = upPath req.URL.RawPath = "" if targetQuery == "" || req.URL.RawQuery == "" { req.URL.RawQuery = targetQuery + req.URL.RawQuery } else { req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery } if setAuth != "" { req.Header.Set("Authorization", setAuth) } } return proxy } func buildUpstreamPath(targetPath, pathPrefix, rest string) string { base := strings.TrimSuffix(targetPath, "/") p := strings.Trim(pathPrefix, "/") r := strings.Trim(rest, "/") var segs []string if base != "" { segs = append(segs, base) } if p != "" { segs = append(segs, p) } if r != "" { segs = append(segs, r) } if len(segs) == 0 { return "/" } out := path.Join(segs...) if !strings.HasPrefix(out, "/") { out = "/" + out } return out }