diff --git a/README.md b/README.md index 7e57b28..0b4a83b 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,26 @@ gateway/ The gateway is configured via a YAML file (`configs/bff.yml`). See the example configuration for reference. +## Debugging + +### Proxy Debug Mode + +The gateway includes a debug mode for its reverse proxies, which can be helpful for understanding how requests are being processed and forwarded. + +- **Control**: This mode is controlled by the `debugProxy` boolean flag located in the `global` section of the `configs/bff.yml` configuration file. +- **Functionality**: When enabled, the proxies use a `DebugTransport`. This special transport logs details of outgoing requests, including headers and body (if applicable). +- **Performance Impact**: Enabling `DebugTransport` has a significant performance impact due to the detailed logging it performs. +- **Recommendation**: This mode should **only be enabled for debugging purposes**. It is strongly recommended to keep it disabled in production environments or any situation where performance is critical. + +To enable proxy debug mode, set `debugProxy: true` in `configs/bff.yml`: + +```yaml +global: + policies: + - cors + debugProxy: true # Enable for debugging +``` + ### Example Configuration ```yaml diff --git a/configs/bff.yml b/configs/bff.yml index c0f7747..b6dddae 100644 --- a/configs/bff.yml +++ b/configs/bff.yml @@ -5,6 +5,7 @@ policyDefinitions: global: policies: - cors + debugProxy: false # Add this line endpoints: - path: /proxy diff --git a/internal/config/types.go b/internal/config/types.go index ca0a59b..ccebb56 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -40,5 +40,6 @@ type Cors struct { } type Global struct { - Policies []string `yaml:"policies" json:"policies"` + Policies []string `yaml:"policies" json:"policies"` + DebugProxy bool `yaml:"debugProxy" json:"debugProxy"` } \ No newline at end of file diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index 987ec1e..b3b12ed 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -9,14 +9,18 @@ import ( ) // NewReverseProxy creates a new reverse proxy for the given endpoint -func NewReverseProxy(endpoint config.Endpoint) (*httputil.ReverseProxy, error) { +func NewReverseProxy(endpoint config.Endpoint, debugMode bool) (*httputil.ReverseProxy, error) { targetURL, err := url.Parse(endpoint.Target.URL) if err != nil { return nil, err } proxy := httputil.NewSingleHostReverseProxy(targetURL) - proxy.Transport = middleware.DebugTransport{} + if debugMode { + proxy.Transport = middleware.DebugTransport{} + } else { + // Use default transport if not in debug mode + } proxy.Director = CreateDirector(endpoint, targetURL) return proxy, nil diff --git a/internal/server/handler.go b/internal/server/handler.go index f9611d5..9bd1856 100644 --- a/internal/server/handler.go +++ b/internal/server/handler.go @@ -1,16 +1,15 @@ package server import ( - "log" "net/http" + "net/http/httputil" "gateway/server/internal/config" "gateway/server/internal/middleware" - "gateway/server/internal/proxy" ) // CreateEndpointHandler creates an HTTP handler for a specific endpoint -func CreateEndpointHandler(endpoint config.Endpoint, corsConfig config.Cors, hasCORS bool) http.HandlerFunc { +func CreateEndpointHandler(reverseProxy *httputil.ReverseProxy, corsConfig config.Cors, hasCORS bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Handle CORS headers if hasCORS { @@ -23,14 +22,7 @@ func CreateEndpointHandler(endpoint config.Endpoint, corsConfig config.Cors, has return } - // Create and use reverse proxy - reverseProxy, err := proxy.NewReverseProxy(endpoint) - if err != nil { - log.Printf("Failed to create proxy for %s: %v", endpoint.Path, err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - + // Use the pre-created reverse proxy reverseProxy.ServeHTTP(w, r) } } \ No newline at end of file diff --git a/internal/server/routes.go b/internal/server/routes.go index 272edb3..3e7bb13 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -10,20 +10,20 @@ import ( ) // RegisterRoutes registers all routes based on the configuration -func RegisterRoutes(mux *http.ServeMux, cfg *config.Config) { - for _, endpoint := range cfg.Endpoints { - registerEndpointRoutes(mux, endpoint, cfg) +func (s *Server) RegisterRoutes() { + for _, endpoint := range s.config.Endpoints { + s.registerEndpointRoutes(endpoint) } } -func registerEndpointRoutes(mux *http.ServeMux, endpoint config.Endpoint, cfg *config.Config) { +func (s *Server) registerEndpointRoutes(endpoint config.Endpoint) { // Merge global policies with endpoint policies - allPolicies := append(endpoint.Policies, cfg.Global.Policies...) + allPolicies := append(endpoint.Policies, s.config.Global.Policies...) policies := utils.ToSet(allPolicies) // Check for CORS _, hasCORS := policies["cors"] - + methods := endpoint.Methods if hasCORS { methods = append(methods, "OPTIONS") @@ -34,11 +34,18 @@ func registerEndpointRoutes(mux *http.ServeMux, endpoint config.Endpoint, cfg *c routePath += "/" } + // Retrieve the pre-created proxy. If it doesn't exist (e.g., due to creation error), skip this route. + reverseProxy, ok := s.proxies[endpoint.Path] + if !ok { + fmt.Printf("Proxy for path %s not found, skipping route configuration.\n", endpoint.Path) + return + } + for _, method := range methods { route := method + " " + routePath - handler := CreateEndpointHandler(endpoint, cfg.PolicyDefinitions.CORS, hasCORS) + handler := CreateEndpointHandler(reverseProxy, s.config.PolicyDefinitions.CORS, hasCORS) - mux.HandleFunc(route, handler) + s.mux.HandleFunc(route, handler) fmt.Printf("Configured Route %v --> %v\n", route, endpoint.Target.URL) } } \ No newline at end of file diff --git a/internal/server/server.go b/internal/server/server.go index d64a48c..02f8921 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -2,27 +2,41 @@ package server import ( "fmt" + "fmt" + "log" "net/http" + "net/http/httputil" "gateway/server/internal/config" + "gateway/server/internal/proxy" ) // Server represents the HTTP server type Server struct { - config *config.Config - mux *http.ServeMux + config *config.Config + mux *http.ServeMux + proxies map[string]*httputil.ReverseProxy } // New creates a new server instance func New(cfg *config.Config) *Server { mux := http.NewServeMux() - server := &Server{ - config: cfg, - mux: mux, + config: cfg, + mux: mux, + proxies: make(map[string]*httputil.ReverseProxy), + } + + for _, endpoint := range cfg.Endpoints { + p, err := proxy.NewReverseProxy(endpoint, cfg.Global.DebugProxy) + if err != nil { + log.Printf("Failed to create proxy for path %s: %v", endpoint.Path, err) + continue // Or handle as fatal + } + server.proxies[endpoint.Path] = p } - RegisterRoutes(mux, cfg) + server.RegisterRoutes() return server }