Skip to content

Commit 19e46b5

Browse files
authored
fix: component download (#1394)
1 parent fa31ff2 commit 19e46b5

File tree

3 files changed

+52
-22
lines changed

3 files changed

+52
-22
lines changed

lwcomponent/component.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,14 @@ func (s State) Install(component *Component, version string) error {
257257
return err
258258
}
259259

260-
err = DownloadFile(path, artifact.URL, 5*time.Minute)
260+
// Slow S3 downloads
261+
downloadTimeout := 0 * time.Minute
262+
switch component.Name {
263+
case "sast":
264+
downloadTimeout = 5 * time.Minute
265+
}
266+
267+
err = DownloadFile(path, artifact.URL, time.Duration(downloadTimeout))
261268
if err != nil {
262269
return errors.Wrap(err, "unable to download component artifact")
263270
}

lwcomponent/http.go

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,37 +30,47 @@ const (
3030
defaultMaxRetry = 2
3131
)
3232

33-
// downloadFile is an internal helper that downloads a file to the provided file path
34-
func DownloadFile(filepath string, url string, timeout time.Duration) error {
35-
var (
36-
resp *http.Response
37-
err error
38-
_timeout time.Duration = timeout
39-
)
40-
41-
if _timeout == 0 {
42-
_timeout = defaultTimeout
33+
func DownloadFile(filepath string, url string, timeout time.Duration) (err error) {
34+
if timeout == 0 {
35+
timeout = defaultTimeout
4336
}
4437

45-
client := &http.Client{Timeout: _timeout}
38+
client := &http.Client{Timeout: timeout}
4639

47-
resp, err = client.Get(url)
40+
file, err := os.Create(filepath)
4841
if err != nil {
49-
for retry := 0; retry < defaultMaxRetry && os.IsTimeout(err); retry++ {
50-
resp, err = client.Get(url)
51-
}
42+
return err
43+
}
44+
defer file.Close()
45+
46+
err = downloadFile(client, url, file)
47+
48+
for retry := 0; retry < defaultMaxRetry && os.IsTimeout(err); retry++ {
49+
_, err = file.Seek(0, io.SeekStart)
5250
if err != nil {
5351
return err
5452
}
53+
54+
err = downloadFile(client, url, file)
5555
}
56-
defer resp.Body.Close()
5756

58-
out, err := os.Create(filepath)
57+
return
58+
}
59+
60+
// client.Get returns on receiving HTTP headers and we stream the HTTP data to the output file.
61+
// A timeout will interrupt io.Copy.
62+
func downloadFile(client *http.Client, url string, file *os.File) (err error) {
63+
var (
64+
resp *http.Response
65+
)
66+
67+
resp, err = client.Get(url)
5968
if err != nil {
6069
return err
6170
}
62-
defer out.Close()
71+
defer resp.Body.Close()
72+
73+
_, err = io.Copy(file, resp.Body)
6374

64-
_, err = io.Copy(out, resp.Body)
65-
return err
75+
return
6676
}

lwcomponent/http_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,22 @@ func TestDownloadFile(t *testing.T) {
4343
})
4444

4545
t.Run("timeout error", func(t *testing.T) {
46-
err = lwcomponent.DownloadFile(file.Name(), fmt.Sprintf("%s%s", server.URL, urlPath), 1*time.Microsecond)
46+
var (
47+
count int = 0
48+
)
49+
50+
mux.HandleFunc("/slow", func(w http.ResponseWriter, r *http.Request) {
51+
if assert.Equal(t, "GET", r.Method, "Get() should be a GET method") {
52+
count += 1
53+
time.Sleep(10 * time.Millisecond)
54+
fmt.Fprint(w, content)
55+
}
56+
})
57+
58+
err = lwcomponent.DownloadFile(file.Name(), fmt.Sprintf("%s%s", server.URL, "/slow"), 2*time.Millisecond)
4759
assert.NotNil(t, err)
4860
assert.True(t, os.IsTimeout(err))
61+
assert.Equal(t, 3, count)
4962
})
5063

5164
t.Run("non-timeout error", func(t *testing.T) {

0 commit comments

Comments
 (0)