Newer
Older
httpcat / src / proxy.go
/**
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)
	}
}