/**
Author: Mark George <mark.george@otago.ac.nz
License: WTFPL v2 <http://www.wtfpl.net/txt/copying/>
Original Source: https://gist.github.com/yowu/f7dc34bd4736a65ff28d
*/
package main
import (
// "flag"
"fmt"
// "io"
// "log"
"net/http"
"net/http/httputil"
"net/url"
// "strings"
"time"
"github.com/fatih/color"
)
var (
listen string
target string
)
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
func ServeProxy(target string, rsp http.ResponseWriter, req *http.Request) {
url, _ := url.Parse(target)
proxy := httputil.NewSingleHostReverseProxy(url)
req.URL.Host = url.Host
req.URL.Scheme = url.Scheme
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
proxy.ServeHTTP(rsp, req)
// fmt.Println()
// log.Println("\n")
// // log the original request
dumpReq, _ := httputil.DumpRequest(req, true)
color.Set(color.FgBlue)
fmt.Println(string(dumpReq[:]))
fmt.Println()
// // log the response
// dumpRsp, _ := httputil.DumpResponse(resp, true)
// color.Set(color.FgRed)
// fmt.Println(string(dumpRsp[:]))
// copyHeader(wr.Header(), resp.Header)
// wr.WriteHeader(resp.StatusCode)
// io.Copy(wr, resp.Body)
// color.Unset()
// defer resp.Body.Close()
}
func CreateProxy(target string) (*httputil.ReverseProxy, error) {
url, err := url.Parse(target)
// bad target URL
if (err != nil) {
return nil, err
}
proxy := httputil.NewSingleHostReverseProxy(url)
OriginalDirector := proxy.Director
proxy.Director = func(req *http.Request) {
LogRequest(req)
// send request to target
OriginalDirector(req)
}
proxy.ModifyResponse = func (rsp *http.Response) error {
LogResponse(rsp)
return nil
}
proxy.ErrorHandler = func (http.ResponseWriter, *http.Request, error) {
fmt.Println("Could not connect to target server\n")
}
return proxy, nil
}
func RequestHandler(proxy *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
proxy.ServeHTTP(w, r)
}
}
func LogRequest(req *http.Request) error {
color.Set(color.FgWhite)
fmt.Println(time.Now().Format(time.StampMilli))
dumpReq, _ := httputil.DumpRequest(req, true)
color.Set(color.FgBlue)
fmt.Println(string(dumpReq[:]))
color.Unset()
return nil
}
func LogResponse(rsp *http.Response) {
color.Set(color.FgWhite)
fmt.Println(time.Now().Format(time.StampMilli))
dumpRsp, _ := httputil.DumpResponse(rsp, true)
color.Set(color.FgRed)
fmt.Println(string(dumpRsp[:]))
color.Unset()
}
func main() {
// flag.StringVar(&listen, "listen", "9090", "The port that the proxy listens on.")
// flag.StringVar(&listen, "l", "9090", "The port that the proxy listens on.")
// flag.StringVar(&target, "target", "8080", "The port that the proxy forwards requests to.")
// flag.StringVar(&target, "t", "8080", "The port that the proxy forwards requests to.")
// flag.Parse()
// handler := &proxy{}
// log.Println("Forwarding port", listen, "to port", target)
// if err := http.ListenAndServe("localhost:"+listen, handler); err != nil {
// log.Fatal("ListenAndServe:", err)
// }
target := "http://localhost:8080"
listenPort := "9090"
proxy, err := CreateProxy(target)
if err != nil {
panic(err)
}
http.HandleFunc("/", RequestHandler(proxy))
if err := http.ListenAndServe(":"+listenPort, nil); err != nil {
panic(err)
}
}