Skip to content

Commit ccfdf6c

Browse files
fix(debian): make fault-tolerant HTTP downloads (#2674)
I noticed a recent spate of 503s in the error logging that may have benefited from this
1 parent 4a3d43c commit ccfdf6c

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
go.work
2+
go.work.sum
13
*.pyc
24
__pycache__/
35
.idea/

vulnfeeds/cmd/debian/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strconv"
1212

1313
"github.com/google/osv/vulnfeeds/cves"
14+
"github.com/google/osv/vulnfeeds/faulttolerant"
1415
"github.com/google/osv/vulnfeeds/utility"
1516
"github.com/google/osv/vulnfeeds/vulns"
1617
)
@@ -54,7 +55,7 @@ func main() {
5455
// getDebianReleaseMap gets the Debian version number, excluding testing and experimental versions.
5556
func getDebianReleaseMap() (map[string]string, error) {
5657
releaseMap := make(map[string]string)
57-
res, err := http.Get(debianDistroInfoURL)
58+
res, err := faulttolerant.Get(debianDistroInfoURL)
5859
if err != nil {
5960
return releaseMap, err
6061
}
@@ -194,7 +195,7 @@ func writeToOutput(cvePkgInfos map[string][]vulns.PackageInfo) error {
194195

195196
// downloadDebianSecurityTracker download Debian json file
196197
func downloadDebianSecurityTracker() (DebianSecurityTrackerData, error) {
197-
res, err := http.Get(debianSecurityTrackerURL)
198+
res, err := faulttolerant.Get(debianSecurityTrackerURL)
198199
if err != nil {
199200
return nil, err
200201
}

vulnfeeds/faulttolerant/http.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package faulttolerant
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"time"
8+
9+
"github.com/sethvargo/go-retry"
10+
)
11+
12+
// Make a HTTP GET request for url and retry 3 times, with an exponential backoff.
13+
func Get(url string) (resp *http.Response, err error) {
14+
backoff := retry.NewExponential(1 * time.Second)
15+
if err := retry.Do(context.Background(), retry.WithMaxRetries(3, backoff), func(ctx context.Context) error {
16+
req, err := http.NewRequest("GET", url, nil)
17+
if err != nil {
18+
return err
19+
}
20+
21+
r, err := http.DefaultClient.Do(req)
22+
if err != nil {
23+
return err
24+
}
25+
26+
switch r.StatusCode / 100 {
27+
case 4:
28+
return fmt.Errorf("bad response: %v", r.StatusCode)
29+
case 5:
30+
return retry.RetryableError(fmt.Errorf("bad response: %v", r.StatusCode))
31+
default:
32+
resp = r
33+
return nil
34+
}
35+
}); err != nil {
36+
return nil, fmt.Errorf("fail: %q: %v", url, err)
37+
}
38+
return resp, err
39+
}
40+
41+
// Make a HTTP HEAD request for url and retry 3 times, with an exponential backoff.
42+
func Head(url string) (resp *http.Response, err error) {
43+
backoff := retry.NewExponential(1 * time.Second)
44+
if err := retry.Do(context.Background(), retry.WithMaxRetries(3, backoff), func(ctx context.Context) error {
45+
req, err := http.NewRequest("HEAD", url, nil)
46+
if err != nil {
47+
return err
48+
}
49+
50+
r, err := http.DefaultClient.Do(req)
51+
if err != nil {
52+
return err
53+
}
54+
defer r.Body.Close()
55+
56+
switch r.StatusCode / 100 {
57+
case 4:
58+
return fmt.Errorf("bad response: %v", r.StatusCode)
59+
case 5:
60+
return retry.RetryableError(fmt.Errorf("bad response: %v", r.StatusCode))
61+
default:
62+
resp = r
63+
return nil
64+
}
65+
}); err != nil {
66+
return nil, fmt.Errorf("fail: %q: %v", url, err)
67+
}
68+
return resp, err
69+
}

0 commit comments

Comments
 (0)