104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
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)
|
|
} |