From dd8717797e51675b611a99efac9ada2e96b18696 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 8 Sep 2015 21:01:26 +0100 Subject: [PATCH] Implement --dump-headers and --dump-bodies debug flags --- fs/config.go | 12 +++++++++++- fs/loghttp.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 fs/loghttp.go diff --git a/fs/config.go b/fs/config.go index e751cd852..172031a9f 100644 --- a/fs/config.go +++ b/fs/config.go @@ -50,6 +50,8 @@ var ( dryRun = pflag.BoolP("dry-run", "n", false, "Do a trial run with no permanent changes") connectTimeout = pflag.DurationP("contimeout", "", 60*time.Second, "Connect timeout") timeout = pflag.DurationP("timeout", "", 5*60*time.Second, "IO idle timeout") + dumpHeaders = pflag.BoolP("dump-headers", "", false, "Dump HTTP headers - may contain sensitive info") + dumpBodies = pflag.BoolP("dump-bodies", "", false, "Dump HTTP headers and bodies - may contain sensitive info") bwLimit SizeSuffix ) @@ -155,11 +157,13 @@ type ConfigInfo struct { Transfers int ConnectTimeout time.Duration // Connect timeout Timeout time.Duration // Data channel timeout + DumpHeaders bool + DumpBodies bool } // Transport returns an http.RoundTripper with the correct timeouts func (ci *ConfigInfo) Transport() http.RoundTripper { - return &httpclient.Transport{ + t := &httpclient.Transport{ Proxy: http.ProxyFromEnvironment, MaxIdleConnsPerHost: ci.Checkers + ci.Transfers + 1, @@ -182,6 +186,10 @@ func (ci *ConfigInfo) Transport() http.RoundTripper { // Write operation on the request connection. ReadWriteTimeout: ci.Timeout, } + if ci.DumpHeaders || ci.DumpBodies { + return NewLoggedTransport(t, ci.DumpBodies) + } + return t } // Transport returns an http.Client with the correct timeouts @@ -227,6 +235,8 @@ func LoadConfig() { Config.ConnectTimeout = *connectTimeout Config.CheckSum = *checkSum Config.SizeOnly = *sizeOnly + Config.DumpHeaders = *dumpHeaders + Config.DumpBodies = *dumpBodies ConfigPath = *configFile diff --git a/fs/loghttp.go b/fs/loghttp.go new file mode 100644 index 000000000..e3fbe88d7 --- /dev/null +++ b/fs/loghttp.go @@ -0,0 +1,54 @@ +// A logging http transport + +package fs + +import ( + "log" + "net/http" + "net/http/httputil" +) + +const separator = "------------------------------------------------------------" + +// An http transport which logs the traffic +type loggedTransport struct { + wrapped http.RoundTripper + logBody bool +} + +// NewLoggedTransport wraps the transport passed in and logs all roundtrips +// including the body if logBody is set. +func NewLoggedTransport(transport http.RoundTripper, logBody bool) *loggedTransport { + return &loggedTransport{ + wrapped: transport, + logBody: logBody, + } +} + +// CancelRequest cancels an in-flight request by closing its +// connection. CancelRequest should only be called after RoundTrip has +// returned. +func (t *loggedTransport) CancelRequest(req *http.Request) { + if wrapped, ok := t.wrapped.(interface { + CancelRequest(*http.Request) + }); ok { + log.Printf("CANCEL REQUEST %v", req) + wrapped.CancelRequest(req) + } +} + +// RoundTrip implements the RoundTripper interface. +func (t *loggedTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { + buf, _ := httputil.DumpRequest(req, t.logBody) + log.Println(separator) + log.Println("HTTP REQUEST") + log.Println(string(buf)) + log.Println(separator) + resp, err = t.wrapped.RoundTrip(req) + buf, _ = httputil.DumpResponse(resp, t.logBody) + log.Println(separator) + log.Println("HTTP RESPONSE") + log.Println(string(buf)) + log.Println(separator) + return resp, err +}