From 72f50d4f844d8f10be325bf8226de651f6145f3e Mon Sep 17 00:00:00 2001 From: Chiran Fernando Date: Sat, 5 Apr 2025 08:24:12 +0530 Subject: [PATCH] Validate depedencies needed for subprocess to start --- internal/proxy/proxy.go | 33 +++++++++++++++++++-------------- internal/subprocess/manager.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index 0213ea4..e02c8e5 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -100,7 +100,6 @@ func NewRouter(cfg *config.Config, provider authz.Provider) http.Handler { func buildProxyHandler(cfg *config.Config, modifiers map[string]RequestModifier) http.HandlerFunc { // Parse the base URLs up front - authBase, err := url.Parse(cfg.AuthServerBaseURL) if err != nil { log.Fatalf("Invalid auth server URL: %v", err) @@ -191,19 +190,13 @@ func buildProxyHandler(cfg *config.Config, modifiers map[string]RequestModifier) req.URL.RawQuery = r.URL.RawQuery req.Host = targetURL.Host - // for key, values := range r.Header { - // log.Printf("Header: %s, Values: %v", key, values) - // } - cleanHeaders := http.Header{} - - // Preserve the original Origin header if present - // if origin := r.Header.Get("Origin"); origin != "" { - // cleanHeaders.Set("Origin", origin) - // } else { - // log.Printf("[proxy] No Origin header found, setting to target URL: http://localhost:8080") - // cleanHeaders.Set("Origin", "http://localhost:8080") - // } + + // Set proper origin header to match the target + if isSSE { + // For SSE, ensure origin matches the target + req.Header.Set("Origin", targetURL.Scheme+"://"+targetURL.Host) + } for k, v := range r.Header { // Skip hop-by-hop headers @@ -232,6 +225,18 @@ func buildProxyHandler(cfg *config.Config, modifiers map[string]RequestModifier) } if isSSE { + // Add special response handling for SSE connections to rewrite endpoint URLs + rp.Transport = &sseTransport{ + Transport: http.DefaultTransport, + proxyHost: r.Host, + targetHost: targetURL.Host, + } + + // Set SSE-specific headers + w.Header().Set("X-Accel-Buffering", "no") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Connection", "keep-alive") + // Keep SSE connections open HandleSSE(w, r, rp) } else { @@ -301,4 +306,4 @@ func skipHeader(h string) bool { return true } return false -} +} \ No newline at end of file diff --git a/internal/subprocess/manager.go b/internal/subprocess/manager.go index faf22b4..a83e75b 100644 --- a/internal/subprocess/manager.go +++ b/internal/subprocess/manager.go @@ -7,6 +7,8 @@ import ( "sync" "syscall" "time" + "fmt" + "strings" "github.com/wso2/open-mcp-auth-proxy/internal/config" ) @@ -27,6 +29,38 @@ func NewManager() *Manager { } } +// EnsureDependenciesAvailable checks and installs required package executors +func EnsureDependenciesAvailable(command string) error { + // Always ensure npx is available regardless of the command + if _, err := exec.LookPath("npx"); err != nil { + // npx is not available, check if npm is installed + if _, err := exec.LookPath("npm"); err != nil { + return fmt.Errorf("npx not found and npm not available; please install Node.js from https://nodejs.org/") + } + + // Try to install npx using npm + log.Printf("npx not found, attempting to install...") + cmd := exec.Command("npm", "install", "-g", "npx") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install npx: %w", err) + } + + log.Printf("npx installed successfully") + } + + // Check if uv is needed based on the command + if strings.Contains(command, "uv ") { + if _, err := exec.LookPath("uv"); err != nil { + return fmt.Errorf("command requires uv but it's not installed; please install it following instructions at https://github.com/astral-sh/uv") + } + } + + return nil +} + // SetShutdownDelay sets the maximum time to wait for graceful shutdown func (m *Manager) SetShutdownDelay(duration time.Duration) { m.shutdownDelay = duration