1
15
16 package getter
17
18 import (
19 "fmt"
20 "io"
21 "net/http"
22 "net/http/httptest"
23 "net/url"
24 "os"
25 "path/filepath"
26 "strconv"
27 "strings"
28 "testing"
29 "time"
30
31 "github.com/pkg/errors"
32
33 "helm.sh/helm/v3/internal/tlsutil"
34 "helm.sh/helm/v3/internal/version"
35 "helm.sh/helm/v3/pkg/cli"
36 )
37
38 func TestHTTPGetter(t *testing.T) {
39 g, err := NewHTTPGetter(WithURL("http://example.com"))
40 if err != nil {
41 t.Fatal(err)
42 }
43
44 if _, ok := g.(*HTTPGetter); !ok {
45 t.Fatal("Expected NewHTTPGetter to produce an *HTTPGetter")
46 }
47
48 cd := "../../testdata"
49 join := filepath.Join
50 ca, pub, priv := join(cd, "rootca.crt"), join(cd, "crt.pem"), join(cd, "key.pem")
51 insecure := false
52 timeout := time.Second * 5
53 transport := &http.Transport{}
54
55
56 g, err = NewHTTPGetter(
57 WithBasicAuth("I", "Am"),
58 WithPassCredentialsAll(false),
59 WithUserAgent("Groot"),
60 WithTLSClientConfig(pub, priv, ca),
61 WithInsecureSkipVerifyTLS(insecure),
62 WithTimeout(timeout),
63 WithTransport(transport),
64 )
65 if err != nil {
66 t.Fatal(err)
67 }
68
69 hg, ok := g.(*HTTPGetter)
70 if !ok {
71 t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter")
72 }
73
74 if hg.opts.username != "I" {
75 t.Errorf("Expected NewHTTPGetter to contain %q as the username, got %q", "I", hg.opts.username)
76 }
77
78 if hg.opts.password != "Am" {
79 t.Errorf("Expected NewHTTPGetter to contain %q as the password, got %q", "Am", hg.opts.password)
80 }
81
82 if hg.opts.passCredentialsAll != false {
83 t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll)
84 }
85
86 if hg.opts.userAgent != "Groot" {
87 t.Errorf("Expected NewHTTPGetter to contain %q as the user agent, got %q", "Groot", hg.opts.userAgent)
88 }
89
90 if hg.opts.certFile != pub {
91 t.Errorf("Expected NewHTTPGetter to contain %q as the public key file, got %q", pub, hg.opts.certFile)
92 }
93
94 if hg.opts.keyFile != priv {
95 t.Errorf("Expected NewHTTPGetter to contain %q as the private key file, got %q", priv, hg.opts.keyFile)
96 }
97
98 if hg.opts.caFile != ca {
99 t.Errorf("Expected NewHTTPGetter to contain %q as the CA file, got %q", ca, hg.opts.caFile)
100 }
101
102 if hg.opts.insecureSkipVerifyTLS != insecure {
103 t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", false, hg.opts.insecureSkipVerifyTLS)
104 }
105
106 if hg.opts.timeout != timeout {
107 t.Errorf("Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout)
108 }
109
110 if hg.opts.transport != transport {
111 t.Errorf("Expected NewHTTPGetter to contain %p as Transport, got %p", transport, hg.opts.transport)
112 }
113
114
115 insecure = true
116
117 g, err = NewHTTPGetter(
118 WithInsecureSkipVerifyTLS(insecure),
119 )
120 if err != nil {
121 t.Fatal(err)
122 }
123
124 hg, ok = g.(*HTTPGetter)
125 if !ok {
126 t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter")
127 }
128
129 if hg.opts.insecureSkipVerifyTLS != insecure {
130 t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", insecure, hg.opts.insecureSkipVerifyTLS)
131 }
132
133
134 if hg.opts.passCredentialsAll != false {
135 t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll)
136 }
137
138
139 g, err = NewHTTPGetter(
140 WithBasicAuth("I", "Am"),
141 WithPassCredentialsAll(true),
142 )
143 if err != nil {
144 t.Fatal(err)
145 }
146
147 hg, ok = g.(*HTTPGetter)
148 if !ok {
149 t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter")
150 }
151 if hg.opts.passCredentialsAll != true {
152 t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", true, hg.opts.passCredentialsAll)
153 }
154 }
155
156 func TestDownload(t *testing.T) {
157 expect := "Call me Ishmael"
158 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
159 defaultUserAgent := version.GetUserAgent()
160 if r.UserAgent() != defaultUserAgent {
161 t.Errorf("Expected '%s', got '%s'", defaultUserAgent, r.UserAgent())
162 }
163 fmt.Fprint(w, expect)
164 }))
165 defer srv.Close()
166
167 g, err := All(cli.New()).ByScheme("http")
168 if err != nil {
169 t.Fatal(err)
170 }
171 got, err := g.Get(srv.URL, WithURL(srv.URL))
172 if err != nil {
173 t.Fatal(err)
174 }
175
176 if got.String() != expect {
177 t.Errorf("Expected %q, got %q", expect, got.String())
178 }
179
180
181 const expectedUserAgent = "I am Groot"
182 basicAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
183 username, password, ok := r.BasicAuth()
184 if !ok || username != "username" || password != "password" {
185 t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password)
186 }
187 if r.UserAgent() != expectedUserAgent {
188 t.Errorf("Expected '%s', got '%s'", expectedUserAgent, r.UserAgent())
189 }
190 fmt.Fprint(w, expect)
191 }))
192
193 defer basicAuthSrv.Close()
194
195 u, _ := url.ParseRequestURI(basicAuthSrv.URL)
196 httpgetter, err := NewHTTPGetter(
197 WithURL(u.String()),
198 WithBasicAuth("username", "password"),
199 WithPassCredentialsAll(false),
200 WithUserAgent(expectedUserAgent),
201 )
202 if err != nil {
203 t.Fatal(err)
204 }
205 got, err = httpgetter.Get(u.String())
206 if err != nil {
207 t.Fatal(err)
208 }
209
210 if got.String() != expect {
211 t.Errorf("Expected %q, got %q", expect, got.String())
212 }
213
214
215 crossAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
216 username, password, ok := r.BasicAuth()
217 if ok || username == "username" || password == "password" {
218 t.Errorf("Expected request to not include but got '%v', '%s', '%s'", ok, username, password)
219 }
220 fmt.Fprint(w, expect)
221 }))
222
223 defer crossAuthSrv.Close()
224
225 u, _ = url.ParseRequestURI(crossAuthSrv.URL)
226
227
228 u2, _ := url.ParseRequestURI(crossAuthSrv.URL)
229 host := strings.Split(u2.Host, ":")
230 host[0] = host[0] + "a"
231 u2.Host = strings.Join(host, ":")
232 httpgetter, err = NewHTTPGetter(
233 WithURL(u2.String()),
234 WithBasicAuth("username", "password"),
235 WithPassCredentialsAll(false),
236 )
237 if err != nil {
238 t.Fatal(err)
239 }
240 got, err = httpgetter.Get(u.String())
241 if err != nil {
242 t.Fatal(err)
243 }
244
245 if got.String() != expect {
246 t.Errorf("Expected %q, got %q", expect, got.String())
247 }
248
249
250 crossAuthSrv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
251 username, password, ok := r.BasicAuth()
252 if !ok || username != "username" || password != "password" {
253 t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password)
254 }
255 fmt.Fprint(w, expect)
256 }))
257
258 defer crossAuthSrv.Close()
259
260 u, _ = url.ParseRequestURI(crossAuthSrv.URL)
261
262
263 u2, _ = url.ParseRequestURI(crossAuthSrv.URL)
264 host = strings.Split(u2.Host, ":")
265 host[0] = host[0] + "a"
266 u2.Host = strings.Join(host, ":")
267 httpgetter, err = NewHTTPGetter(
268 WithURL(u2.String()),
269 WithBasicAuth("username", "password"),
270 WithPassCredentialsAll(true),
271 )
272 if err != nil {
273 t.Fatal(err)
274 }
275 got, err = httpgetter.Get(u.String())
276 if err != nil {
277 t.Fatal(err)
278 }
279
280 if got.String() != expect {
281 t.Errorf("Expected %q, got %q", expect, got.String())
282 }
283 }
284
285 func TestDownloadTLS(t *testing.T) {
286 cd := "../../testdata"
287 ca, pub, priv := filepath.Join(cd, "rootca.crt"), filepath.Join(cd, "crt.pem"), filepath.Join(cd, "key.pem")
288 insecureSkipTLSverify := false
289
290 tlsSrv := httptest.NewUnstartedServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}))
291 tlsConf, err := tlsutil.NewClientTLS(pub, priv, ca, insecureSkipTLSverify)
292 if err != nil {
293 t.Fatal(errors.Wrap(err, "can't create TLS config for client"))
294 }
295 tlsConf.ServerName = "helm.sh"
296 tlsSrv.TLS = tlsConf
297 tlsSrv.StartTLS()
298 defer tlsSrv.Close()
299
300 u, _ := url.ParseRequestURI(tlsSrv.URL)
301 g, err := NewHTTPGetter(
302 WithURL(u.String()),
303 WithTLSClientConfig(pub, priv, ca),
304 )
305 if err != nil {
306 t.Fatal(err)
307 }
308
309 if _, err := g.Get(u.String()); err != nil {
310 t.Error(err)
311 }
312
313
314 g, err = NewHTTPGetter()
315 if err != nil {
316 t.Fatal(err)
317 }
318
319 if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)); err != nil {
320 t.Error(err)
321 }
322
323
324 g, err = NewHTTPGetter()
325 if err != nil {
326 t.Fatal(err)
327 }
328
329 if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca)); err != nil {
330 t.Error(err)
331 }
332 }
333
334 func TestDownloadInsecureSkipTLSVerify(t *testing.T) {
335 ts := httptest.NewTLSServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}))
336 defer ts.Close()
337
338 u, _ := url.ParseRequestURI(ts.URL)
339
340
341 g, err := NewHTTPGetter(
342 WithURL(u.String()),
343 )
344 if err != nil {
345 t.Error(err)
346 }
347
348 if _, err := g.Get(u.String()); err == nil {
349 t.Errorf("Expected Getter to throw an error, got %s", err)
350 }
351
352
353 g, err = NewHTTPGetter(
354 WithURL(u.String()),
355 WithInsecureSkipVerifyTLS(true),
356 )
357 if err != nil {
358 t.Error(err)
359 }
360 if _, err = g.Get(u.String()); err != nil {
361 t.Error(err)
362 }
363
364 }
365
366 func TestHTTPGetterTarDownload(t *testing.T) {
367 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
368 f, _ := os.Open("testdata/empty-0.0.1.tgz")
369 defer f.Close()
370
371 b := make([]byte, 512)
372 f.Read(b)
373
374 FileStat, _ := f.Stat()
375 FileSize := strconv.FormatInt(FileStat.Size(), 10)
376
377
378 w.Header().Set("Content-Type", "application/x-tar")
379 w.Header().Set("Content-Encoding", "gzip")
380 w.Header().Set("Content-Length", FileSize)
381
382 f.Seek(0, 0)
383 io.Copy(w, f)
384 }))
385
386 defer srv.Close()
387
388 g, err := NewHTTPGetter(WithURL(srv.URL))
389 if err != nil {
390 t.Fatal(err)
391 }
392
393 data, _ := g.Get(srv.URL)
394 mimeType := http.DetectContentType(data.Bytes())
395
396 expectedMimeType := "application/x-gzip"
397 if mimeType != expectedMimeType {
398 t.Fatalf("Expected response with MIME type %s, but got %s", expectedMimeType, mimeType)
399 }
400 }
401
402 func TestHttpClientInsecureSkipVerify(t *testing.T) {
403 g := HTTPGetter{}
404 g.opts.url = "https://localhost"
405 verifyInsecureSkipVerify(t, &g, "Blank HTTPGetter", false)
406
407 g = HTTPGetter{}
408 g.opts.url = "https://localhost"
409 g.opts.caFile = "testdata/ca.crt"
410 verifyInsecureSkipVerify(t, &g, "HTTPGetter with ca file", false)
411
412 g = HTTPGetter{}
413 g.opts.url = "https://localhost"
414 g.opts.insecureSkipVerifyTLS = true
415 verifyInsecureSkipVerify(t, &g, "HTTPGetter with skip cert verification only", true)
416
417 g = HTTPGetter{}
418 g.opts.url = "https://localhost"
419 g.opts.certFile = "testdata/client.crt"
420 g.opts.keyFile = "testdata/client.key"
421 g.opts.insecureSkipVerifyTLS = true
422 transport := verifyInsecureSkipVerify(t, &g, "HTTPGetter with 2 way ssl", true)
423 if len(transport.TLSClientConfig.Certificates) <= 0 {
424 t.Fatal("transport.TLSClientConfig.Certificates is not present")
425 }
426 if transport.TLSClientConfig.ServerName == "" {
427 t.Fatal("TLSClientConfig.ServerName is blank")
428 }
429 }
430
431 func verifyInsecureSkipVerify(t *testing.T, g *HTTPGetter, caseName string, expectedValue bool) *http.Transport {
432 returnVal, err := g.httpClient()
433
434 if err != nil {
435 t.Fatal(err)
436 }
437
438 if returnVal == nil {
439 t.Fatalf("Expected non nil value for http client")
440 }
441 transport := (returnVal.Transport).(*http.Transport)
442 gotValue := false
443 if transport.TLSClientConfig != nil {
444 gotValue = transport.TLSClientConfig.InsecureSkipVerify
445 }
446 if gotValue != expectedValue {
447 t.Fatalf("Case Name = %s\nInsecureSkipVerify did not come as expected. Expected = %t; Got = %v",
448 caseName, expectedValue, gotValue)
449 }
450 return transport
451 }
452
453 func TestDefaultHTTPTransportReuse(t *testing.T) {
454 g := HTTPGetter{}
455
456 httpClient1, err := g.httpClient()
457
458 if err != nil {
459 t.Fatal(err)
460 }
461
462 if httpClient1 == nil {
463 t.Fatalf("Expected non nil value for http client")
464 }
465
466 transport1 := (httpClient1.Transport).(*http.Transport)
467
468 httpClient2, err := g.httpClient()
469
470 if err != nil {
471 t.Fatal(err)
472 }
473
474 if httpClient2 == nil {
475 t.Fatalf("Expected non nil value for http client")
476 }
477
478 transport2 := (httpClient2.Transport).(*http.Transport)
479
480 if transport1 != transport2 {
481 t.Fatalf("Expected default transport to be reused")
482 }
483 }
484
485 func TestHTTPTransportOption(t *testing.T) {
486 transport := &http.Transport{}
487
488 g := HTTPGetter{}
489 g.opts.transport = transport
490 httpClient1, err := g.httpClient()
491
492 if err != nil {
493 t.Fatal(err)
494 }
495
496 if httpClient1 == nil {
497 t.Fatalf("Expected non nil value for http client")
498 }
499
500 transport1 := (httpClient1.Transport).(*http.Transport)
501
502 if transport1 != transport {
503 t.Fatalf("Expected transport option to be applied")
504 }
505
506 httpClient2, err := g.httpClient()
507
508 if err != nil {
509 t.Fatal(err)
510 }
511
512 if httpClient2 == nil {
513 t.Fatalf("Expected non nil value for http client")
514 }
515
516 transport2 := (httpClient2.Transport).(*http.Transport)
517
518 if transport1 != transport2 {
519 t.Fatalf("Expected applied transport to be reused")
520 }
521
522 g = HTTPGetter{}
523 g.opts.url = "https://localhost"
524 g.opts.certFile = "testdata/client.crt"
525 g.opts.keyFile = "testdata/client.key"
526 g.opts.insecureSkipVerifyTLS = true
527 g.opts.transport = transport
528 usedTransport := verifyInsecureSkipVerify(t, &g, "HTTPGetter with 2 way ssl", false)
529 if usedTransport.TLSClientConfig != nil {
530 t.Fatal("transport.TLSClientConfig should not be set")
531 }
532 }
533
View as plain text