Last active
November 10, 2022 10:15
-
-
Save tjamet/8a3d9e3019045855137deadcf3318245 to your computer and use it in GitHub Desktop.
http handler factory to proxy requests in go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func newProxyHandler(client *http.Client, backend *url.URL) http.Handler { | |
return http.HandlerFunc(func(ow http.ResponseWriter, r *http.Request) { | |
w := &loggedResponseWriter{ResponseWriter: ow} | |
defer func() { | |
log.Printf("%s %s %d %d Bytes", r.Method, r.URL.Path, w.code, w.size) | |
}() | |
req, err := http.NewRequest(r.Method, fmt.Sprintf("%s://%s", backend.Scheme, backend.Host), r.Body) | |
if err != nil { | |
log.Println("failed to call backend:", err.Error()) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
req.Host = r.Host | |
// r.RequestURI contains the full value of GET http://host/path?query HTTP/1.1 | |
// When sending the request, request.URL.RequestURI() is used to fill GET <what> HTTP/1.1 | |
// Although this does not work when using proxy: | |
// https://github.com/golang/go/blob/c0547476f342665514904cf2581a62135d2366c3/src/net/http/request.go#L524 | |
// This behaviour is achieved by providing only Opaque: | |
// https://github.com/golang/go/blob/c0547476f342665514904cf2581a62135d2366c3/src/net/url/url.go#L1002 | |
req.URL.Opaque = r.URL.RequestURI() | |
// Implement the X-Forwarded headers as defined in | |
// https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html | |
reqURL := url.URL{Host: r.RemoteAddr} | |
req.Header.Set("X-Forwarded-Port", reqURL.Port()) | |
if r.TLS == nil { | |
req.Header.Set("X-Forwarded-Proto", "http") | |
} else { | |
req.Header.Set("X-Forwarded-Proto", "https") | |
} | |
req.Header["X-Forwarded-For"] = []string{} | |
// Forward all original request headers | |
for key, value := range r.Header { | |
req.Header[key] = value | |
} | |
req.Header["X-Forwarded-For"] = append(req.Header["X-Forwarded-For"], reqURL.Hostname()) | |
resp, err := client.Do(req) | |
if err != nil { | |
log.Println("failed to write response:", err.Error()) | |
w.WriteHeader(http.StatusInternalServerError) | |
} else { | |
// Write the response back with all headers | |
for key, value := range resp.Header { | |
w.Header()[key] = value | |
} | |
w.WriteHeader(resp.StatusCode) | |
_, err = io.Copy(w, resp.Body) | |
if err != nil { | |
log.Println("failed to write response:", err.Error()) | |
} | |
} | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment