waldo_proxy.go

 1package rtw
 2
 3import (
 4	"context"
 5	"errors"
 6	"log/slog"
 7	"net/http"
 8	"net/http/httputil"
 9	"net/url"
10)
11
12// WaldoProxyHandler returns an HTTP handler that transparently proxies GET
13// requests to the upstream Waldo geocoding service at targetURL.
14// Forwards request headers and query parameters to the upstream Waldo service.
15func WaldoProxyHandler(targetURL string) http.Handler {
16	target, err := url.Parse(targetURL)
17	if err != nil {
18		slog.Error("invalid waldo target url", "error", err, "url", targetURL)
19		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
20			http.Error(w, "invalid geocoder configuration", http.StatusInternalServerError)
21		})
22	}
23
24	proxy := httputil.NewSingleHostReverseProxy(target)
25
26	proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
27		if errors.Is(err, context.Canceled) {
28			slog.Debug("waldo proxy client disconnected", "path", r.URL.Path)
29			return
30		}
31		slog.Error("waldo proxy error", "error", err, "path", r.URL.Path)
32		http.Error(w, "upstream error", http.StatusBadGateway)
33	}
34
35	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
36		if r.Method != http.MethodGet && r.Method != http.MethodHead {
37			w.Header().Set("Allow", "GET, HEAD")
38			http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
39			return
40		}
41		proxy.ServeHTTP(w, r)
42	})
43}