package main import ( "io" "log" "net" "net/http" "net/url" "path" "strings" "gfx.cafe/open/gun" ) var Config struct { Port string Root string Remote string } func init() { gun.Load(&Config) if Config.Port == "" { Config.Port = "8080" } if Config.Root == "" { Config.Root = "dist" } if Config.Remote == "" { Config.Remote = "https://beta.lifeto.co" } Config.Root = path.Clean(Config.Root) } var hopHeaders = []string{ "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", "Te", "Trailers", "Transfer-Encoding", "Upgrade", } func appendHostToXForwardHeader(header http.Header, host string) { if prior, ok := header["X-Forwarded-For"]; ok { host = strings.Join(prior, ", ") + ", " + host } header.Set("X-Forwarded-For", host) } func copyHeader(dst, src http.Header) { for k, vv := range src { for _, v := range vv { dst.Add(k, v) } } } func delHopHeaders(header http.Header) { for _, h := range hopHeaders { header.Del(h) } } type Handler struct { p ProxyHandler } func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/lifeto") { http.StripPrefix("/lifeto", &h.p).ServeHTTP(w, r) return } h.handleSite(w, r) } type ProxyHandler struct { c http.Client } func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { r.RequestURI = "" if clientIP, _, err := net.SplitHostPort(r.RemoteAddr); err == nil { appendHostToXForwardHeader(r.Header, clientIP) } r.URL, _ = url.Parse(Config.Remote + r.URL.Path) r.Host = r.URL.Host resp, err := h.c.Do(r) if err != nil { http.Error(w, "Server Error", http.StatusInternalServerError) log.Println("ServeHTTP:", err) return } defer resp.Body.Close() delHopHeaders(resp.Header) copyHeader(w.Header(), resp.Header) w.WriteHeader(resp.StatusCode) io.Copy(w, resp.Body) } func (h *Handler) handleSite(w http.ResponseWriter, r *http.Request) { http.FileServer(http.Dir(Config.Root)).ServeHTTP(w, r) } func main() { log.Printf("starting with config: %+v", Config) http.ListenAndServe(":"+Config.Port, &Handler{}) }