1
15
16 package getter
17
18 import (
19 "bytes"
20 "crypto/tls"
21 "io"
22 "net/http"
23 "net/url"
24 "sync"
25
26 "github.com/pkg/errors"
27
28 "helm.sh/helm/v3/internal/tlsutil"
29 "helm.sh/helm/v3/internal/urlutil"
30 "helm.sh/helm/v3/internal/version"
31 )
32
33
34 type HTTPGetter struct {
35 opts options
36 transport *http.Transport
37 once sync.Once
38 }
39
40
41 func (g *HTTPGetter) Get(href string, options ...Option) (*bytes.Buffer, error) {
42 for _, opt := range options {
43 opt(&g.opts)
44 }
45 return g.get(href)
46 }
47
48 func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
49
50
51 req, err := http.NewRequest(http.MethodGet, href, nil)
52 if err != nil {
53 return nil, err
54 }
55
56 req.Header.Set("User-Agent", version.GetUserAgent())
57 if g.opts.userAgent != "" {
58 req.Header.Set("User-Agent", g.opts.userAgent)
59 }
60
61
62
63 u1, err := url.Parse(g.opts.url)
64 if err != nil {
65 return nil, errors.Wrap(err, "Unable to parse getter URL")
66 }
67 u2, err := url.Parse(href)
68 if err != nil {
69 return nil, errors.Wrap(err, "Unable to parse URL getting from")
70 }
71
72
73
74
75 if g.opts.passCredentialsAll || (u1.Scheme == u2.Scheme && u1.Host == u2.Host) {
76 if g.opts.username != "" && g.opts.password != "" {
77 req.SetBasicAuth(g.opts.username, g.opts.password)
78 }
79 }
80
81 client, err := g.httpClient()
82 if err != nil {
83 return nil, err
84 }
85
86 resp, err := client.Do(req)
87 if err != nil {
88 return nil, err
89 }
90 defer resp.Body.Close()
91 if resp.StatusCode != http.StatusOK {
92 return nil, errors.Errorf("failed to fetch %s : %s", href, resp.Status)
93 }
94
95 buf := bytes.NewBuffer(nil)
96 _, err = io.Copy(buf, resp.Body)
97 return buf, err
98 }
99
100
101 func NewHTTPGetter(options ...Option) (Getter, error) {
102 var client HTTPGetter
103
104 for _, opt := range options {
105 opt(&client.opts)
106 }
107
108 return &client, nil
109 }
110
111 func (g *HTTPGetter) httpClient() (*http.Client, error) {
112 if g.opts.transport != nil {
113 return &http.Client{
114 Transport: g.opts.transport,
115 Timeout: g.opts.timeout,
116 }, nil
117 }
118
119 g.once.Do(func() {
120 g.transport = &http.Transport{
121 DisableCompression: true,
122 Proxy: http.ProxyFromEnvironment,
123 }
124 })
125
126 if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" || g.opts.insecureSkipVerifyTLS {
127 tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile, g.opts.insecureSkipVerifyTLS)
128 if err != nil {
129 return nil, errors.Wrap(err, "can't create TLS config for client")
130 }
131
132 sni, err := urlutil.ExtractHostname(g.opts.url)
133 if err != nil {
134 return nil, err
135 }
136 tlsConf.ServerName = sni
137
138 g.transport.TLSClientConfig = tlsConf
139 }
140
141 if g.opts.insecureSkipVerifyTLS {
142 if g.transport.TLSClientConfig == nil {
143 g.transport.TLSClientConfig = &tls.Config{
144 InsecureSkipVerify: true,
145 }
146 } else {
147 g.transport.TLSClientConfig.InsecureSkipVerify = true
148 }
149 }
150
151 client := &http.Client{
152 Transport: g.transport,
153 Timeout: g.opts.timeout,
154 }
155
156 return client, nil
157 }
158
View as plain text