package proxy import ( "fmt" "net/http" "net/http/httputil" "net/url" "strings" "git.secnex.io/secnex/gogwapi/config" "git.secnex.io/secnex/masterlog" ) type ReverseProxy struct { config *config.YAMLConfig } func NewReverseProxy(cfg *config.YAMLConfig) *ReverseProxy { return &ReverseProxy{ config: cfg, } } type TargetMatch struct { URL *url.URL Endpoint *config.Endpoint } func (rp *ReverseProxy) findTarget(host string, path string) (*TargetMatch, error) { for _, target := range rp.config.Targets { for _, record := range target.Records { expectedHost := fmt.Sprintf("%s.%s", record.Record, target.Name) if host == expectedHost { for _, endpoint := range record.Endpoints { if endpoint.Path == "/" { targetURL, err := url.Parse(endpoint.URL) if err != nil { return nil, err } return &TargetMatch{URL: targetURL, Endpoint: &endpoint}, nil } if strings.HasPrefix(path, endpoint.Path) { targetURL, err := url.Parse(endpoint.URL) if err != nil { return nil, err } return &TargetMatch{URL: targetURL, Endpoint: &endpoint}, nil } } } } } return nil, fmt.Errorf("no target found for host: %s, path: %s", host, path) } func (rp *ReverseProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { host := r.Host path := r.URL.Path targetMatch, err := rp.findTarget(host, path) if err != nil { masterlog.Error("target not found", map[string]interface{}{ "host": host, "path": path, "error": err.Error(), }) http.Error(w, "Service not found", http.StatusNotFound) return } targetURL := targetMatch.URL endpoint := targetMatch.Endpoint // Transform the path: remove the endpoint prefix if it's not "/" var transformedPath string if endpoint.Path == "/" { transformedPath = path } else { transformedPath = strings.TrimPrefix(path, endpoint.Path) if transformedPath == "" { transformedPath = "/" } } masterlog.Info("proxying request", map[string]interface{}{ "host": host, "original_path": path, "transformed_path": transformedPath, "endpoint_prefix": endpoint.Path, "target": targetURL.String(), }) proxy := httputil.NewSingleHostReverseProxy(targetURL) // Create a new request with the transformed path r.URL.Host = targetURL.Host r.URL.Scheme = targetURL.Scheme r.URL.Path = transformedPath r.Header.Set("X-Forwarded-Host", host) r.Header.Set("X-Forwarded-For", r.RemoteAddr) r.Header.Set("X-Forwarded-Path", path) // Original path for debugging proxy.ServeHTTP(w, r) }