Skip to content

Instantly share code, notes, and snippets.

@chrisdd2
Created February 25, 2025 20:34
Show Gist options
  • Select an option

  • Save chrisdd2/b33b69552d5d8f3cef8e96963f0049b0 to your computer and use it in GitHub Desktop.

Select an option

Save chrisdd2/b33b69552d5d8f3cef8e96963f0049b0 to your computer and use it in GitHub Desktop.
proxy with a map
package main
import (
"fmt"
"io"
"log"
"net/http"
"net/url"
"os"
"strings"
)
type MappedProxy struct {
hosts map[string]*url.URL
}
func copyHeader(src http.Header, tgt http.Header) {
for k, vv := range src {
for _, v := range vv {
tgt.Add(k, v)
}
}
}
func (s *MappedProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// get mapping
mappedHost, ok := s.hosts[r.Host]
if !ok {
http.Error(w, "mapping not found", http.StatusNotFound)
return
}
// create request with mapped host
targetUrl := mappedHost.ResolveReference(&url.URL{Path: r.URL.Path, RawQuery: r.URL.RawQuery})
req, err := http.NewRequest(r.Method, targetUrl.String(), r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("unable to create request [%s]", err), http.StatusInternalServerError)
return
}
log.Printf("redirecting [%s] [%s] to [%s]", r.Host, r.URL.String(), targetUrl.String())
copyHeader(r.Header, req.Header)
req.Host = mappedHost.Host
// perform and hope
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, fmt.Sprintf("proxy error [%s]", err), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
copyHeader(w.Header(), resp.Header)
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)
}
func main() {
addr := os.Getenv("APP_LISTEN_ADDR")
sourceHost := strings.Split(os.Getenv("APP_SOURCE_HOSTS"), ",")
targetHosts := strings.Split(os.Getenv("APP_TARGET_HOSTS"), ",")
if len(sourceHost) != len(targetHosts) {
log.Fatalln("source target hosts mismatch")
}
mustParse := func(u string) *url.URL {
ret, err := url.Parse(u)
if err != nil {
panic(err.Error())
}
return ret
}
proxy := MappedProxy{hosts: make(map[string]*url.URL)}
for i := 0; i < len(sourceHost); i++ {
proxy.hosts[sourceHost[i]] = mustParse(targetHosts[i])
}
log.Printf("listening on [%s]\n", addr)
if err := http.ListenAndServe(addr, &proxy); err != nil {
log.Fatalln(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment