From e75d84004620206f0cddffea8745860cbc4ec260 Mon Sep 17 00:00:00 2001 From: Omer Zidkoni <50792403+omerzi@users.noreply.github.com> Date: Sun, 18 Dec 2022 11:49:52 +0200 Subject: [PATCH] Check HTTP response status code in DownloadRepository (#54) --- vcsclient/azurerepos.go | 12 +++++++----- vcsclient/bitbucketcloud.go | 3 +++ vcsclient/github.go | 3 +++ vcsutils/utils.go | 37 +++++++++++++++++++++++++++++++++++-- vcsutils/utils_test.go | 19 +++++++++++++++++++ 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/vcsclient/azurerepos.go b/vcsclient/azurerepos.go index e7fbce95..dd57c612 100644 --- a/vcsclient/azurerepos.go +++ b/vcsclient/azurerepos.go @@ -94,9 +94,11 @@ func (client *AzureReposClient) DownloadRepository(ctx context.Context, owner, r }() res, err := client.sendDownloadRepoRequest(ctx, repository, branch) defer func() { - e := res.Body.Close() - if err == nil { - err = e + if res.Body != nil { + e := res.Body.Close() + if err == nil { + err = e + } } }() if err != nil { @@ -140,8 +142,8 @@ func (client *AzureReposClient) sendDownloadRepoRequest(ctx context.Context, rep if res, err = httpClient.Do(req); err != nil { return } - if res.StatusCode < 200 || res.StatusCode >= 300 { - err = fmt.Errorf("bad HTTP status: %d", res.StatusCode) + if err = vcsutils.CheckResponseStatusWithBody(res, http.StatusOK); err != nil { + return &http.Response{}, err } client.logger.Info(repository, "downloaded successfully, starting with repository extraction") return diff --git a/vcsclient/bitbucketcloud.go b/vcsclient/bitbucketcloud.go index 1054d5fb..90628fca 100644 --- a/vcsclient/bitbucketcloud.go +++ b/vcsclient/bitbucketcloud.go @@ -243,6 +243,9 @@ func (client *BitbucketCloudClient) DownloadRepository(ctx context.Context, owne if err != nil { return err } + if err = vcsutils.CheckResponseStatusWithBody(response, http.StatusOK); err != nil { + return err + } client.logger.Info(repository, "downloaded successfully, starting with repository extraction") err = vcsutils.Untar(localPath, response.Body, true) if err != nil { diff --git a/vcsclient/github.go b/vcsclient/github.go index c25f1f63..ba1aadb6 100644 --- a/vcsclient/github.go +++ b/vcsclient/github.go @@ -210,6 +210,9 @@ func (client *GitHubClient) DownloadRepository(ctx context.Context, owner, repos return err } defer func() { _ = resp.Body.Close() }() + if err = vcsutils.CheckResponseStatusWithBody(resp, http.StatusOK); err != nil { + return err + } client.logger.Info(repository, "downloaded successfully, starting with repository extraction") err = vcsutils.Untar(localPath, resp.Body, true) if err != nil { diff --git a/vcsutils/utils.go b/vcsutils/utils.go index 5dc05a5b..5dc7c69c 100644 --- a/vcsutils/utils.go +++ b/vcsutils/utils.go @@ -5,6 +5,7 @@ import ( "archive/zip" "bytes" "compress/gzip" + "encoding/json" "fmt" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" @@ -16,8 +17,6 @@ import ( "strings" ) -var ErrStatusCode = "invalid status code. expected %d and received %d" - // CreateToken create a random UUID func CreateToken() string { return uuid.New().String() @@ -235,6 +234,40 @@ func unzipFile(f *zip.File, destination string) (err error) { return safeCopy(destinationFile, zippedFile) } +func CheckResponseStatusWithBody(resp *http.Response, expectedStatusCodes ...int) error { + for _, statusCode := range expectedStatusCodes { + if statusCode == resp.StatusCode { + return nil + } + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + return GenerateResponseError(resp.Status, generateErrorString(body)) +} + +func GenerateResponseError(status, body string) error { + responseErrString := "server response: " + status + if body != "" { + responseErrString = responseErrString + "\n" + body + } + return fmt.Errorf(responseErrString) +} + +func generateErrorString(bodyArray []byte) string { + var content bytes.Buffer + if len(bodyArray) > 0 { + if err := json.Indent(&content, bodyArray, "", " "); err != nil { + return string(bodyArray) + } + return content.String() + } + return "" +} + // CreateDotGitFolderWithRemote creates a .git folder inside path with remote details of remoteName and remoteUrl func CreateDotGitFolderWithRemote(path, remoteName, remoteUrl string) error { repo, err := git.PlainInit(path, false) diff --git a/vcsutils/utils_test.go b/vcsutils/utils_test.go index ad1a4c55..a219e609 100644 --- a/vcsutils/utils_test.go +++ b/vcsutils/utils_test.go @@ -150,6 +150,25 @@ func TestGetZeroValue(t *testing.T) { assert.Equal(t, 0.0, GetZeroValue[float64]()) } +func TestGenerateResponseError(t *testing.T) { + status := "404" + emptyBodyErr := GenerateResponseError(status, "") + assert.Error(t, emptyBodyErr) + assert.Equal(t, "server response: 404", emptyBodyErr.Error()) + err := GenerateResponseError(status, "error") + assert.Error(t, err) + assert.Equal(t, "server response: 404\nerror", err.Error()) +} + +func TestCheckResponseStatusWithBody(t *testing.T) { + expectedStatusCode := 200 + resp := &http.Response{ + Status: "200", + StatusCode: 200, + } + assert.NoError(t, CheckResponseStatusWithBody(resp, expectedStatusCode)) +} + func TestCreateDotGitFolderWithRemote(t *testing.T) { dir1, err := os.MkdirTemp("", "tmp") assert.NoError(t, err)