diff --git a/http-multicaster.go b/http-multicaster.go index a55ab56..1869c3f 100644 --- a/http-multicaster.go +++ b/http-multicaster.go @@ -2,78 +2,116 @@ package main import ( "fmt" - "io/ioutil" + "io" + "log" "net/http" + "os" + "strings" "sync" ) -var backends = []string{ - "http://backend1.local/api", - "http://backend2.local/api", - "http://backend3.local/api", -} +var backends []string func forwardRequestToBackend(wg *sync.WaitGroup, client *http.Client, backend string, req *http.Request, responses chan<- string) { defer wg.Done() - // Recréer la requête HTTP + /* Recreate the request with same Method, path,query and Body, but to the specified backend */ + forwardReq, err := http.NewRequest(req.Method, backend, req.Body) if err != nil { log.Printf("Error creating request for %s: %v", backend, err) - responses <- fmt.Sprintf("Error: %v", err) + responses <- fmt.Sprintf("Failed: %v", err) return } - // Copier les en-têtes de la requête originale + // Override Host with original Host + forwardReq.Host = req.Host + // Override RequestURI + forwardReq.RequestURI = req.RequestURI + // Add original headers forwardReq.Header = req.Header.Clone() - // Envoyer la requête au backend + // Send request resp, err := client.Do(forwardReq) if err != nil { log.Printf("Error forwarding to %s: %v", backend, err) - responses <- fmt.Sprintf("Error: %v", err) + responses <- fmt.Sprintf("%s failed: %v", err) return } defer resp.Body.Close() - // Lire la réponse du backend - body, err := ioutil.ReadAll(resp.Body) + // Read response body + body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response from %s: %v", backend, err) - responses <- fmt.Sprintf("Error: %v", err) + responses <- fmt.Sprintf("%s failed: %v", backend, err) return } // Ajouter la réponse dans le canal - responses <- fmt.Sprintf("Response from %s: %s", backend, body) + responses <- fmt.Sprintf("%s succeeded", backend) } +/* +* Take incoming request and make a new request for each backend in a new goroutine. +* In response to origin request send a report sucess or failure with HTTP code. + */ func handler(w http.ResponseWriter, req *http.Request) { client := &http.Client{} var wg sync.WaitGroup responses := make(chan string, len(backends)) - // Forward la requête vers chaque backend for _, backend := range backends { wg.Add(1) go forwardRequestToBackend(&wg, client, backend, req, responses) } - // Attendre la fin de toutes les requêtes wg.Wait() close(responses) - // Collecter et afficher les réponses des backends for response := range responses { fmt.Fprintf(w, "%s\n", response) } } +/* +* Just print incoming request elements + */ +func debugHandler(w http.ResponseWriter, req *http.Request) { + backend := "127.0.0.1:8080" + /* Recreate the request with same Method, path,query and Body, but to the specified backend */ + backendRequest := fmt.Sprintf("http://%s%s", backend, req.RequestURI) + fmt.Println("Backend Request", ":", backendRequest) + forwardReq, err := http.NewRequest(req.Method, backendRequest, req.Body) + if err != nil { + log.Printf("Error creating request for %s: %v", backend, err) + return + } + forwardReq.Host = req.Host + forwardReq.RequestURI = req.RequestURI + forwardReq.Header = req.Header.Clone() + + fmt.Printf("%#v\n", req) + fmt.Printf("%#v\n", forwardReq) + +} func main() { - http.HandleFunc("/", handler) + backendsStr := os.Getenv("BACKENDS") + listenAddress := os.Getenv("LISTEN") + if len(listenAddress) == 0 { + listenAddress = ":8080" + } + if len(backendsStr) == 0 { + log.Println("BACKENDS environment var not defined or empty (BACKENDS=IP:PORT,IP:PORT)") + log.Println("Running as debugger") + http.HandleFunc("/", debugHandler) + } else { + backends = strings.Split(backendsStr, ",") + http.HandleFunc("/", handler) + } fmt.Println("Starting server on :8080...") - if err := http.ListenAndServe(":8080", nil); err != nil { + if err := http.ListenAndServe(listenAddress, nil); err != nil { log.Fatalf("Server failed: %v", err) } }