Skip to content

Commit 970c6c7

Browse files
committed
refactor: make CopyBody exported from rest package
1 parent f5003ec commit 970c6c7

File tree

4 files changed

+59
-65
lines changed

4 files changed

+59
-65
lines changed

client/rest/client.go

+1-15
Original file line numberDiff line numberDiff line change
@@ -218,23 +218,9 @@ func (s *restClient) Send(req *http.Request) (*http.Response, error) {
218218
return s.send(req)
219219
}
220220

221-
func copyBody(req *http.Request) ([]byte, error) {
222-
var (
223-
body []byte
224-
err error
225-
)
226-
if req.Body != nil {
227-
body, err = io.ReadAll(req.Body)
228-
if body != nil {
229-
req.Body = io.NopCloser(bytes.NewBuffer(body))
230-
}
231-
}
232-
return body, err
233-
}
234-
235221
func (s *restClient) send(req *http.Request) (*http.Response, error) {
236222
// copy the bytes in case we need to retry the request
237-
if body, err := copyBody(req); err != nil {
223+
if body, err := CopyBody(req); err != nil {
238224
return nil, err
239225
} else {
240226
var (

client/rest/client_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ func TestClosedConnection(t *testing.T) {
5050

5151
// make request in separate goroutine so its not blocking after we validated the retry
5252
go func() {
53-
client.Authenticate() // Authenticate()because it uses the internal client.send method.
54-
// the above request should block this from running, however if it does then the test fails.
53+
client.Authenticate() // Authenticate() because it uses the internal client.send method.
54+
// the above request should block the request from completing, however if it does then the test fails.
5555
requestCompleted = true
5656
}()
5757

client/rest/utils.go

+18-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package rest
1919

2020
import (
21+
"bytes"
2122
"crypto/sha1"
2223
"crypto/x509"
2324
"encoding/base64"
@@ -26,6 +27,7 @@ import (
2627
"fmt"
2728
"io"
2829
"math"
30+
"net/http"
2931
"strings"
3032
"time"
3133

@@ -122,10 +124,9 @@ func x5t(certificate string) (string, error) {
122124
}
123125
}
124126

125-
var ClosedConnectionMsg = "An existing connection was forcibly closed by the remote host."
126-
127127
func IsClosedConnectionErr(err error) bool {
128-
closedFromClient := strings.Contains(err.Error(), ClosedConnectionMsg)
128+
var closedConnectionMsg = "An existing connection was forcibly closed by the remote host."
129+
closedFromClient := strings.Contains(err.Error(), closedConnectionMsg)
129130
// Mocking http.Do would require a larger refactor,
130131
// so closedFromTestCase is used for testing only.
131132
closedFromTestCase := strings.HasSuffix(err.Error(), ": EOF")
@@ -136,3 +137,17 @@ func ExponentialBackoff(retry int, maxRetries int) {
136137
backoff := math.Pow(5, float64(retry+1))
137138
time.Sleep(time.Second * time.Duration(backoff))
138139
}
140+
141+
func CopyBody(req *http.Request) ([]byte, error) {
142+
var (
143+
body []byte
144+
err error
145+
)
146+
if req.Body != nil {
147+
body, err = io.ReadAll(req.Body)
148+
if body != nil {
149+
req.Body = io.NopCloser(bytes.NewBuffer(body))
150+
}
151+
}
152+
return body, err
153+
}

cmd/start.go

+38-45
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import (
3131
"os/signal"
3232
"runtime"
3333
"sort"
34-
"strings"
3534
"sync"
3635
"sync/atomic"
3736
"time"
@@ -229,8 +228,8 @@ func ingest(ctx context.Context, bheUrl url.URL, bheClient *http.Client, in <-ch
229228
log.Error(err, unrecoverableErrMsg)
230229
return true
231230
} else if response.StatusCode == http.StatusGatewayTimeout || response.StatusCode == http.StatusServiceUnavailable || response.StatusCode == http.StatusBadGateway {
232-
serverError := fmt.Errorf("received server error %d while requesting %v", response.StatusCode, endpoint)
233-
log.Error(serverError, "attempt %d/%d", retry+1, maxRetries)
231+
serverError := fmt.Errorf("received server error %d while requesting %v;", response.StatusCode, endpoint)
232+
log.Error(serverError, "attempt %d/%d; trying again", retry+1, maxRetries)
234233

235234
rest.ExponentialBackoff(retry, maxRetries)
236235

@@ -266,61 +265,55 @@ func ingest(ctx context.Context, bheUrl url.URL, bheClient *http.Client, in <-ch
266265
// TODO: create/use a proper bloodhound client
267266
func do(bheClient *http.Client, req *http.Request) (*http.Response, error) {
268267
var (
269-
body []byte
270268
res *http.Response
271269
err error
272270
maxRetries = 3
273271
)
274272

275273
// copy the bytes in case we need to retry the request
276-
if req.Body != nil {
277-
if body, err = io.ReadAll(req.Body); err != nil {
278-
return nil, err
279-
}
280-
if body != nil {
281-
req.Body = io.NopCloser(bytes.NewBuffer(body))
282-
}
283-
}
274+
if body, err := rest.CopyBody(req); err != nil {
275+
return nil, err
276+
} else {
277+
for retry := 0; retry < maxRetries; retry++ {
278+
// Reusing http.Request requires rewinding the request body
279+
// back to a working state
280+
if body != nil && retry > 0 {
281+
req.Body = io.NopCloser(bytes.NewBuffer(body))
282+
}
284283

285-
for retry := 0; retry < maxRetries; retry++ {
286-
// Reusing http.Request requires rewinding the request body
287-
// back to a working state
288-
if body != nil && retry > 0 {
289-
req.Body = io.NopCloser(bytes.NewBuffer(body))
290-
}
284+
if res, err = bheClient.Do(req); err != nil {
285+
if rest.IsClosedConnectionErr(err) {
286+
// try again on force closed connections
287+
log.Error(err, "remote host force closed connection while requesting %s; attempt %d/%d; trying again\n", req.URL, retry+1, maxRetries)
288+
rest.ExponentialBackoff(retry, maxRetries)
289+
continue
290+
}
291+
// normal client error, dont attempt again
292+
return nil, err
293+
} else if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest {
294+
if res.StatusCode >= http.StatusInternalServerError {
295+
// Internal server error, backoff and try again.
296+
serverError := fmt.Errorf("received server error %d while requesting %v", res.StatusCode, req.URL)
297+
log.Error(serverError, "attempt %d/%d", retry+1, maxRetries)
291298

292-
if res, err = bheClient.Do(req); err != nil {
293-
if strings.Contains(err.Error(), rest.ClosedConnectionMsg) || strings.HasSuffix(err.Error(), ": EOF") {
294-
// try again on force closed connections
295-
log.Error(err, "remote host force closed connection while requesting %s; attempt %d/%d; trying again\n", req.URL, retry+1, maxRetries)
296-
rest.ExponentialBackoff(retry, maxRetries)
297-
continue
298-
}
299-
// normal client error, dont attempt again
300-
return nil, err
301-
} else if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest {
302-
if res.StatusCode >= http.StatusInternalServerError {
303-
// Internal server error, backoff and try again.
304-
serverError := fmt.Errorf("received server error %d while requesting %v", res.StatusCode, req.URL)
305-
log.Error(serverError, "attempt %d/%d", retry+1, maxRetries)
306-
307-
rest.ExponentialBackoff(retry, maxRetries)
308-
continue
309-
}
310-
// bad request we do not need to retry
311-
var body json.RawMessage
312-
defer res.Body.Close()
313-
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
314-
return nil, fmt.Errorf("received unexpected response code from %v: %s; failure reading response body", req.URL, res.Status)
299+
rest.ExponentialBackoff(retry, maxRetries)
300+
continue
301+
}
302+
// bad request we do not need to retry
303+
var body json.RawMessage
304+
defer res.Body.Close()
305+
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
306+
return nil, fmt.Errorf("received unexpected response code from %v: %s; failure reading response body", req.URL, res.Status)
307+
} else {
308+
return nil, fmt.Errorf("received unexpected response code from %v: %s %s", req.URL, res.Status, body)
309+
}
315310
} else {
316-
return nil, fmt.Errorf("received unexpected response code from %v: %s %s", req.URL, res.Status, body)
311+
return res, nil
317312
}
318-
} else {
319-
return res, nil
320313
}
321314
}
322315

323-
return nil, fmt.Errorf("unable to complete request | url=%s | attempts=%d | ERR=%w", req.URL, maxRetries, err)
316+
return nil, fmt.Errorf("unable to complete request to url=%s; attempts=%d; ERR=%w", req.URL, maxRetries, err)
324317
}
325318

326319
type basicResponse[T any] struct {

0 commit comments

Comments
 (0)