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 }