bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/pkg/apiclient/client_http.go (about)

     1  package apiclient
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  	"net/url"
    12  	"strings"
    13  )
    14  
    15  func (c *ApiClient) NewRequest(method, url string, body interface{}) (*http.Request, error) {
    16  	if !strings.HasSuffix(c.BaseURL.Path, "/") {
    17  		return nil, fmt.Errorf("BaseURL must have a trailing slash, but %q does not", c.BaseURL)
    18  	}
    19  	u, err := c.BaseURL.Parse(url)
    20  	if err != nil {
    21  		return nil, err
    22  	}
    23  
    24  	var buf io.ReadWriter
    25  	if body != nil {
    26  		buf = &bytes.Buffer{}
    27  		enc := json.NewEncoder(buf)
    28  		enc.SetEscapeHTML(false)
    29  		err := enc.Encode(body)
    30  		if err != nil {
    31  			return nil, err
    32  		}
    33  	}
    34  
    35  	req, err := http.NewRequest(method, u.String(), buf)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	if body != nil {
    41  		req.Header.Set("Content-Type", "application/json")
    42  	}
    43  
    44  	return req, nil
    45  }
    46  
    47  func (c *ApiClient) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) {
    48  	if ctx == nil {
    49  		return nil, errors.New("context must be non-nil")
    50  	}
    51  	req = req.WithContext(ctx)
    52  
    53  	// Check rate limit
    54  
    55  	if c.UserAgent != "" {
    56  		req.Header.Add("User-Agent", c.UserAgent)
    57  	}
    58  
    59  	resp, err := c.client.Do(req)
    60  
    61  	if err != nil {
    62  		// If we got an error, and the context has been canceled,
    63  		// the context's error is probably more useful.
    64  		select {
    65  		case <-ctx.Done():
    66  			return nil, ctx.Err()
    67  		default:
    68  		}
    69  
    70  		// If the error type is *url.Error, sanitize its URL before returning.
    71  		if e, ok := err.(*url.Error); ok {
    72  			if url, err := url.Parse(e.URL); err == nil {
    73  				e.URL = url.String()
    74  				return newResponse(resp), e
    75  			} else {
    76  				return newResponse(resp), err
    77  			}
    78  		}
    79  		return newResponse(resp), err
    80  	}
    81  
    82  	response := newResponse(resp)
    83  
    84  	err = CheckResponse(resp)
    85  	if err != nil {
    86  		return response, err
    87  	}
    88  
    89  	if v != nil {
    90  		if w, ok := v.(io.Writer); ok {
    91  			io.Copy(w, resp.Body)
    92  		} else {
    93  			decErr := json.NewDecoder(resp.Body).Decode(v)
    94  			if decErr == io.EOF {
    95  				decErr = nil // ignore EOF errors caused by empty response body
    96  			}
    97  			if decErr != nil {
    98  				err = decErr
    99  			}
   100  		}
   101  	}
   102  	return response, err
   103  }