package rest import ( "fmt" "net/http" "net/http/httputil" "net/url" "os" "strings" ) func (s *Server) handleRouteDecisionTree(w http.ResponseWriter, r *http.Request) { s.proxyRouteTreeEndpoint(w, r, "/api/v1/routes/tree") } func (s *Server) handleRouteDepth(w http.ResponseWriter, r *http.Request) { s.proxyRouteTreeEndpoint(w, r, "/api/v1/routes/depth") } func (s *Server) proxyRouteTreeEndpoint(w http.ResponseWriter, r *http.Request, path string) { if r.Method != http.MethodGet { writeMethodNotAllowed(w) return } baseURL := strings.TrimSpace(firstNonEmptyEnv( "TOKEN_AGGREGATION_API_BASE", "TOKEN_AGGREGATION_URL", "TOKEN_AGGREGATION_BASE_URL", )) if baseURL == "" { writeError(w, http.StatusServiceUnavailable, "service_unavailable", "token aggregation api base url is not configured") return } target, err := url.Parse(strings.TrimRight(baseURL, "/")) if err != nil { writeError(w, http.StatusBadGateway, "bad_gateway", fmt.Sprintf("invalid token aggregation api base url: %v", err)) return } proxy := httputil.NewSingleHostReverseProxy(target) originalDirector := proxy.Director proxy.Director = func(req *http.Request) { originalDirector(req) req.URL.Path = joinProxyPath(target.Path, path) req.URL.RawPath = req.URL.Path } proxy.ErrorHandler = func(rw http.ResponseWriter, req *http.Request, proxyErr error) { writeError(rw, http.StatusBadGateway, "bad_gateway", fmt.Sprintf("route tree proxy failed for %s: %v", path, proxyErr)) } proxy.ServeHTTP(w, r) } func joinProxyPath(basePath, path string) string { switch { case strings.HasSuffix(basePath, "/") && strings.HasPrefix(path, "/"): return basePath + path[1:] case !strings.HasSuffix(basePath, "/") && !strings.HasPrefix(path, "/"): return basePath + "/" + path default: return basePath + path } } func firstNonEmptyEnv(keys ...string) string { for _, key := range keys { if value := strings.TrimSpace(os.Getenv(key)); value != "" { return value } } return "" }