git-lfs/lfsapi/verbose.go

153 lines
3.2 KiB
Go
Raw Normal View History

2016-12-20 23:02:10 +00:00
package lfsapi
import (
"bufio"
"bytes"
"fmt"
"io"
2016-12-20 23:02:10 +00:00
"net/http"
"net/http/httputil"
"strings"
"github.com/rubyist/tracerx"
)
2016-12-22 18:01:51 +00:00
func (c *Client) traceRequest(req *http.Request) {
2016-12-20 23:02:10 +00:00
tracerx.Printf("HTTP: %s", traceReq(req))
2016-12-22 18:01:51 +00:00
if !c.Verbose {
return
}
if dump, err := httputil.DumpRequest(req, false); err == nil {
c.traceHTTPDump(">", dump)
}
2016-12-22 18:01:51 +00:00
}
2016-12-22 18:01:51 +00:00
func (c *Client) prepareRequestBody(req *http.Request) error {
body, ok := req.Body.(ReadSeekCloser)
if body != nil && !ok {
2016-12-21 18:22:22 +00:00
return fmt.Errorf("Request body must implement io.ReadCloser and io.Seeker. Got: %T", body)
}
2016-12-22 18:01:51 +00:00
if body != nil && ok {
body.Seek(0, io.SeekStart)
req.Body = &tracedRequest{
verbose: c.Verbose && isTraceableContent(req.Header),
verboseOut: c.VerboseOut,
ReadSeekCloser: body,
}
2016-12-20 23:02:10 +00:00
}
2016-12-21 18:22:22 +00:00
return nil
2016-12-20 23:02:10 +00:00
}
type tracedRequest struct {
2016-12-22 18:01:51 +00:00
verbose bool
verboseOut io.Writer
ReadSeekCloser
}
func (r *tracedRequest) Read(b []byte) (int, error) {
2016-12-22 18:01:51 +00:00
n, err := tracedRead(r.ReadSeekCloser, b, r.verboseOut, false, r.verbose)
return n, err
}
2016-12-22 18:01:51 +00:00
func (c *Client) traceResponse(res *http.Response) {
2016-12-20 23:02:10 +00:00
if res == nil {
2016-12-22 18:01:51 +00:00
return
2016-12-20 23:02:10 +00:00
}
tracerx.Printf("HTTP: %d", res.StatusCode)
2016-12-22 18:01:51 +00:00
verboseBody := isTraceableContent(res.Header)
res.Body = &tracedResponse{
client: c,
response: res,
gitTrace: verboseBody,
verbose: verboseBody && c.Verbose,
verboseOut: c.VerboseOut,
ReadCloser: res.Body,
2016-12-20 23:02:10 +00:00
}
2016-12-22 18:01:51 +00:00
if !c.Verbose {
return
2016-12-20 23:02:10 +00:00
}
2016-12-22 18:01:51 +00:00
if dump, err := httputil.DumpResponse(res, false); err == nil {
if verboseBody {
fmt.Fprintf(c.VerboseOut, "\n\n")
} else {
fmt.Fprintf(c.VerboseOut, "\n")
}
c.traceHTTPDump("<", dump)
2016-12-20 23:02:10 +00:00
}
}
type tracedResponse struct {
2016-12-22 18:01:51 +00:00
Count int
client *Client
response *http.Response
verbose bool
gitTrace bool
verboseOut io.Writer
io.ReadCloser
}
func (r *tracedResponse) Read(b []byte) (int, error) {
2016-12-22 18:01:51 +00:00
n, err := tracedRead(r.ReadCloser, b, r.verboseOut, r.gitTrace, r.verbose)
r.Count += n
2016-12-21 18:22:22 +00:00
if err == io.EOF {
r.client.finishResponseStats(r.response, int64(r.Count))
2016-12-21 18:22:22 +00:00
}
return n, err
}
2016-12-22 18:01:51 +00:00
func tracedRead(r io.Reader, b []byte, verboseOut io.Writer, gitTrace, verbose bool) (int, error) {
n, err := r.Read(b)
if err == nil || err == io.EOF {
2016-12-22 18:01:51 +00:00
if n > 0 && (gitTrace || verbose) {
chunk := string(b[0:n])
2016-12-22 18:01:51 +00:00
if gitTrace {
tracerx.Printf("HTTP: %s", chunk)
}
2016-12-22 18:01:51 +00:00
if verbose {
fmt.Fprint(verboseOut, chunk)
}
}
}
return n, err
2016-12-20 23:02:10 +00:00
}
func (c *Client) traceHTTPDump(direction string, dump []byte) {
scanner := bufio.NewScanner(bytes.NewBuffer(dump))
for scanner.Scan() {
line := scanner.Text()
if !c.DebuggingVerbose && strings.HasPrefix(strings.ToLower(line), "authorization: basic") {
2016-12-22 18:01:51 +00:00
fmt.Fprintf(c.VerboseOut, "%s Authorization: Basic * * * * *\n", direction)
2016-12-20 23:02:10 +00:00
} else {
2016-12-22 18:01:51 +00:00
fmt.Fprintf(c.VerboseOut, "%s %s\n", direction, line)
2016-12-20 23:02:10 +00:00
}
}
}
var tracedTypes = []string{"json", "text", "xml", "html"}
func isTraceableContent(h http.Header) bool {
ctype := strings.ToLower(strings.SplitN(h.Get("Content-Type"), ";", 2)[0])
for _, tracedType := range tracedTypes {
if strings.Contains(ctype, tracedType) {
return true
}
}
return false
}
func traceReq(req *http.Request) string {
return fmt.Sprintf("%s %s", req.Method, strings.SplitN(req.URL.String(), "?", 2)[0])
}