github.com/saracen/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  }