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  }