diff options
author | John Cai <jcai@gitlab.com> | 2020-05-04 10:59:49 -0700 |
---|---|---|
committer | John Cai <jcai@gitlab.com> | 2020-05-04 14:19:47 -0700 |
commit | 91f45342c4ff29a24c61812d539ac745dbb1570a (patch) | |
tree | aec9280d8c4e1c0d02515f1ca9d46a65182cfb14 /client/gitlabnet.go | |
parent | f62a4b2fb89754372a346f24659212eb8da13601 (diff) | |
download | gitlab-shell-jc-refactor-gitlabnet-client.tar.gz |
Move gitlabnet client to client packagejc-refactor-gitlabnet-client
Diffstat (limited to 'client/gitlabnet.go')
-rw-r--r-- | client/gitlabnet.go | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/client/gitlabnet.go b/client/gitlabnet.go new file mode 100644 index 0000000..67c48c7 --- /dev/null +++ b/client/gitlabnet.go @@ -0,0 +1,140 @@ +package client + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" + + log "github.com/sirupsen/logrus" +) + +const ( + internalApiPath = "/api/v4/internal" + secretHeaderName = "Gitlab-Shared-Secret" +) + +type ErrorResponse struct { + Message string `json:"message"` +} + +type GitlabNetClient struct { + httpClient *HttpClient + user, password, secret string +} + +func NewGitlabNetClient( + user, + password, + secret string, + httpClient *HttpClient, +) (*GitlabNetClient, error) { + + if httpClient == nil { + return nil, fmt.Errorf("Unsupported protocol") + } + + return &GitlabNetClient{ + httpClient: httpClient, + user: user, + password: password, + secret: secret, + }, nil +} + +func normalizePath(path string) string { + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + + if !strings.HasPrefix(path, internalApiPath) { + path = internalApiPath + path + } + return path +} + +func newRequest(method, host, path string, data interface{}) (*http.Request, error) { + var jsonReader io.Reader + if data != nil { + jsonData, err := json.Marshal(data) + if err != nil { + return nil, err + } + + jsonReader = bytes.NewReader(jsonData) + } + + request, err := http.NewRequest(method, host+path, jsonReader) + if err != nil { + return nil, err + } + + return request, nil +} + +func parseError(resp *http.Response) error { + if resp.StatusCode >= 200 && resp.StatusCode <= 399 { + return nil + } + defer resp.Body.Close() + parsedResponse := &ErrorResponse{} + + if err := json.NewDecoder(resp.Body).Decode(parsedResponse); err != nil { + return fmt.Errorf("Internal API error (%v)", resp.StatusCode) + } else { + return fmt.Errorf(parsedResponse.Message) + } + +} + +func (c *GitlabNetClient) Get(path string) (*http.Response, error) { + return c.DoRequest(http.MethodGet, normalizePath(path), nil) +} + +func (c *GitlabNetClient) Post(path string, data interface{}) (*http.Response, error) { + return c.DoRequest(http.MethodPost, normalizePath(path), data) +} + +func (c *GitlabNetClient) DoRequest(method, path string, data interface{}) (*http.Response, error) { + request, err := newRequest(method, c.httpClient.Host, path, data) + if err != nil { + return nil, err + } + + user, password := c.user, c.password + if user != "" && password != "" { + request.SetBasicAuth(user, password) + } + + encodedSecret := base64.StdEncoding.EncodeToString([]byte(c.secret)) + request.Header.Set(secretHeaderName, encodedSecret) + + request.Header.Add("Content-Type", "application/json") + request.Close = true + + start := time.Now() + response, err := c.httpClient.Do(request) + fields := log.Fields{ + "method": method, + "url": request.URL.String(), + "duration_ms": time.Since(start) / time.Millisecond, + } + + if err != nil { + log.WithError(err).WithFields(fields).Error("Internal API unreachable") + return nil, fmt.Errorf("Internal API unreachable") + } + + if err := parseError(response); err != nil { + log.WithError(err).WithFields(fields).Error("Internal API error") + return nil, err + } + + log.WithFields(fields).Info("Finished HTTP request") + + return response, nil +} |