From 141465dea9e41fb801387b8e62818d78c6de6cae Mon Sep 17 00:00:00 2001 From: Eldad Marciano Date: Wed, 31 Aug 2022 14:56:09 +0300 Subject: [PATCH 1/3] dumping har logs to file --- cmd/proxy/main.go | 15 +++++++++++ har/har_handlers.go | 64 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/cmd/proxy/main.go b/cmd/proxy/main.go index 98ebf8de9..3a379c756 100644 --- a/cmd/proxy/main.go +++ b/cmd/proxy/main.go @@ -194,6 +194,7 @@ import ( "crypto/tls" "crypto/x509" "flag" + "fmt" "log" "net" "net/http" @@ -247,6 +248,7 @@ var ( validity = flag.Duration("validity", time.Hour, "window of time that MITM certificates are valid") allowCORS = flag.Bool("cors", false, "allow CORS requests to configure the proxy") harLogging = flag.Bool("har", false, "enable HAR logging API") + harFile = flag.String("harFile", "./martian.har", "har file path") marblLogging = flag.Bool("marbl", false, "enable MARBL logging API") trafficShaping = flag.Bool("traffic-shaping", false, "enable traffic shaping API") skipTLSVerify = flag.Bool("skip-tls-verify", false, "skip TLS server verification; insecure") @@ -389,6 +391,7 @@ func main() { configure("/logs", har.NewExportHandler(hl), mux) configure("/logs/reset", har.NewResetHandler(hl), mux) + configure("/logs/dump", har.NewDumpHandler(hl, *harFile), mux) } logger := martianlog.NewLogger() @@ -442,6 +445,18 @@ func main() { <-sigc + if *harLogging { + log.Println("martian: dumping har file") + u := url.URL{} + proxy, _ := u.Parse(fmt.Sprintf("http://%v", *addr)) + transport := http.Transport{} + transport.Proxy = http.ProxyURL(proxy) // set proxy + + client := &http.Client{} + client.Transport = &transport + client.Get("http://martian.proxy/logs/dump") + } + log.Println("martian: shutting down") os.Exit(0) } diff --git a/har/har_handlers.go b/har/har_handlers.go index aca499140..380536cdf 100644 --- a/har/har_handlers.go +++ b/har/har_handlers.go @@ -16,8 +16,11 @@ package har import ( "encoding/json" + "io" "net/http" "net/url" + "os" + "path/filepath" "strconv" "github.com/google/martian/v3/log" @@ -31,6 +34,11 @@ type resetHandler struct { logger *Logger } +type dumpHandler struct { + logger *Logger + filePath string +} + // NewExportHandler returns an http.Handler for requesting HAR logs. func NewExportHandler(l *Logger) http.Handler { return &exportHandler{ @@ -45,6 +53,61 @@ func NewResetHandler(l *Logger) http.Handler { } } +// NewDumpHandler returns an http.Handler for dumping log entries to file. +func NewDumpHandler(l *Logger, path string) http.Handler { + return &dumpHandler{ + logger: l, + filePath: path, + } +} + +type fileResponseWriter struct { + file io.Writer + multi io.Writer +} + +func (w *fileResponseWriter) Write(b []byte) (int, error) { + return w.multi.Write(b) +} + +func newFileResponseWriter(file io.Writer) io.Writer { + multi := io.MultiWriter(file) + return &fileResponseWriter{ + file: file, + multi: multi, + } +} + +func (h *dumpHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if req.Method != "GET" { + rw.Header().Add("Allow", "GET") + rw.WriteHeader(http.StatusMethodNotAllowed) + log.Errorf("har.ServeHTTP: method not allowed: %s", req.Method) + return + } + log.Debugf("exportHandler.ServeHTTP: writing HAR logs to ResponseWriter") + rw.Header().Set("Content-Type", "application/json; charset=utf-8") + + dir := filepath.Dir(h.filePath) + err := os.MkdirAll(dir, 0764) + if err != nil { + log.Errorf("mkdir", err) + } + + file, err := os.Create(h.filePath) + defer file.Close() + if err != nil { + log.Errorf("create file", err) + return + } + + writer := newFileResponseWriter(file) + hl := h.logger.Export() + encoder := json.NewEncoder(writer) + encoder.SetIndent("", "\t") + encoder.Encode(hl) +} + // ServeHTTP writes the log in HAR format to the response body. func (h *exportHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if req.Method != "GET" { @@ -70,7 +133,6 @@ func (h *resetHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { return } - v, err := parseBoolQueryParam(req.URL.Query(), "return") if err != nil { log.Errorf("har: invalid value for return param: %s", err) From 4cf95d6ab135f48aefecf050c0c67b8c3b6cc178 Mon Sep 17 00:00:00 2001 From: Eldad Marciano Date: Wed, 31 Aug 2022 15:41:51 +0300 Subject: [PATCH 2/3] defer after error --- har/har_handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/har/har_handlers.go b/har/har_handlers.go index 380536cdf..4dc058676 100644 --- a/har/har_handlers.go +++ b/har/har_handlers.go @@ -95,11 +95,11 @@ func (h *dumpHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } file, err := os.Create(h.filePath) - defer file.Close() if err != nil { log.Errorf("create file", err) return } + defer file.Close() writer := newFileResponseWriter(file) hl := h.logger.Export() From 5907ea44388b5b66330be25b0dd452c740170596 Mon Sep 17 00:00:00 2001 From: Eldad Marciano Date: Wed, 31 Aug 2022 15:55:44 +0300 Subject: [PATCH 3/3] only file writer --- har/har_handlers.go | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/har/har_handlers.go b/har/har_handlers.go index 380536cdf..342b0e1b3 100644 --- a/har/har_handlers.go +++ b/har/har_handlers.go @@ -16,7 +16,6 @@ package har import ( "encoding/json" - "io" "net/http" "net/url" "os" @@ -61,23 +60,7 @@ func NewDumpHandler(l *Logger, path string) http.Handler { } } -type fileResponseWriter struct { - file io.Writer - multi io.Writer -} - -func (w *fileResponseWriter) Write(b []byte) (int, error) { - return w.multi.Write(b) -} - -func newFileResponseWriter(file io.Writer) io.Writer { - multi := io.MultiWriter(file) - return &fileResponseWriter{ - file: file, - multi: multi, - } -} - +// ServeHTTP writes the log in HAR format to a file. func (h *dumpHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if req.Method != "GET" { rw.Header().Add("Allow", "GET") @@ -95,17 +78,15 @@ func (h *dumpHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } file, err := os.Create(h.filePath) - defer file.Close() if err != nil { log.Errorf("create file", err) return } + defer file.Close() - writer := newFileResponseWriter(file) - hl := h.logger.Export() - encoder := json.NewEncoder(writer) + encoder := json.NewEncoder(file) encoder.SetIndent("", "\t") - encoder.Encode(hl) + encoder.Encode(h.logger.Export()) } // ServeHTTP writes the log in HAR format to the response body.