/**
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" descrtiption:"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)
}
}