|
| 1 | +package dcos |
| 2 | + |
| 3 | +import ( |
| 4 | + "crypto/tls" |
| 5 | + "fmt" |
| 6 | + "net" |
| 7 | + "net/http" |
| 8 | + "time" |
| 9 | +) |
| 10 | + |
| 11 | +const ( |
| 12 | + // Set a 10 seconds timeout for the connection to be established. |
| 13 | + DefaultHTTPClientDialContextTimeout = 10 * time.Second |
| 14 | + // Set it to 10 seconds as well for the TLS handshake when using HTTPS. |
| 15 | + DefaultHTTPClientTLSHandshakeTimeout = 10 * time.Second |
| 16 | + // The client will be dealing with a single host (the one in baseURL), |
| 17 | + // set max idle connections to 30 regardless of the host. |
| 18 | + DefaultHTTPClientMaxIdleConns = 30 |
| 19 | + DefaultHTTPClientMaxIdleConnsPerHost = 30 |
| 20 | +) |
| 21 | + |
| 22 | +// DefaultTransport is a http.RoundTripper that adds authentication based on Config |
| 23 | +type DefaultTransport struct { |
| 24 | + Config *Config |
| 25 | + Base http.RoundTripper |
| 26 | +} |
| 27 | + |
| 28 | +func (t *DefaultTransport) base() http.RoundTripper { |
| 29 | + if t.Base != nil { |
| 30 | + return t.Base |
| 31 | + } |
| 32 | + return http.DefaultTransport |
| 33 | +} |
| 34 | + |
| 35 | +// RoundTrip authorizes requests to DC/OS by adding dcos_acs_token to Authorization header |
| 36 | +func (t *DefaultTransport) RoundTrip(req *http.Request) (*http.Response, error) { |
| 37 | + // meet the requirements of RoundTripper and only modify a copy |
| 38 | + req2 := cloneRequest(req) |
| 39 | + req2.Header.Set("Authorization", fmt.Sprintf("token=%s", t.Config.ACSToken())) |
| 40 | + |
| 41 | + return t.base().RoundTrip(req2) |
| 42 | +} |
| 43 | + |
| 44 | +func cloneRequest(req *http.Request) *http.Request { |
| 45 | + req2 := new(http.Request) |
| 46 | + *req2 = *req |
| 47 | + |
| 48 | + // until now we only clone headers as we only modify those. |
| 49 | + req2.Header = make(http.Header, len(req.Header)) |
| 50 | + for k, s := range req.Header { |
| 51 | + req2.Header[k] = append([]string(nil), s...) |
| 52 | + } |
| 53 | + |
| 54 | + return req2 |
| 55 | +} |
| 56 | + |
| 57 | +// NewHTTPClient provides a http.Client able to communicate to dcos in an authenticated way |
| 58 | +func NewHTTPClient(config *Config) *http.Client { |
| 59 | + client := &http.Client{} |
| 60 | + client.Transport = &http.Transport{ |
| 61 | + |
| 62 | + // Allow http_proxy, https_proxy, and no_proxy. |
| 63 | + Proxy: http.ProxyFromEnvironment, |
| 64 | + |
| 65 | + DialContext: (&net.Dialer{ |
| 66 | + Timeout: DefaultHTTPClientDialContextTimeout, |
| 67 | + }).DialContext, |
| 68 | + |
| 69 | + TLSHandshakeTimeout: DefaultHTTPClientTLSHandshakeTimeout, |
| 70 | + TLSClientConfig: &tls.Config{ |
| 71 | + InsecureSkipVerify: config.TLS().Insecure, |
| 72 | + RootCAs: config.TLS().RootCAs, |
| 73 | + }, |
| 74 | + |
| 75 | + MaxIdleConns: DefaultHTTPClientMaxIdleConns, |
| 76 | + MaxIdleConnsPerHost: DefaultHTTPClientMaxIdleConnsPerHost, |
| 77 | + } |
| 78 | + |
| 79 | + return AddTransportHTTPClient(client, config) |
| 80 | +} |
| 81 | + |
| 82 | +// AddTransportHTTPClient adds dcos.DefaultTransport to http.Client to add dcos authentication |
| 83 | +func AddTransportHTTPClient(client *http.Client, config *Config) *http.Client { |
| 84 | + transport := DefaultTransport{ |
| 85 | + Config: config, |
| 86 | + Base: client.Transport, |
| 87 | + } |
| 88 | + |
| 89 | + client.Transport = &transport |
| 90 | + |
| 91 | + return client |
| 92 | +} |
0 commit comments