package main import ( "fmt" "io" "net" "log" "net/http" "net/url" "time" ) type ReverseProxy struct { URL *url.URL jwtKey string } func (rp *ReverseProxy) reverseProxyHandlerFunc() http.Handler { return http.HandlerFunc(rp.reverseProxyHandler) } func (rp *ReverseProxy) reverseProxyHandler(rw http.ResponseWriter, req *http.Request) { fmt.Printf("[sidoxy] Reverse proxy received request at: %s\n", time.Now()) // set req Host, URL and Request URI to forward a request to the origin server req.Host = rp.URL.Host req.URL.Host = rp.URL.Host req.URL.Scheme = rp.URL.Scheme req.RequestURI = "" // set X-FORWARDED-FOR xForwardedFor := req.Header.Get("X-Forwarded-For") var remoteAddr string if xForwardedFor != "" { remoteAddr = xForwardedFor } else { remoteAddr, _, _ = net.SplitHostPort(req.RemoteAddr) } req.Header.Set("X-Forwarded-For", remoteAddr) fmt.Printf("[sidoxy] Reverse proxy setting X-Forwarded-For to %s\n", remoteAddr) // TODO: To be implemented // decode JWT if key present if rp.jwtKey != "" { jwtDecode(rp.jwtKey, req.Header.Get("JWT_TOKEN"), req) } // save the response from the origin server originServerResponse, err := http.DefaultClient.Do(req) if err != nil { rw.WriteHeader(http.StatusInternalServerError) _, _ = fmt.Fprint(rw, err) return } fmt.Printf("[sidoxy] Reverse proxy setting the following return headers\n") // return Header response for key, values := range originServerResponse.Header { for _, value := range values { fmt.Printf("[sidoxy] \t%v: %v\n", key, value) rw.Header().Set(key, value) } } // support stream done := make(chan bool) defer close(done) go func() { for { select { case <-time.Tick(10 * time.Millisecond): rw.(http.Flusher).Flush() case <-done: return } } }() // return response to the client rw.WriteHeader(http.StatusOK) io.Copy(rw, originServerResponse.Body) } func parse_url(host_url string) *url.URL { h_url, err := url.Parse(host_url) if err != nil { log.Fatal("[sidoxy] Invalid server URL: " + host_url) } return h_url } func listen_and_serve(address string, handler http.Handler) error { return http.ListenAndServe(address, handler) }