github.com/ohlinux/git-lfs@v1.5.4/httputil/response.go (about)

     1  package httputil
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"regexp"
    10  
    11  	"github.com/git-lfs/git-lfs/auth"
    12  	"github.com/git-lfs/git-lfs/config"
    13  	"github.com/git-lfs/git-lfs/errors"
    14  )
    15  
    16  var (
    17  	lfsMediaTypeRE  = regexp.MustCompile(`\Aapplication/vnd\.git\-lfs\+json(;|\z)`)
    18  	jsonMediaTypeRE = regexp.MustCompile(`\Aapplication/json(;|\z)`)
    19  	hiddenHeaders   = map[string]bool{
    20  		"Authorization": true,
    21  	}
    22  
    23  	defaultErrors = map[int]string{
    24  		400: "Client error: %s",
    25  		401: "Authorization error: %s\nCheck that you have proper access to the repository",
    26  		403: "Authorization error: %s\nCheck that you have proper access to the repository",
    27  		404: "Repository or object not found: %s\nCheck that it exists and that you have proper access to it",
    28  		429: "Rate limit exceeded: %s",
    29  		500: "Server error: %s",
    30  		507: "Insufficient server storage: %s",
    31  		509: "Bandwidth limit exceeded: %s",
    32  	}
    33  )
    34  
    35  // DecodeResponse attempts to decode the contents of the response as a JSON object
    36  func DecodeResponse(res *http.Response, obj interface{}) error {
    37  	ctype := res.Header.Get("Content-Type")
    38  	if !(lfsMediaTypeRE.MatchString(ctype) || jsonMediaTypeRE.MatchString(ctype)) {
    39  		return nil
    40  	}
    41  
    42  	err := json.NewDecoder(res.Body).Decode(obj)
    43  	io.Copy(ioutil.Discard, res.Body)
    44  	res.Body.Close()
    45  
    46  	if err != nil {
    47  		return errors.Wrapf(err, "Unable to parse HTTP response for %s", TraceHttpReq(res.Request))
    48  	}
    49  
    50  	return nil
    51  }
    52  
    53  // GetDefaultError returns the default text for standard error codes (blank if none)
    54  func GetDefaultError(code int) string {
    55  	if s, ok := defaultErrors[code]; ok {
    56  		return s
    57  	}
    58  	return ""
    59  }
    60  
    61  // Check the response from a HTTP request for problems
    62  func handleResponse(cfg *config.Configuration, res *http.Response, creds auth.Creds) error {
    63  	auth.SaveCredentials(cfg, creds, res)
    64  
    65  	if res.StatusCode < 400 {
    66  		return nil
    67  	}
    68  
    69  	defer func() {
    70  		io.Copy(ioutil.Discard, res.Body)
    71  		res.Body.Close()
    72  	}()
    73  
    74  	cliErr := &ClientError{}
    75  	err := DecodeResponse(res, cliErr)
    76  	if err == nil {
    77  		if len(cliErr.Message) == 0 {
    78  			err = defaultError(res)
    79  		} else {
    80  			err = errors.Wrap(cliErr, "http")
    81  		}
    82  	}
    83  
    84  	if res.StatusCode == 401 {
    85  		if err == nil {
    86  			err = errors.New("api: received status 401")
    87  		}
    88  		return errors.NewAuthError(err)
    89  	}
    90  
    91  	if res.StatusCode > 499 && res.StatusCode != 501 && res.StatusCode != 507 && res.StatusCode != 509 {
    92  		if err == nil {
    93  			err = errors.Errorf("api: received status %d", res.StatusCode)
    94  		}
    95  		return errors.NewFatalError(err)
    96  	}
    97  
    98  	return err
    99  }
   100  
   101  func defaultError(res *http.Response) error {
   102  	var msgFmt string
   103  
   104  	if f, ok := defaultErrors[res.StatusCode]; ok {
   105  		msgFmt = f
   106  	} else if res.StatusCode < 500 {
   107  		msgFmt = defaultErrors[400] + fmt.Sprintf(" from HTTP %d", res.StatusCode)
   108  	} else {
   109  		msgFmt = defaultErrors[500] + fmt.Sprintf(" from HTTP %d", res.StatusCode)
   110  	}
   111  
   112  	return errors.Errorf(msgFmt, res.Request.URL)
   113  }
   114  
   115  func SetErrorResponseContext(cfg *config.Configuration, err error, res *http.Response) {
   116  	errors.SetContext(err, "Status", res.Status)
   117  	setErrorHeaderContext(err, "Request", res.Header)
   118  	setErrorRequestContext(cfg, err, res.Request)
   119  }
   120  
   121  func setErrorRequestContext(cfg *config.Configuration, err error, req *http.Request) {
   122  	errors.SetContext(err, "Endpoint", cfg.Endpoint(auth.GetOperationForRequest(req)).Url)
   123  	errors.SetContext(err, "URL", TraceHttpReq(req))
   124  	setErrorHeaderContext(err, "Response", req.Header)
   125  }
   126  
   127  func setErrorHeaderContext(err error, prefix string, head http.Header) {
   128  	for key, _ := range head {
   129  		contextKey := fmt.Sprintf("%s:%s", prefix, key)
   130  		if _, skip := hiddenHeaders[key]; skip {
   131  			errors.SetContext(err, contextKey, "--")
   132  		} else {
   133  			errors.SetContext(err, contextKey, head.Get(key))
   134  		}
   135  	}
   136  }