2017-11-08 00:10:54 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2017-11-15 15:37:54 +01:00
|
|
|
"compress/gzip"
|
2017-11-19 16:51:26 +01:00
|
|
|
"errors"
|
2017-11-18 13:23:36 +01:00
|
|
|
"fmt"
|
2017-11-08 00:10:54 +01:00
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
2017-11-21 22:36:40 +01:00
|
|
|
"log"
|
2017-11-08 00:10:54 +01:00
|
|
|
"net/http"
|
|
|
|
"net/http/httputil"
|
|
|
|
|
2017-11-21 22:36:40 +01:00
|
|
|
"github.com/googollee/go-socket.io"
|
|
|
|
)
|
2017-11-15 15:37:54 +01:00
|
|
|
|
2017-11-21 22:36:40 +01:00
|
|
|
var captures Captures
|
|
|
|
var socket socketio.Socket
|
2017-11-08 00:10:54 +01:00
|
|
|
|
2017-11-15 15:37:54 +01:00
|
|
|
type Transport struct {
|
|
|
|
http.RoundTripper
|
|
|
|
}
|
|
|
|
|
2017-11-08 00:10:54 +01:00
|
|
|
func main() {
|
2017-11-21 22:36:40 +01:00
|
|
|
targetURL, proxyPort, dashboard, maxCaptures := parseFlags()
|
|
|
|
captures.max = maxCaptures
|
2017-11-08 00:10:54 +01:00
|
|
|
|
2017-11-18 12:05:41 +01:00
|
|
|
proxy := httputil.NewSingleHostReverseProxy(targetURL)
|
2017-11-15 15:37:54 +01:00
|
|
|
proxy.Transport = Transport{http.DefaultTransport}
|
|
|
|
|
2017-11-08 00:10:54 +01:00
|
|
|
http.Handle("/", getProxyHandler(proxy))
|
|
|
|
http.Handle("/socket.io/", getSocketHandler())
|
2017-11-18 12:05:41 +01:00
|
|
|
http.Handle("/"+dashboard+"/", getDashboardHandler())
|
2017-11-18 13:23:36 +01:00
|
|
|
|
2017-11-21 22:36:55 +01:00
|
|
|
fmt.Printf("\nListening on http://localhost:%s", proxyPort)
|
|
|
|
fmt.Printf("\n http://localhost:%s/%s\n\n", proxyPort, dashboard)
|
2017-11-18 13:23:36 +01:00
|
|
|
|
2017-11-18 12:05:41 +01:00
|
|
|
http.ListenAndServe(":"+proxyPort, nil)
|
2017-11-08 00:10:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func getProxyHandler(handler http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
|
|
|
|
request.Host = request.URL.Host
|
2017-11-15 15:37:54 +01:00
|
|
|
handler.ServeHTTP(response, request)
|
|
|
|
})
|
|
|
|
}
|
2017-11-08 00:10:54 +01:00
|
|
|
|
2017-11-21 22:36:40 +01:00
|
|
|
func getSocketHandler() http.Handler {
|
|
|
|
server, err := socketio.NewServer(nil)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
server.On("connection", func(so socketio.Socket) {
|
|
|
|
socket = so
|
|
|
|
emit()
|
|
|
|
})
|
|
|
|
server.On("error", func(so socketio.Socket, err error) {
|
|
|
|
log.Println("socket error:", err)
|
|
|
|
})
|
|
|
|
return server
|
|
|
|
}
|
|
|
|
|
2017-11-15 15:37:54 +01:00
|
|
|
func (t Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
2017-11-19 16:51:26 +01:00
|
|
|
reqDump, err := httputil.DumpRequest(req, true)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-11-08 00:10:54 +01:00
|
|
|
|
2017-11-18 12:42:53 +01:00
|
|
|
res, err := t.RoundTripper.RoundTrip(req)
|
2017-11-19 16:51:26 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.New(err.Error() + ": " + req.URL.String())
|
|
|
|
}
|
2017-11-08 00:10:54 +01:00
|
|
|
|
2017-11-19 16:51:26 +01:00
|
|
|
resDump, err := DumpResponse(res)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-11-15 15:37:54 +01:00
|
|
|
|
2017-11-21 22:36:40 +01:00
|
|
|
capture := Capture{req.URL.Path, req.Method, res.StatusCode,
|
|
|
|
string(reqDump),
|
|
|
|
string(resDump),
|
2017-11-15 15:37:54 +01:00
|
|
|
}
|
|
|
|
|
2017-11-21 22:36:40 +01:00
|
|
|
captures.Add(capture)
|
|
|
|
emit()
|
2017-11-15 15:37:54 +01:00
|
|
|
|
2017-11-19 16:51:26 +01:00
|
|
|
return res, nil
|
2017-11-08 00:10:54 +01:00
|
|
|
}
|
|
|
|
|
2017-11-15 15:37:54 +01:00
|
|
|
func DumpResponse(res *http.Response) ([]byte, error) {
|
|
|
|
var originalBody bytes.Buffer
|
|
|
|
res.Body = ioutil.NopCloser(io.TeeReader(res.Body, &originalBody))
|
|
|
|
if res.Header.Get("Content-Encoding") == "gzip" {
|
|
|
|
res.Body, _ = gzip.NewReader(res.Body)
|
|
|
|
}
|
2017-11-18 12:42:53 +01:00
|
|
|
resDump, err := httputil.DumpResponse(res, true)
|
2017-11-15 15:37:54 +01:00
|
|
|
res.Body = ioutil.NopCloser(&originalBody)
|
2017-11-18 12:42:53 +01:00
|
|
|
return resDump, err
|
2017-11-15 15:37:54 +01:00
|
|
|
}
|
2017-11-08 00:10:54 +01:00
|
|
|
|
2017-11-21 22:36:40 +01:00
|
|
|
func emit() {
|
|
|
|
if socket == nil {
|
|
|
|
return
|
2017-11-08 00:10:54 +01:00
|
|
|
}
|
2017-11-21 22:36:40 +01:00
|
|
|
socket.Emit("captures", captures.items)
|
2017-11-08 00:10:54 +01:00
|
|
|
}
|