Merge pull request #175 from hawser/http-trace
trace http calls in DoHTTP()
This commit is contained in:
commit
140b755fbf
@ -38,7 +38,7 @@ func Download(oidPath string) (io.ReadCloser, int64, *WrappedError) {
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", gitMediaType)
|
||||
res, wErr := doRequest(req, creds)
|
||||
res, wErr := doHTTPWithCreds(req, creds)
|
||||
|
||||
if wErr != nil {
|
||||
return nil, 0, wErr
|
||||
@ -190,11 +190,10 @@ func callOptions(filehash string) (int, *WrappedError) {
|
||||
return 0, Errorf(err, "Unable to build OPTIONS request for %s", oid)
|
||||
}
|
||||
|
||||
res, wErr := doRequest(req, creds)
|
||||
res, wErr := doHTTPWithCreds(req, creds)
|
||||
if wErr != nil {
|
||||
return 0, wErr
|
||||
}
|
||||
tracerx.Printf("api_options_status: %d", res.StatusCode)
|
||||
|
||||
return res.StatusCode, nil
|
||||
}
|
||||
@ -240,8 +239,7 @@ func callPut(filehash, filename string, cb CopyCallback) *WrappedError {
|
||||
fmt.Printf("Sending %s\n", filename)
|
||||
|
||||
tracerx.Printf("api_put: %s %s", oid, filename)
|
||||
res, wErr := doRequest(req, creds)
|
||||
tracerx.Printf("api_put_status: %d", res.StatusCode)
|
||||
_, wErr := doHTTPWithCreds(req, creds)
|
||||
|
||||
return wErr
|
||||
}
|
||||
@ -296,7 +294,6 @@ func callExternalPut(filehash, filename string, obj *objectResource, cb CopyCall
|
||||
if err != nil {
|
||||
return Errorf(err, "Error attempting to PUT %s", filename)
|
||||
}
|
||||
tracerx.Printf("external_put_status: %d", res.StatusCode)
|
||||
saveCredentials(creds, res)
|
||||
|
||||
// Run the verify callback
|
||||
@ -323,7 +320,6 @@ func callExternalPut(filehash, filename string, obj *objectResource, cb CopyCall
|
||||
if err != nil {
|
||||
return Errorf(err, "Error attempting to verify %s", filename)
|
||||
}
|
||||
tracerx.Printf("verify_status: %d", verifyRes.StatusCode)
|
||||
saveCredentials(verifyCreds, verifyRes)
|
||||
|
||||
return nil
|
||||
@ -354,11 +350,10 @@ func callPost(filehash, filename string) (*objectResource, int, *WrappedError) {
|
||||
req.Header.Set("Accept", gitMediaMetaType)
|
||||
|
||||
tracerx.Printf("api_post: %s %s", oid, filename)
|
||||
res, wErr := doRequest(req, creds)
|
||||
res, wErr := doHTTPWithCreds(req, creds)
|
||||
if wErr != nil {
|
||||
return nil, 0, wErr
|
||||
}
|
||||
tracerx.Printf("api_post_status: %d", res.StatusCode)
|
||||
|
||||
if res.StatusCode == 202 {
|
||||
obj := &objectResource{}
|
||||
@ -404,7 +399,9 @@ func validateMediaHeader(contentType string, reader io.Reader) (bool, int, *Wrap
|
||||
return true, headerSize, nil
|
||||
}
|
||||
|
||||
func doRequest(req *http.Request, creds Creds) (*http.Response, *WrappedError) {
|
||||
// Wraps DoHTTP(), and saves or removes credentials from the git credential
|
||||
// store based on the response.
|
||||
func doHTTPWithCreds(req *http.Request, creds Creds) (*http.Response, *WrappedError) {
|
||||
res, err := DoHTTP(Config, req)
|
||||
|
||||
var wErr *WrappedError
|
||||
|
@ -17,15 +17,24 @@ type Configuration struct {
|
||||
remotes []string
|
||||
httpClient *http.Client
|
||||
redirectingHttpClient *http.Client
|
||||
isTracingHttp bool
|
||||
}
|
||||
|
||||
var (
|
||||
Config = &Configuration{CurrentRemote: defaultRemote}
|
||||
Config = NewConfig()
|
||||
RedirectError = fmt.Errorf("Unexpected redirection")
|
||||
httpPrefixRe = regexp.MustCompile("\\Ahttps?://")
|
||||
defaultRemote = "origin"
|
||||
)
|
||||
|
||||
func NewConfig() *Configuration {
|
||||
c := &Configuration{
|
||||
CurrentRemote: defaultRemote,
|
||||
isTracingHttp: len(os.Getenv("GIT_CURL_VERBOSE")) > 0,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Configuration) Endpoint() string {
|
||||
if url, ok := c.GitConfig("hawser.url"); ok {
|
||||
return url
|
||||
@ -69,24 +78,18 @@ func (c *Configuration) RemoteEndpoint(remote string) string {
|
||||
}
|
||||
|
||||
func (c *Configuration) Remotes() []string {
|
||||
if c.remotes == nil {
|
||||
c.loadGitConfig()
|
||||
}
|
||||
c.loadGitConfig()
|
||||
return c.remotes
|
||||
}
|
||||
|
||||
func (c *Configuration) GitConfig(key string) (string, bool) {
|
||||
if c.gitConfig == nil {
|
||||
c.loadGitConfig()
|
||||
}
|
||||
c.loadGitConfig()
|
||||
value, ok := c.gitConfig[strings.ToLower(key)]
|
||||
return value, ok
|
||||
}
|
||||
|
||||
func (c *Configuration) SetConfig(key, value string) {
|
||||
if c.gitConfig == nil {
|
||||
c.loadGitConfig()
|
||||
}
|
||||
c.loadGitConfig()
|
||||
c.gitConfig[key] = value
|
||||
}
|
||||
|
||||
@ -107,6 +110,10 @@ type AltConfig struct {
|
||||
}
|
||||
|
||||
func (c *Configuration) loadGitConfig() {
|
||||
if c.gitConfig != nil {
|
||||
return
|
||||
}
|
||||
|
||||
uniqRemotes := make(map[string]bool)
|
||||
|
||||
c.gitConfig = make(map[string]string)
|
||||
@ -148,10 +155,3 @@ func (c *Configuration) loadGitConfig() {
|
||||
c.remotes = append(c.remotes, remote)
|
||||
}
|
||||
}
|
||||
|
||||
func configFileExists(filename string) bool {
|
||||
if _, err := os.Stat(filename); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
118
hawser/http.go
118
hawser/http.go
@ -2,17 +2,36 @@ package hawser
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/rubyist/tracerx"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func DoHTTP(c *Configuration, req *http.Request) (*http.Response, error) {
|
||||
var res *http.Response
|
||||
var err error
|
||||
|
||||
var counter *countingBody
|
||||
if req.Body != nil {
|
||||
counter = newCountingBody(req.Body)
|
||||
req.Body = counter
|
||||
}
|
||||
|
||||
traceHttpRequest(c, req)
|
||||
|
||||
switch req.Method {
|
||||
case "GET", "HEAD":
|
||||
return c.RedirectingHttpClient().Do(req)
|
||||
res, err = c.RedirectingHttpClient().Do(req)
|
||||
default:
|
||||
return c.HttpClient().Do(req)
|
||||
res, err = c.HttpClient().Do(req)
|
||||
}
|
||||
|
||||
traceHttpResponse(c, res, counter)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (c *Configuration) HttpClient() *http.Client {
|
||||
@ -29,18 +48,97 @@ func (c *Configuration) HttpClient() *http.Client {
|
||||
|
||||
func (c *Configuration) RedirectingHttpClient() *http.Client {
|
||||
if c.redirectingHttpClient == nil {
|
||||
c.redirectingHttpClient = &http.Client{
|
||||
Transport: httpTransportFor(c),
|
||||
tr := &http.Transport{}
|
||||
sslVerify, _ := c.GitConfig("http.sslverify")
|
||||
if sslVerify == "false" || len(os.Getenv("GIT_SSL_NO_VERIFY")) > 0 {
|
||||
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
c.redirectingHttpClient = &http.Client{Transport: tr}
|
||||
}
|
||||
return c.redirectingHttpClient
|
||||
}
|
||||
|
||||
func httpTransportFor(c *Configuration) *http.Transport {
|
||||
tr := &http.Transport{}
|
||||
sslVerify, _ := c.GitConfig("http.sslverify")
|
||||
if len(os.Getenv("GIT_SSL_NO_VERIFY")) > 0 || sslVerify == "false" {
|
||||
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
var tracedTypes = []string{"json", "text", "xml", "html"}
|
||||
|
||||
func traceHttpRequest(c *Configuration, req *http.Request) {
|
||||
tracerx.Printf("HTTP: %s %s", req.Method, req.URL.String())
|
||||
|
||||
if c.isTracingHttp == false {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "> %s %s %s\n", req.Method, req.URL.RequestURI(), req.Proto)
|
||||
for key, _ := range req.Header {
|
||||
fmt.Fprintf(os.Stderr, "> %s: %s\n", key, req.Header.Get(key))
|
||||
}
|
||||
return tr
|
||||
}
|
||||
|
||||
func traceHttpResponse(c *Configuration, res *http.Response, counter *countingBody) {
|
||||
tracerx.Printf("HTTP: %d", res.StatusCode)
|
||||
|
||||
if c.isTracingHttp == false {
|
||||
return
|
||||
}
|
||||
|
||||
if counter != nil {
|
||||
fmt.Fprintf(os.Stderr, "* upload sent off: %d bytes\n", counter.Size)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
|
||||
fmt.Fprintf(os.Stderr, "< %s %s\n", res.Proto, res.Status)
|
||||
for key, _ := range res.Header {
|
||||
fmt.Fprintf(os.Stderr, "< %s: %s\n", key, res.Header.Get(key))
|
||||
}
|
||||
|
||||
traceBody := false
|
||||
ctype := strings.ToLower(strings.SplitN(res.Header.Get("Content-Type"), ";", 2)[0])
|
||||
for _, tracedType := range tracedTypes {
|
||||
if strings.Contains(ctype, tracedType) {
|
||||
traceBody = true
|
||||
}
|
||||
}
|
||||
|
||||
if traceBody {
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
res.Body = newTracedBody(res.Body)
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
}
|
||||
|
||||
type countingBody struct {
|
||||
body io.ReadCloser
|
||||
Size int64
|
||||
}
|
||||
|
||||
func (r *countingBody) Read(p []byte) (int, error) {
|
||||
n, err := r.body.Read(p)
|
||||
r.Size += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *countingBody) Close() error {
|
||||
return r.body.Close()
|
||||
}
|
||||
|
||||
func newCountingBody(body io.ReadCloser) *countingBody {
|
||||
return &countingBody{body, 0}
|
||||
}
|
||||
|
||||
type tracedBody struct {
|
||||
body io.ReadCloser
|
||||
}
|
||||
|
||||
func (r *tracedBody) Read(p []byte) (int, error) {
|
||||
n, err := r.body.Read(p)
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(p[0:n]))
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *tracedBody) Close() error {
|
||||
return r.body.Close()
|
||||
}
|
||||
|
||||
func newTracedBody(body io.ReadCloser) *tracedBody {
|
||||
return &tracedBody{body}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user