diff options
Diffstat (limited to 'phlox/main.go')
-rw-r--r-- | phlox/main.go | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/phlox/main.go b/phlox/main.go new file mode 100644 index 0000000..3516374 --- /dev/null +++ b/phlox/main.go @@ -0,0 +1,112 @@ +package main + +import ( + "fmt" + "io" + "strings" + "net" + "net/http" + "net/url" + log "github.com/sirupsen/logrus" +) + + +func main() { + const addr = "localhost:3333" + + log.Info("configuring reverse proxy...") + configureEndpoint("/proxy1", "http://localhost:8000") + + log.Infof("serving on %v", addr) + log.Fatal(http.ListenAndServe(addr, nil)) +} + + +type Endpoint struct { + Path string + Origin *url.URL +} + + +func configureEndpoint(path, address string) { + log.Infof("proxying endpoint %v to %v", path, address) + origin, err := url.Parse(address) + if err != nil { + log.Fatal(err) + } + + end := Endpoint{ + Path: path, + Origin: origin, + } + + http.HandleFunc(path + "/", func(w http.ResponseWriter, req *http.Request) { + log.Infof("REQ: %v", req.URL.Path) + proxy(w, req, end) + }) +} + + +func proxy(w http.ResponseWriter, req *http.Request, end Endpoint) { + response := proxyRequest(w, req, end) + proxyResponse(w, response) +} + + +func proxyRequest(w http.ResponseWriter, req *http.Request, end Endpoint) *http.Response { + // configure host address + req.Host = end.Origin.Host + req.URL.Host = end.Origin.Host + + // strip proxy endpoint path from request path + req.URL.Path = strings.TrimPrefix(req.URL.Path, end.Path) + + // set X-Forwarded-For + forwardedFor, _, _ := net.SplitHostPort(req.RemoteAddr) + req.Header.Set("X-Forwarded-For", forwardedFor) + + // misc request cleanups + req.URL.Scheme = end.Origin.Scheme + req.RequestURI = "" + + // make request + response, err := http.DefaultClient.Do(req) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "%v", err) + log.Fatal(err) + } + + 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) + } + } +} |