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"
)

type ProxyCommand struct {
	port   string `short:"p" long:"port" description:"The port that the proxy listens on."`
	target string `short:"t" long:"target" descrtiption:"The target web server that the proxy forwards requests to."`
}

func (c *ProxyCommand) Execute(args []string) error {
	fmt.Println("Start proxy")
	return nil
}

func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

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)
		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 FixHeaders(url *url.URL, req *http.Request) {
	// 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)
	}
}

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 ymain() {
	// 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)
	}
}