Issues (121)

gost/util.go (4 issues)

Severity
1
/* Vuls - Vulnerability Scanner
2
Copyright (C) 2016  Future Architect, Inc. Japan.
3
4
This program is free software: you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation, either version 3 of the License, or
7
(at your option) any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
package gost
19
20
import (
21
	"net/http"
22
	"time"
23
24
	"github.com/cenkalti/backoff"
25
	"github.com/future-architect/vuls/models"
26
	"github.com/future-architect/vuls/util"
27
	"github.com/parnurzeal/gorequest"
28
	"golang.org/x/xerrors"
29
)
30
31
type response struct {
32
	request request
33
	json    string
34
}
35
36
func getCvesViaHTTP(cveIDs []string, urlPrefix string) (
37
	responses []response, err error) {
38
	nReq := len(cveIDs)
39
	reqChan := make(chan request, nReq)
40
	resChan := make(chan response, nReq)
41
	errChan := make(chan error, nReq)
42
	defer close(reqChan)
43
	defer close(resChan)
44
	defer close(errChan)
45
46
	go func() {
47
		for _, cveID := range cveIDs {
48
			reqChan <- request{
49
				cveID: cveID,
50
			}
51
		}
52
	}()
53
54
	concurrency := 10
55
	tasks := util.GenWorkers(concurrency)
56
	for i := 0; i < nReq; i++ {
57
		tasks <- func() {
58
			select {
59
			case req := <-reqChan:
60
				url, err := util.URLPathJoin(
61
					urlPrefix,
62
					req.cveID,
63
				)
64
				if err != nil {
65
					errChan <- err
66
				} else {
67
					util.Log.Debugf("HTTP Request to %s", url)
68
					httpGet(url, req, resChan, errChan)
69
				}
70
			}
71
		}
72
	}
73
74
	timeout := time.After(2 * 60 * time.Second)
75
	var errs []error
76
	for i := 0; i < nReq; i++ {
77
		select {
78
		case res := <-resChan:
79
			responses = append(responses, res)
80
		case err := <-errChan:
81
			errs = append(errs, err)
82
		case <-timeout:
83
			return nil, xerrors.New("Timeout Fetching OVAL")
84
		}
85
	}
86
	if len(errs) != 0 {
87
		return nil, xerrors.Errorf("Failed to fetch OVAL. err: %w", errs)
0 ignored issues
show
unrecognized printf verb 'w'
Loading history...
88
	}
89
	return
90
}
91
92
type request struct {
93
	osMajorVersion string
94
	packName       string
95
	isSrcPack      bool
96
	cveID          string
97
}
98
99
func getAllUnfixedCvesViaHTTP(r *models.ScanResult, urlPrefix string) (
100
	responses []response, err error) {
101
102
	nReq := len(r.Packages) + len(r.SrcPackages)
103
	reqChan := make(chan request, nReq)
104
	resChan := make(chan response, nReq)
105
	errChan := make(chan error, nReq)
106
	defer close(reqChan)
107
	defer close(resChan)
108
	defer close(errChan)
109
110
	go func() {
111
		for _, pack := range r.Packages {
112
			reqChan <- request{
113
				osMajorVersion: major(r.Release),
114
				packName:       pack.Name,
115
				isSrcPack:      false,
116
			}
117
		}
118
		for _, pack := range r.SrcPackages {
119
			reqChan <- request{
120
				osMajorVersion: major(r.Release),
121
				packName:       pack.Name,
122
				isSrcPack:      true,
123
			}
124
		}
125
	}()
126
127
	concurrency := 10
128
	tasks := util.GenWorkers(concurrency)
129
	for i := 0; i < nReq; i++ {
130
		tasks <- func() {
131
			select {
132
			case req := <-reqChan:
133
				url, err := util.URLPathJoin(
134
					urlPrefix,
135
					req.packName,
136
					"unfixed-cves",
137
				)
138
				if err != nil {
139
					errChan <- err
140
				} else {
141
					util.Log.Debugf("HTTP Request to %s", url)
142
					httpGet(url, req, resChan, errChan)
143
				}
144
			}
145
		}
146
	}
147
148
	timeout := time.After(2 * 60 * time.Second)
149
	var errs []error
150
	for i := 0; i < nReq; i++ {
151
		select {
152
		case res := <-resChan:
153
			responses = append(responses, res)
154
		case err := <-errChan:
155
			errs = append(errs, err)
156
		case <-timeout:
157
			return nil, xerrors.New("Timeout Fetching OVAL")
158
		}
159
	}
160
	if len(errs) != 0 {
161
		return nil, xerrors.Errorf("Failed to fetch OVAL. err: %w", errs)
0 ignored issues
show
unrecognized printf verb 'w'
Loading history...
162
	}
163
	return
164
}
165
166
func httpGet(url string, req request, resChan chan<- response, errChan chan<- error) {
167
	var body string
168
	var errs []error
169
	var resp *http.Response
170
	count, retryMax := 0, 3
171
	f := func() (err error) {
172
		//  resp, body, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
173
		resp, body, errs = gorequest.New().Get(url).End()
174
		if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
175
			count++
176
			if count == retryMax {
177
				return nil
178
			}
179
			return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
0 ignored issues
show
unrecognized printf verb 'w'
Loading history...
180
		}
181
		return nil
182
	}
183
	notify := func(err error, t time.Duration) {
184
		util.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %s", t, err)
185
	}
186
	err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
187
	if err != nil {
188
		errChan <- xerrors.Errorf("HTTP Error %w", err)
0 ignored issues
show
unrecognized printf verb 'w'
Loading history...
189
		return
190
	}
191
	if count == retryMax {
192
		errChan <- xerrors.New("Retry count exceeded")
193
		return
194
	}
195
196
	resChan <- response{
197
		request: req,
198
		json:    body,
199
	}
200
}
201