diff options
Diffstat (limited to 'proxy.go')
-rw-r--r-- | proxy.go | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/proxy.go b/proxy.go new file mode 100644 index 0000000..7be9419 --- /dev/null +++ b/proxy.go @@ -0,0 +1,112 @@ +package main + +import ( + "io" + "strings" + "net" + "net/http" + "net/url" + "sanine.net/git/phlox/auth" + "sanine.net/git/phlox/config" + "sanine.net/git/phlox/page" + log "github.com/sirupsen/logrus" +) + + +type Endpoint struct { + Path string + Origin *url.URL +} + + +func addEndpoint(s *auth.Sessions, pages page.Pages, e config.Endpoint) { + log.Infof("proxying endpoint %v to %v", e.Path, e.Address) + origin, err := url.Parse(e.Address) + if err != nil { + log.Fatal(err) + } + + end := Endpoint{ + Path: e.Path, + Origin: origin, + } + + http.HandleFunc(e.Path + "/", func(w http.ResponseWriter, r *http.Request) { + log.Infof("REQ: %v", r.URL.Path) + proxy(w, r, s, pages, end) + }) +} + + +func proxy(w http.ResponseWriter, r *http.Request, s *auth.Sessions, pages page.Pages, end Endpoint) { + ok := authenticateRequest(r, s) + if !ok { + w.Header().Set("Location", "/phlox/login") + w.WriteHeader(http.StatusTemporaryRedirect) + return + } + + response := proxyRequest(w, r, pages, end) + if response != nil { + proxyResponse(w, response) + } +} + + +func proxyRequest(w http.ResponseWriter, r *http.Request, pages page.Pages, end Endpoint) *http.Response { + // configure host address + r.Host = end.Origin.Host + r.URL.Host = end.Origin.Host + + // strip proxy endpoint path from request path + r.URL.Path = strings.TrimPrefix(r.URL.Path, end.Path) + + // set X-Forwarded-For + forwardedFor, _, _ := net.SplitHostPort(r.RemoteAddr) + r.Header.Set("X-Forwarded-For", forwardedFor) + + // misc request cleanups + r.URL.Scheme = end.Origin.Scheme + r.RequestURI = "" + + // make request + response, err := http.DefaultClient.Do(r) + if err != nil { + pages.ServeError500(w) + log.Error(err) + return nil + } + + return response +} + + +func proxyResponse(w http.ResponseWriter, response *http.Response) { + // copy header + for key, values := range response.Header { + for _, value := range values { + w.Header().Add(key, value) + } + } + + // get trailer keys + trailerKeys := []string{} + for key := range response.Trailer { + trailerKeys = append(trailerKeys, key) + } + if (len(trailerKeys) > 0) { + w.Header().Set("Trailer", strings.Join(trailerKeys, ",")) + } + + w.WriteHeader(response.StatusCode) + + // copy body to client + io.Copy(w, response.Body) + + // write trailers + for key, values := range response.Trailer { + for _, value := range values { + w.Header().Set(key, value) + } + } +} |