diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index a72a9337a..9e4fb552f 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -17,6 +17,7 @@ package getter import ( "bytes" + "compress/gzip" "context" "crypto/tls" "fmt" @@ -24,6 +25,7 @@ import ( "log/slog" "net/http" "net/url" + "strings" "sync" "helm.sh/helm/v4/internal/tlsutil" @@ -58,6 +60,10 @@ func (g *HTTPGetter) get(href string, opts getterOptions) (*bytes.Buffer, error) if opts.acceptHeader != "" { req.Header.Set("Accept", opts.acceptHeader) } + acceptCompressedIndex := strings.HasSuffix(req.URL.Path, "/index.yaml") + if acceptCompressedIndex { + req.Header.Set("Accept-Encoding", "gzip") + } req.Header.Set("User-Agent", version.GetUserAgent()) if opts.userAgent != "" { @@ -101,7 +107,16 @@ func (g *HTTPGetter) get(href string, opts getterOptions) (*bytes.Buffer, error) } buf := bytes.NewBuffer(nil) - _, err = io.Copy(buf, resp.Body) + body := io.Reader(resp.Body) + if acceptCompressedIndex && resp.Header.Get("Content-Encoding") == "gzip" { + gz, err := gzip.NewReader(resp.Body) + if err != nil { + return nil, err + } + defer gz.Close() + body = gz + } + _, err = io.Copy(buf, body) return buf, err } diff --git a/pkg/repo/v1/index_test.go b/pkg/repo/v1/index_test.go index 9b46065a8..de0b53d03 100644 --- a/pkg/repo/v1/index_test.go +++ b/pkg/repo/v1/index_test.go @@ -19,6 +19,7 @@ package repo import ( "bufio" "bytes" + "compress/gzip" "encoding/json" "errors" "net/http" @@ -289,6 +290,28 @@ func TestDownloadIndexFile(t *testing.T) { require.NoErrorf(t, err, "error reading charts file") verifyLocalChartsFile(t, b, i) }) + + t.Run("should accept gzip-compressed index responses", func(t *testing.T) { + fileBytes, err := os.ReadFile(testfile) + require.NoError(t, err) + srv, err := startLocalServerForTests(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "gzip", r.Header.Get("Accept-Encoding")) + w.Header().Set("Content-Encoding", "gzip") + gz := gzip.NewWriter(w) + _, _ = gz.Write(fileBytes) + _ = gz.Close() + })) + require.NoError(t, err) + defer srv.Close() + + r, err := NewChartRepository(&Entry{Name: testRepo, URL: srv.URL}, getter.All(&cli.EnvSettings{})) + require.NoError(t, err) + idx, err := r.DownloadIndexFile() + require.NoError(t, err) + i, err := LoadIndexFile(idx) + require.NoError(t, err) + verifyLocalIndex(t, i) + }) } func verifyLocalIndex(t *testing.T, i *IndexFile) {