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  }