forked from hashicorp/faas-nomad
/
proxy_client.go
102 lines (83 loc) · 2.46 KB
/
proxy_client.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
package handlers
import (
"bytes"
"io/ioutil"
"log"
"math/rand"
"net"
"net/http"
"time"
"github.com/gorilla/mux"
hclog "github.com/hashicorp/go-hclog"
)
// ProxyClient defines the interface for a client which calls faas functions
type ProxyClient interface {
GetFunctionName(*http.Request) string
CallAndReturnResponse(address string, body []byte, headers http.Header) ([]byte, http.Header, error)
}
// HTTPProxyClient allows the calling of functions
type HTTPProxyClient struct {
proxyClient *http.Client
logger hclog.Logger
}
// MakeProxyClient creates a new HTTPProxyClient
func MakeProxyClient(timeout time.Duration, l hclog.Logger) *HTTPProxyClient {
proxyClient := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: timeout,
KeepAlive: 0,
}).DialContext,
MaxIdleConns: 200,
DisableKeepAlives: true,
IdleConnTimeout: 120 * time.Millisecond,
ExpectContinueTimeout: 1500 * time.Millisecond,
},
}
return &HTTPProxyClient{
proxyClient: proxyClient,
logger: l,
}
}
// GetFunctionName returns the name of the function from the request vars
func (pc *HTTPProxyClient) GetFunctionName(r *http.Request) string {
vars := mux.Vars(r)
return vars["name"]
}
// CallAndReturnResponse calls the function and returns the response
func (pc *HTTPProxyClient) CallAndReturnResponse(address string, body []byte, headers http.Header) (
[]byte, http.Header, error) {
defer func(when time.Time) {
seconds := time.Since(when).Seconds()
pc.logger.Info("Execution time", "address", address, "duration(s)", seconds)
}(time.Now())
pc.logger.Info("Trying to call:", "address", address)
request, _ := http.NewRequest("POST", address, bytes.NewReader(body))
copyHeaders(&request.Header, &headers)
defer request.Body.Close()
response, err := pc.proxyClient.Do(request)
if err != nil {
log.Println(err.Error())
return nil, nil, err
}
respBody, err := ioutil.ReadAll(response.Body)
if err != nil {
pc.logger.Error("Error reading body", "error", err)
return nil, nil, err
}
response.Body.Close()
pc.logger.Info("Finished")
return respBody, response.Header, nil
}
func copyHeaders(destination *http.Header, source *http.Header) {
for k, vv := range *source {
vvClone := make([]string, len(vv))
copy(vvClone, vv)
(*destination)[k] = vvClone
}
}
func randomInt(min, max int) int {
rand.Seed(time.Now().Unix())
return rand.Intn(max-min) + min
}