From b336d33dd3f5df94df358dd7e2693d7c9334c9e6 Mon Sep 17 00:00:00 2001 From: Fabricio Date: Sat, 1 Dec 2018 20:59:33 -0200 Subject: [PATCH] comment code --- capture.go | 11 ++++++++++ config.go | 2 ++ main.go | 63 ++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/capture.go b/capture.go index 74d643b..a95951f 100644 --- a/capture.go +++ b/capture.go @@ -9,6 +9,7 @@ import ( var captureID int var captures CaptureList +// CaptureList stores all captures type CaptureList struct { items []Capture mux sync.Mutex @@ -17,12 +18,14 @@ type CaptureList struct { Updated chan struct{} } +// Capture saves our traffic data type Capture struct { ID int Req *http.Request Res *http.Response } +// CaptureMetadata is the data for each list item in the dashboard type CaptureMetadata struct { ID int `json:"id"` Path string `json:"path"` @@ -30,12 +33,14 @@ type CaptureMetadata struct { Status int `json:"status"` } +// CaptureDump saves all the dumps shown in the dashboard type CaptureDump struct { Request string `json:"request"` Response string `json:"response"` Curl string `json:"curl"` } +// Metadata returns the metadada of a capture func (c *Capture) Metadata() CaptureMetadata { return CaptureMetadata{ ID: c.ID, @@ -45,6 +50,7 @@ func (c *Capture) Metadata() CaptureMetadata { } } +// NewCaptureList creates a new list of captures func NewCaptureList(maxItems int) *CaptureList { return &CaptureList{ maxItems: maxItems, @@ -52,6 +58,7 @@ func NewCaptureList(maxItems int) *CaptureList { } } +// Insert adds a new capture func (c *CaptureList) Insert(capture Capture) { c.mux.Lock() defer c.mux.Unlock() @@ -63,6 +70,7 @@ func (c *CaptureList) Insert(capture Capture) { c.signalsItemsChange() } +// Find finds a capture by its id func (c *CaptureList) Find(captureID string) *Capture { c.mux.Lock() defer c.mux.Unlock() @@ -75,6 +83,7 @@ func (c *CaptureList) Find(captureID string) *Capture { return nil } +// RemoveAll removes all the captures func (c *CaptureList) RemoveAll() { c.mux.Lock() defer c.mux.Unlock() @@ -82,10 +91,12 @@ func (c *CaptureList) RemoveAll() { c.signalsItemsChange() } +// Items returns all the captures func (c *CaptureList) Items() []Capture { return c.items } +// ItemsAsMetadata returns all the captures as metadata func (c *CaptureList) ItemsAsMetadata() []CaptureMetadata { c.mux.Lock() defer c.mux.Unlock() diff --git a/config.go b/config.go index dd7115b..eb92fcd 100644 --- a/config.go +++ b/config.go @@ -5,6 +5,7 @@ import ( "fmt" ) +// Config has all the configuration parsed from the command line type Config struct { TargetURL string `json:"targetURL"` ProxyPort string `json:"proxyPort"` @@ -17,6 +18,7 @@ type Config struct { DashboardItemInfoPath string `json:"dashboardItemInfoPath"` } +// ReadConfig reads the arguments from the command line func ReadConfig() Config { targetURL := flag.String("url", "https://jsonplaceholder.typicode.com", "Required. Set the base url you want to capture") proxyPort := flag.String("port", "9000", "Set the proxy port") diff --git a/main.go b/main.go index 5ff4833..bbcfb20 100644 --- a/main.go +++ b/main.go @@ -33,7 +33,7 @@ func startCapture(config Config) { handler := NewPlugin(NewRecorder(list, NewProxyHandler(config.TargetURL))) http.HandleFunc("/", handler) - http.HandleFunc(config.DashboardPath, NewDashboardHtmlHandler(config)) + http.HandleFunc(config.DashboardPath, NewDashboardHTMLHandler(config)) http.HandleFunc(config.DashboardConnPath, NewDashboardConnHandler(list)) http.HandleFunc(config.DashboardClearPath, NewDashboardClearHandler(list)) http.HandleFunc(config.DashboardRetryPath, NewDashboardRetryHandler(list, handler)) @@ -47,6 +47,8 @@ func startCapture(config Config) { fmt.Println(http.ListenAndServe(":"+config.ProxyPort, nil)) } +// NewDashboardConnHandler opens an event stream connection with the dashboard +// so that it is notified everytime a new capture arrives func NewDashboardConnHandler(list *CaptureList) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { if _, ok := rw.(http.Flusher); !ok { @@ -74,6 +76,7 @@ func NewDashboardConnHandler(list *CaptureList) http.HandlerFunc { } } +// NewDashboardClearHandler clears all the captures func NewDashboardClearHandler(list *CaptureList) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { list.RemoveAll() @@ -81,7 +84,8 @@ func NewDashboardClearHandler(list *CaptureList) http.HandlerFunc { } } -func NewDashboardHtmlHandler(config Config) http.HandlerFunc { +// NewDashboardHTMLHandler returns the dashboard html page +func NewDashboardHTMLHandler(config Config) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("Content-Type", "text/html") t, err := template.New("dashboard template").Delims("<<", ">>").Parse(dashboardHTML) @@ -95,6 +99,7 @@ func NewDashboardHtmlHandler(config Config) http.HandlerFunc { } } +// NewDashboardRetryHandler retries a request func NewDashboardRetryHandler(list *CaptureList, next http.HandlerFunc) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { id := req.URL.Path[strings.LastIndex(req.URL.Path, "/")+1:] @@ -112,6 +117,7 @@ func NewDashboardRetryHandler(list *CaptureList, next http.HandlerFunc) http.Han } } +// NewDashboardItemInfoHandler returns the full capture info func NewDashboardItemInfoHandler(list *CaptureList) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { id := req.URL.Path[strings.LastIndex(req.URL.Path, "/")+1:] @@ -125,6 +131,7 @@ func NewDashboardItemInfoHandler(list *CaptureList) http.HandlerFunc { } } +// NewPlugin setups plugin handler for requests and resposes func NewPlugin(next http.HandlerFunc) http.HandlerFunc { p, err := plugin.Open("plugin.so") if err != nil { @@ -146,6 +153,7 @@ func NewPlugin(next http.HandlerFunc) http.HandlerFunc { return pluginFn(next) } +// NewRecorder saves all the traffic data func NewRecorder(list *CaptureList, next http.HandlerFunc) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { @@ -171,6 +179,7 @@ func NewRecorder(list *CaptureList, next http.HandlerFunc) http.HandlerFunc { } } +// NewProxyHandler is the reverse proxy handler func NewProxyHandler(URL string) http.HandlerFunc { url, _ := url.Parse(URL) proxy := httputil.NewSingleHostReverseProxy(url) @@ -205,37 +214,49 @@ func dump(c *Capture) CaptureDump { func dumpRequest(req *http.Request) ([]byte, error) { if req.Header.Get("Content-Encoding") == "gzip" { - var reqBody []byte - req.Body, reqBody = drain(req.Body) - reader, _ := gzip.NewReader(bytes.NewReader(reqBody)) - req.Body = ioutil.NopCloser(reader) - reqDump, err := httputil.DumpRequest(req, true) - req.Body = ioutil.NopCloser(bytes.NewReader(reqBody)) - return reqDump, err + return dumpGzipRequest(req) } return httputil.DumpRequest(req, true) } +func dumpGzipRequest(req *http.Request) ([]byte, error) { + var reqBody []byte + req.Body, reqBody = drain(req.Body) + reader, _ := gzip.NewReader(bytes.NewReader(reqBody)) + req.Body = ioutil.NopCloser(reader) + reqDump, err := httputil.DumpRequest(req, true) + req.Body = ioutil.NopCloser(bytes.NewReader(reqBody)) + return reqDump, err +} + func dumpResponse(res *http.Response) ([]byte, error) { if res.StatusCode == StatusInternalProxyError { - // dumps only the body when we have an proxy error. - // This body is set in NewProxyHandler() - var resBody []byte - res.Body, resBody = drain(res.Body) - return resBody, nil + return dumpInternalProxyError(res) } if res.Header.Get("Content-Encoding") == "gzip" { - var resBody []byte - res.Body, resBody = drain(res.Body) - reader, _ := gzip.NewReader(bytes.NewReader(resBody)) - res.Body = ioutil.NopCloser(reader) - resDump, err := httputil.DumpResponse(res, true) - res.Body = ioutil.NopCloser(bytes.NewReader(resBody)) - return resDump, err + return dumpGzipResponse(res) } return httputil.DumpResponse(res, true) } +// Dumps only the body when we have an proxy error. +// This body is set in NewProxyHandler() in proxy.ErrorHandler +func dumpInternalProxyError(res *http.Response) ([]byte, error) { + var resBody []byte + res.Body, resBody = drain(res.Body) + return resBody, nil +} + +func dumpGzipResponse(res *http.Response) ([]byte, error) { + var resBody []byte + res.Body, resBody = drain(res.Body) + reader, _ := gzip.NewReader(bytes.NewReader(resBody)) + res.Body = ioutil.NopCloser(reader) + resDump, err := httputil.DumpResponse(res, true) + res.Body = ioutil.NopCloser(bytes.NewReader(resBody)) + return resDump, err +} + func drain(b io.ReadCloser) (io.ReadCloser, []byte) { all, _ := ioutil.ReadAll(b) b.Close()