/** Author: Mark George <mark.george@otago.ac.nz> License: Zero-Clause BSD License */ package main import ( "fmt" "net/http" "net/http/httputil" "net/url" "strconv" ) type ProxyCommand struct { Port int `short:"p" long:"port" description:"The port that the proxy listens on." required:"true"` Target string `short:"t" long:"target" description:"The URL for the target web server that the proxy forwards requests to." required:"true"` } func (opts *ProxyCommand) Execute(args []string) error { fmt.Println("Proxying port " + strconv.Itoa(opts.Port) + " to " + opts.Target) proxy, err := CreateProxy(opts.Target) if err != nil { panic(err) } http.HandleFunc("/", RequestHandler(proxy)) if err := http.ListenAndServe(":"+strconv.Itoa(opts.Port), nil); err != nil { panic(err) } return nil } 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) { FixHeaders(url, req) showRequest(req) // send request to target OriginalDirector(req) } proxy.ModifyResponse = func(rsp *http.Response) error { showResponse(rsp) return nil } proxy.ErrorHandler = func(rsp http.ResponseWriter, req *http.Request, err error) { fmt.Println("Error sending request to target server:") fmt.Println(" " + err.Error()) } return proxy, nil } func FixHeaders(url *url.URL, req *http.Request) { // TODO this may be necessary for proxying HTTPS (need to test) req.URL.Host = url.Host req.URL.Scheme = url.Scheme req.Host = url.Host } func RequestHandler(proxy *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { proxy.ServeHTTP(w, r) } }