github.com/stffabi/git-lfs@v2.3.5-0.20180214015214-8eeaa8d88902+incompatible/lfsapi/lfsapi.go (about) 1 package lfsapi 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http" 8 "regexp" 9 "sync" 10 11 "github.com/ThomsonReutersEikon/go-ntlm/ntlm" 12 "github.com/git-lfs/git-lfs/config" 13 "github.com/git-lfs/git-lfs/errors" 14 "github.com/git-lfs/git-lfs/git" 15 ) 16 17 var ( 18 lfsMediaTypeRE = regexp.MustCompile(`\Aapplication/vnd\.git\-lfs\+json(;|\z)`) 19 jsonMediaTypeRE = regexp.MustCompile(`\Aapplication/json(;|\z)`) 20 ) 21 22 type Client struct { 23 Endpoints EndpointFinder 24 Credentials CredentialHelper 25 SSH SSHResolver 26 Netrc NetrcFinder 27 28 DialTimeout int 29 KeepaliveTimeout int 30 TLSTimeout int 31 ConcurrentTransfers int 32 SkipSSLVerify bool 33 34 Verbose bool 35 DebuggingVerbose bool 36 VerboseOut io.Writer 37 38 hostClients map[string]*http.Client 39 clientMu sync.Mutex 40 41 ntlmSessions map[string]ntlm.ClientSession 42 ntlmMu sync.Mutex 43 44 httpLogger *syncLogger 45 46 LoggingStats bool // DEPRECATED 47 48 commandCredHelper *commandCredentialHelper 49 askpassCredHelper *AskPassCredentialHelper 50 cachingCredHelper *credentialCacher 51 gitEnv config.Environment 52 osEnv config.Environment 53 uc *config.URLConfig 54 } 55 56 type Context interface { 57 GitConfig() *git.Configuration 58 OSEnv() config.Environment 59 GitEnv() config.Environment 60 } 61 62 func NewClient(ctx Context) (*Client, error) { 63 if ctx == nil { 64 ctx = NewContext(nil, nil, nil) 65 } 66 67 gitEnv := ctx.GitEnv() 68 osEnv := ctx.OSEnv() 69 netrc, netrcfile, err := ParseNetrc(osEnv) 70 if err != nil { 71 return nil, errors.Wrap(err, fmt.Sprintf("bad netrc file %s", netrcfile)) 72 } 73 74 cacheCreds := gitEnv.Bool("lfs.cachecredentials", true) 75 var sshResolver SSHResolver = &sshAuthClient{os: osEnv} 76 if cacheCreds { 77 sshResolver = withSSHCache(sshResolver) 78 } 79 80 c := &Client{ 81 Endpoints: NewEndpointFinder(ctx), 82 SSH: sshResolver, 83 Netrc: netrc, 84 DialTimeout: gitEnv.Int("lfs.dialtimeout", 0), 85 KeepaliveTimeout: gitEnv.Int("lfs.keepalive", 0), 86 TLSTimeout: gitEnv.Int("lfs.tlstimeout", 0), 87 ConcurrentTransfers: gitEnv.Int("lfs.concurrenttransfers", 3), 88 SkipSSLVerify: !gitEnv.Bool("http.sslverify", true) || osEnv.Bool("GIT_SSL_NO_VERIFY", false), 89 Verbose: osEnv.Bool("GIT_CURL_VERBOSE", false), 90 DebuggingVerbose: osEnv.Bool("LFS_DEBUG_HTTP", false), 91 commandCredHelper: &commandCredentialHelper{ 92 SkipPrompt: osEnv.Bool("GIT_TERMINAL_PROMPT", false), 93 }, 94 gitEnv: gitEnv, 95 osEnv: osEnv, 96 uc: config.NewURLConfig(gitEnv), 97 } 98 99 askpass, ok := osEnv.Get("GIT_ASKPASS") 100 if !ok { 101 askpass, ok = gitEnv.Get("core.askpass") 102 } 103 if !ok { 104 askpass, _ = osEnv.Get("SSH_ASKPASS") 105 } 106 if len(askpass) > 0 { 107 c.askpassCredHelper = &AskPassCredentialHelper{ 108 Program: askpass, 109 } 110 } 111 112 if cacheCreds { 113 c.cachingCredHelper = newCredentialCacher() 114 } 115 116 return c, nil 117 } 118 119 func (c *Client) GitEnv() config.Environment { 120 return c.gitEnv 121 } 122 123 func (c *Client) OSEnv() config.Environment { 124 return c.osEnv 125 } 126 127 func IsDecodeTypeError(err error) bool { 128 _, ok := err.(*decodeTypeError) 129 return ok 130 } 131 132 type decodeTypeError struct { 133 Type string 134 } 135 136 func (e *decodeTypeError) TypeError() {} 137 138 func (e *decodeTypeError) Error() string { 139 return fmt.Sprintf("Expected json type, got: %q", e.Type) 140 } 141 142 func DecodeJSON(res *http.Response, obj interface{}) error { 143 ctype := res.Header.Get("Content-Type") 144 if !(lfsMediaTypeRE.MatchString(ctype) || jsonMediaTypeRE.MatchString(ctype)) { 145 return &decodeTypeError{Type: ctype} 146 } 147 148 err := json.NewDecoder(res.Body).Decode(obj) 149 res.Body.Close() 150 151 if err != nil { 152 return errors.Wrapf(err, "Unable to parse HTTP response for %s %s", res.Request.Method, res.Request.URL) 153 } 154 155 return nil 156 } 157 158 type testContext struct { 159 gitConfig *git.Configuration 160 osEnv config.Environment 161 gitEnv config.Environment 162 } 163 164 func (c *testContext) GitConfig() *git.Configuration { 165 return c.gitConfig 166 } 167 168 func (c *testContext) OSEnv() config.Environment { 169 return c.osEnv 170 } 171 172 func (c *testContext) GitEnv() config.Environment { 173 return c.gitEnv 174 } 175 176 func NewContext(gitConf *git.Configuration, osEnv, gitEnv map[string]string) Context { 177 c := &testContext{gitConfig: gitConf} 178 if c.gitConfig == nil { 179 c.gitConfig = git.NewConfig("", "") 180 } 181 if osEnv != nil { 182 c.osEnv = testEnv(osEnv) 183 } else { 184 c.osEnv = make(testEnv) 185 } 186 187 if gitEnv != nil { 188 c.gitEnv = testEnv(gitEnv) 189 } else { 190 c.gitEnv = make(testEnv) 191 } 192 return c 193 } 194 195 type testEnv map[string]string 196 197 func (e testEnv) Get(key string) (v string, ok bool) { 198 v, ok = e[key] 199 return 200 } 201 202 func (e testEnv) GetAll(key string) []string { 203 if v, ok := e.Get(key); ok { 204 return []string{v} 205 } 206 return make([]string, 0) 207 } 208 209 func (e testEnv) Int(key string, def int) int { 210 s, _ := e.Get(key) 211 return config.Int(s, def) 212 } 213 214 func (e testEnv) Bool(key string, def bool) bool { 215 s, _ := e.Get(key) 216 return config.Bool(s, def) 217 } 218 219 func (e testEnv) All() map[string][]string { 220 m := make(map[string][]string) 221 for k, _ := range e { 222 m[k] = e.GetAll(k) 223 } 224 return m 225 }