github.com/fawick/restic@v0.1.1-0.20171126184616-c02923fbfc79/internal/debug/round_tripper_debug.go (about) 1 // +build debug 2 3 package debug 4 5 import ( 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net/http" 10 "net/http/httputil" 11 "os" 12 13 "github.com/restic/restic/internal/errors" 14 ) 15 16 type eofDetectRoundTripper struct { 17 http.RoundTripper 18 } 19 20 type eofDetectReader struct { 21 eofSeen bool 22 rd io.ReadCloser 23 } 24 25 func (rd *eofDetectReader) Read(p []byte) (n int, err error) { 26 n, err = rd.rd.Read(p) 27 if err == io.EOF { 28 rd.eofSeen = true 29 } 30 return n, err 31 } 32 33 func (rd *eofDetectReader) Close() error { 34 if !rd.eofSeen { 35 buf, err := ioutil.ReadAll(rd) 36 msg := fmt.Sprintf("body not drained, %d bytes not read", len(buf)) 37 if err != nil { 38 msg += fmt.Sprintf(", error: %v", err) 39 } 40 41 if len(buf) > 0 { 42 if len(buf) > 20 { 43 buf = append(buf[:20], []byte("...")...) 44 } 45 msg += fmt.Sprintf(", body: %q", buf) 46 } 47 48 fmt.Fprintln(os.Stderr, msg) 49 Log("%s: %+v", msg, errors.New("Close()")) 50 } 51 return rd.rd.Close() 52 } 53 54 func (tr eofDetectRoundTripper) RoundTrip(req *http.Request) (res *http.Response, err error) { 55 res, err = tr.RoundTripper.RoundTrip(req) 56 if res != nil && res.Body != nil { 57 res.Body = &eofDetectReader{rd: res.Body} 58 } 59 return res, err 60 } 61 62 type loggingRoundTripper struct { 63 http.RoundTripper 64 } 65 66 // RoundTripper returns a new http.RoundTripper which logs all requests (if 67 // debug is enabled). When debug is not enabled, upstream is returned. 68 func RoundTripper(upstream http.RoundTripper) http.RoundTripper { 69 return loggingRoundTripper{eofDetectRoundTripper{upstream}} 70 } 71 72 func (tr loggingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, err error) { 73 trace, err := httputil.DumpRequestOut(req, false) 74 if err != nil { 75 Log("DumpRequestOut() error: %v\n", err) 76 } else { 77 Log("------------ HTTP REQUEST -----------\n%s", trace) 78 } 79 80 res, err = tr.RoundTripper.RoundTrip(req) 81 if err != nil { 82 Log("RoundTrip() returned error: %v", err) 83 } 84 85 if res != nil { 86 trace, err := httputil.DumpResponse(res, false) 87 if err != nil { 88 Log("DumpResponse() error: %v\n", err) 89 } else { 90 Log("------------ HTTP RESPONSE ----------\n%s", trace) 91 } 92 } 93 94 return res, err 95 }