github.com/2lambda123/git-lfs@v2.5.2+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 sshTries int 56 } 57 58 type Context interface { 59 GitConfig() *git.Configuration 60 OSEnv() config.Environment 61 GitEnv() config.Environment 62 } 63 64 func NewClient(ctx Context) (*Client, error) { 65 if ctx == nil { 66 ctx = NewContext(nil, nil, nil) 67 } 68 69 gitEnv := ctx.GitEnv() 70 osEnv := ctx.OSEnv() 71 netrc, netrcfile, err := ParseNetrc(osEnv) 72 if err != nil { 73 return nil, errors.Wrap(err, fmt.Sprintf("bad netrc file %s", netrcfile)) 74 } 75 76 cacheCreds := gitEnv.Bool("lfs.cachecredentials", true) 77 var sshResolver SSHResolver = &sshAuthClient{os: osEnv, git: gitEnv} 78 if cacheCreds { 79 sshResolver = withSSHCache(sshResolver) 80 } 81 82 c := &Client{ 83 Endpoints: NewEndpointFinder(ctx), 84 SSH: sshResolver, 85 Netrc: netrc, 86 DialTimeout: gitEnv.Int("lfs.dialtimeout", 0), 87 KeepaliveTimeout: gitEnv.Int("lfs.keepalive", 0), 88 TLSTimeout: gitEnv.Int("lfs.tlstimeout", 0), 89 ConcurrentTransfers: gitEnv.Int("lfs.concurrenttransfers", 3), 90 SkipSSLVerify: !gitEnv.Bool("http.sslverify", true) || osEnv.Bool("GIT_SSL_NO_VERIFY", false), 91 Verbose: osEnv.Bool("GIT_CURL_VERBOSE", false), 92 DebuggingVerbose: osEnv.Bool("LFS_DEBUG_HTTP", false), 93 commandCredHelper: &commandCredentialHelper{ 94 SkipPrompt: osEnv.Bool("GIT_TERMINAL_PROMPT", false), 95 }, 96 gitEnv: gitEnv, 97 osEnv: osEnv, 98 uc: config.NewURLConfig(gitEnv), 99 sshTries: gitEnv.Int("lfs.ssh.retries", 5), 100 } 101 102 askpass, ok := osEnv.Get("GIT_ASKPASS") 103 if !ok { 104 askpass, ok = gitEnv.Get("core.askpass") 105 } 106 if !ok { 107 askpass, _ = osEnv.Get("SSH_ASKPASS") 108 } 109 if len(askpass) > 0 { 110 c.askpassCredHelper = &AskPassCredentialHelper{ 111 Program: askpass, 112 } 113 } 114 115 if cacheCreds { 116 c.cachingCredHelper = newCredentialCacher() 117 } 118 119 return c, nil 120 } 121 122 func (c *Client) GitEnv() config.Environment { 123 return c.gitEnv 124 } 125 126 func (c *Client) OSEnv() config.Environment { 127 return c.osEnv 128 } 129 130 func IsDecodeTypeError(err error) bool { 131 _, ok := err.(*decodeTypeError) 132 return ok 133 } 134 135 type decodeTypeError struct { 136 Type string 137 } 138 139 func (e *decodeTypeError) TypeError() {} 140 141 func (e *decodeTypeError) Error() string { 142 return fmt.Sprintf("Expected json type, got: %q", e.Type) 143 } 144 145 func DecodeJSON(res *http.Response, obj interface{}) error { 146 ctype := res.Header.Get("Content-Type") 147 if !(lfsMediaTypeRE.MatchString(ctype) || jsonMediaTypeRE.MatchString(ctype)) { 148 return &decodeTypeError{Type: ctype} 149 } 150 151 err := json.NewDecoder(res.Body).Decode(obj) 152 res.Body.Close() 153 154 if err != nil { 155 return errors.Wrapf(err, "Unable to parse HTTP response for %s %s", res.Request.Method, res.Request.URL) 156 } 157 158 return nil 159 } 160 161 type testContext struct { 162 gitConfig *git.Configuration 163 osEnv config.Environment 164 gitEnv config.Environment 165 } 166 167 func (c *testContext) GitConfig() *git.Configuration { 168 return c.gitConfig 169 } 170 171 func (c *testContext) OSEnv() config.Environment { 172 return c.osEnv 173 } 174 175 func (c *testContext) GitEnv() config.Environment { 176 return c.gitEnv 177 } 178 179 func NewContext(gitConf *git.Configuration, osEnv, gitEnv map[string]string) Context { 180 c := &testContext{gitConfig: gitConf} 181 if c.gitConfig == nil { 182 c.gitConfig = git.NewConfig("", "") 183 } 184 if osEnv != nil { 185 c.osEnv = testEnv(osEnv) 186 } else { 187 c.osEnv = make(testEnv) 188 } 189 190 if gitEnv != nil { 191 c.gitEnv = testEnv(gitEnv) 192 } else { 193 c.gitEnv = make(testEnv) 194 } 195 return c 196 } 197 198 type testEnv map[string]string 199 200 func (e testEnv) Get(key string) (v string, ok bool) { 201 v, ok = e[key] 202 return 203 } 204 205 func (e testEnv) GetAll(key string) []string { 206 if v, ok := e.Get(key); ok { 207 return []string{v} 208 } 209 return make([]string, 0) 210 } 211 212 func (e testEnv) Int(key string, def int) int { 213 s, _ := e.Get(key) 214 return config.Int(s, def) 215 } 216 217 func (e testEnv) Bool(key string, def bool) bool { 218 s, _ := e.Get(key) 219 return config.Bool(s, def) 220 } 221 222 func (e testEnv) All() map[string][]string { 223 m := make(map[string][]string) 224 for k, _ := range e { 225 m[k] = e.GetAll(k) 226 } 227 return m 228 }