git-lfs/lfsapi/lfsapi.go
2016-12-21 10:33:12 -07:00

150 lines
3.2 KiB
Go

package lfsapi
import (
"encoding/json"
"net/http"
"regexp"
"strconv"
"strings"
"sync"
"github.com/git-lfs/git-lfs/errors"
)
var (
lfsMediaTypeRE = regexp.MustCompile(`\Aapplication/vnd\.git\-lfs\+json(;|\z)`)
jsonMediaTypeRE = regexp.MustCompile(`\Aapplication/json(;|\z)`)
)
type Client struct {
Endpoints EndpointFinder
Credentials CredentialHelper
Netrc NetrcFinder
DialTimeout int
KeepaliveTimeout int
TLSTimeout int
ConcurrentTransfers int
HTTPSProxy string
HTTPProxy string
NoProxy string
SkipSSLVerify bool
IsTracing bool
IsDebugging bool
IsLogging bool
hostClients map[string]*http.Client
clientMu sync.Mutex
// only used for per-host ssl certs
gitEnv env
osEnv env
}
func NewClient(osEnv env, gitEnv env) (*Client, error) {
if osEnv == nil {
osEnv = make(testEnv)
}
if gitEnv == nil {
gitEnv = make(testEnv)
}
netrc, err := ParseNetrc(osEnv)
if err != nil {
return nil, err
}
httpsProxy, httpProxy, noProxy := getProxyServers(osEnv, gitEnv)
c := &Client{
Endpoints: NewEndpointFinder(gitEnv),
Credentials: &CommandCredentialHelper{
SkipPrompt: !osEnv.Bool("GIT_TERMINAL_PROMPT", true),
},
Netrc: netrc,
DialTimeout: gitEnv.Int("lfs.dialtimeout", 0),
KeepaliveTimeout: gitEnv.Int("lfs.keepalive", 0),
TLSTimeout: gitEnv.Int("lfs.tlstimeout", 0),
ConcurrentTransfers: gitEnv.Int("lfs.concurrenttransfers", 0),
SkipSSLVerify: !gitEnv.Bool("http.sslverify", true) || osEnv.Bool("GIT_SSL_NO_VERIFY", false),
IsTracing: osEnv.Bool("GIT_CURL_VERBOSE", false),
IsDebugging: osEnv.Bool("LFS_DEBUG_HTTP", false),
IsLogging: osEnv.Bool("GIT_LOG_STATS", false),
HTTPSProxy: httpsProxy,
HTTPProxy: httpProxy,
NoProxy: noProxy,
gitEnv: gitEnv,
osEnv: osEnv,
}
return c, nil
}
func decodeResponse(res *http.Response, obj interface{}) error {
ctype := res.Header.Get("Content-Type")
if !(lfsMediaTypeRE.MatchString(ctype) || jsonMediaTypeRE.MatchString(ctype)) {
return nil
}
err := json.NewDecoder(res.Body).Decode(obj)
res.Body.Close()
if err != nil {
return errors.Wrapf(err, "Unable to parse HTTP response for %s %s", res.Request.Method, res.Request.URL)
}
return nil
}
type env interface {
Get(string) (string, bool)
Int(string, int) int
Bool(string, bool) bool
All() map[string]string
}
// basic config.Environment implementation. Only used in tests, or as a zero
// value to NewClient().
type testEnv map[string]string
func (e testEnv) Get(key string) (string, bool) {
v, ok := e[key]
return v, ok
}
func (e testEnv) Int(key string, def int) (val int) {
s, _ := e.Get(key)
if len(s) == 0 {
return def
}
i, err := strconv.Atoi(s)
if err != nil {
return def
}
return i
}
func (e testEnv) Bool(key string, def bool) (val bool) {
s, _ := e.Get(key)
if len(s) == 0 {
return def
}
switch strings.ToLower(s) {
case "true", "1", "on", "yes", "t":
return true
case "false", "0", "off", "no", "f":
return false
default:
return false
}
}
func (e testEnv) All() map[string]string {
return e
}