/
common_http.go
107 lines (95 loc) · 3.04 KB
/
common_http.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package pipeline
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"time"
"github.com/pkg/errors"
"github.com/O1MaGnUmO1/erinaceus-vrf/core/logger"
clhttp "github.com/O1MaGnUmO1/erinaceus-vrf/core/utils/http"
)
func makeHTTPRequest(
ctx context.Context,
lggr logger.Logger,
method StringParam,
url URLParam,
reqHeaders []string,
requestData MapParam,
client *http.Client,
httpLimit int64,
) ([]byte, int, http.Header, time.Duration, error) {
var bodyReader io.Reader
if requestData != nil {
bodyBytes, err := json.Marshal(requestData)
if err != nil {
return nil, 0, nil, 0, errors.Wrap(err, "failed to encode request body as JSON")
}
bodyReader = bytes.NewReader(bodyBytes)
}
request, err := http.NewRequestWithContext(ctx, string(method), url.String(), bodyReader)
if err != nil {
return nil, 0, nil, 0, errors.Wrap(err, "failed to create http.Request")
}
request.Header.Set("Content-Type", "application/json")
if len(reqHeaders)%2 != 0 {
panic("headers must have an even number of elements")
}
for i := 0; i+1 < len(reqHeaders); i += 2 {
request.Header.Set(reqHeaders[i], reqHeaders[i+1])
}
httpRequest := clhttp.HTTPRequest{
Client: client,
Request: request,
Config: clhttp.HTTPRequestConfig{SizeLimit: httpLimit},
Logger: lggr.Named("HTTPRequest"),
}
start := time.Now()
responseBytes, statusCode, respHeaders, err := httpRequest.SendRequest()
if ctx.Err() != nil {
return nil, 0, nil, 0, errors.New("http request timed out or interrupted")
}
if err != nil {
return nil, 0, nil, 0, errors.Wrapf(err, "error making http request")
}
elapsed := time.Since(start) // TODO: return elapsed from utils/http
if statusCode >= 400 {
maybeErr := bestEffortExtractError(responseBytes)
return nil, statusCode, respHeaders, 0, errors.Errorf("got error from %s: (status code %v) %s", url.String(), statusCode, maybeErr)
}
return responseBytes, statusCode, respHeaders, elapsed, nil
}
type PossibleErrorResponses struct {
Error string `json:"error"`
ErrorMessage string `json:"errorMessage"`
}
func bestEffortExtractError(responseBytes []byte) string {
var resp PossibleErrorResponses
err := json.Unmarshal(responseBytes, &resp)
if err != nil {
return ""
}
if resp.Error != "" {
return resp.Error
} else if resp.ErrorMessage != "" {
return resp.ErrorMessage
}
return string(responseBytes)
}
func httpRequestCtx(ctx context.Context, t Task, cfg Config) (requestCtx context.Context, cancel context.CancelFunc) {
// Only set the default timeout if the task timeout is missing; task
// timeout if present will have already been set on the context at a higher
// level. If task timeout is explicitly set to zero, we must not override
// with the default http timeout here (since it has been explicitly
// disabled).
//
// DefaultHTTPTimeout is not used if set to 0.
if _, isSet := t.TaskTimeout(); !isSet && cfg.DefaultHTTPTimeout().Duration() > 0 {
requestCtx, cancel = context.WithTimeout(ctx, cfg.DefaultHTTPTimeout().Duration())
} else {
requestCtx = ctx
cancel = func() {}
}
return
}