From 5a3de5a2d003dabc97ecbdd311ca9b81e908632a Mon Sep 17 00:00:00 2001 From: Alvaro Romero Date: Tue, 26 Sep 2023 15:14:56 +0200 Subject: [PATCH] Check content-type before importing to warn against unexpected content imports This commit adds a check in the http-datasource format reader to trigger a warning when importing unexpected content-types. Signed-off-by: Alvaro Romero --- pkg/importer/http-datasource.go | 26 +++++++++++++++++++------- pkg/importer/http-datasource_test.go | 18 +++++++++--------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/pkg/importer/http-datasource.go b/pkg/importer/http-datasource.go index 10316147eb..fd98003d88 100644 --- a/pkg/importer/http-datasource.go +++ b/pkg/importer/http-datasource.go @@ -44,10 +44,12 @@ import ( ) const ( - tempFile = "tmpimage" - nbdkitPid = "/tmp/nbdkit.pid" - nbdkitSocket = "/tmp/nbdkit.sock" - defaultUserAgent = "cdi-golang-importer" + tempFile = "tmpimage" + nbdkitPid = "/tmp/nbdkit.pid" + nbdkitSocket = "/tmp/nbdkit.sock" + defaultUserAgent = "cdi-golang-importer" + httpContentType = "Content-Type" + httpContentLength = "Content-Length" ) // HTTPDataSource is the data provider for http(s) endpoints. @@ -96,7 +98,7 @@ func NewHTTPDataSource(endpoint, accessKey, secKey, certDir string, contentType return nil, errors.Wrap(err, "Error getting extra headers for HTTP client") } - httpReader, contentLength, brokenForQemuImg, err := createHTTPReader(ctx, ep, accessKey, secKey, certDir, extraHeaders, secretExtraHeaders) + httpReader, contentLength, brokenForQemuImg, err := createHTTPReader(ctx, ep, accessKey, secKey, certDir, extraHeaders, secretExtraHeaders, contentType) if err != nil { cancel() return nil, err @@ -294,7 +296,7 @@ func addExtraheaders(req *http.Request, extraHeaders []string) { req.Header.Add("User-Agent", defaultUserAgent) } -func createHTTPReader(ctx context.Context, ep *url.URL, accessKey, secKey, certDir string, extraHeaders, secretExtraHeaders []string) (io.ReadCloser, uint64, bool, error) { +func createHTTPReader(ctx context.Context, ep *url.URL, accessKey, secKey, certDir string, extraHeaders, secretExtraHeaders []string, contentType cdiv1.DataVolumeContentType) (io.ReadCloser, uint64, bool, error) { var brokenForQemuImg bool client, err := createHTTPClient(certDir) if err != nil { @@ -334,6 +336,16 @@ func createHTTPReader(ctx context.Context, ep *url.URL, accessKey, secKey, certD return nil, uint64(0), true, errors.Errorf("expected status code 200, got %d. Status: %s", resp.StatusCode, resp.Status) } + if contentType == cdiv1.DataVolumeKubeVirt { + // Check the content-type if we are expecting a KubeVirt img. + if val, ok := resp.Header[httpContentType]; ok { + if strings.HasPrefix(val[0], "text/") { + // We will continue with the import nonetheless, but content might be unexpected. + klog.Warningf("Unexpected content type '%s'. Content might not be a KubeVirt image.", val[0]) + } + } + } + acceptRanges, ok := resp.Header["Accept-Ranges"] if !ok || acceptRanges[0] == "none" { klog.V(2).Infof("Accept-Ranges isn't bytes, avoiding qemu-img") @@ -416,7 +428,7 @@ func getContentLength(client *http.Client, ep *url.URL, accessKey, secKey string func parseHTTPHeader(resp *http.Response) uint64 { var err error total := uint64(0) - if val, ok := resp.Header["Content-Length"]; ok { + if val, ok := resp.Header[httpContentLength]; ok { total, err = strconv.ParseUint(val[0], 10, 64) if err != nil { klog.Errorf("could not convert content length, got %v", err) diff --git a/pkg/importer/http-datasource_test.go b/pkg/importer/http-datasource_test.go index 36dbe1fc7a..379711b947 100644 --- a/pkg/importer/http-datasource_test.go +++ b/pkg/importer/http-datasource_test.go @@ -232,7 +232,7 @@ var _ = Describe("Http client", func() { var _ = Describe("Http reader", func() { It("should fail when passed an invalid cert directory", func() { - _, total, _, err := createHTTPReader(context.Background(), nil, "", "", "/invalid", nil, nil) + _, total, _, err := createHTTPReader(context.Background(), nil, "", "", "/invalid", nil, nil, cdiv1.DataVolumeKubeVirt) Expect(err).To(HaveOccurred()) Expect(uint64(0)).To(Equal(total)) }) @@ -249,7 +249,7 @@ var _ = Describe("Http reader", func() { defer ts.Close() ep, err := url.Parse(ts.URL) Expect(err).ToNot(HaveOccurred()) - r, total, _, err := createHTTPReader(context.Background(), ep, "user", "password", "", nil, nil) + r, total, _, err := createHTTPReader(context.Background(), ep, "user", "password", "", nil, nil, cdiv1.DataVolumeKubeVirt) Expect(err).ToNot(HaveOccurred()) Expect(uint64(25)).To(Equal(total)) err = r.Close() @@ -272,7 +272,7 @@ var _ = Describe("Http reader", func() { defer ts.Close() ep, err := url.Parse(ts.URL) Expect(err).ToNot(HaveOccurred()) - r, total, _, err := createHTTPReader(context.Background(), ep, "user", "password", "", nil, nil) + r, total, _, err := createHTTPReader(context.Background(), ep, "user", "password", "", nil, nil, cdiv1.DataVolumeKubeVirt) Expect(err).ToNot(HaveOccurred()) Expect(uint64(25)).To(Equal(total)) err = r.Close() @@ -294,7 +294,7 @@ var _ = Describe("Http reader", func() { defer ts.Close() ep, err := url.Parse(ts.URL) Expect(err).ToNot(HaveOccurred()) - r, total, brokenForQemuImg, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil) + r, total, brokenForQemuImg, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil, cdiv1.DataVolumeKubeVirt) Expect(brokenForQemuImg).To(BeFalse()) Expect(err).ToNot(HaveOccurred()) Expect(uint64(25)).To(Equal(total)) @@ -315,7 +315,7 @@ var _ = Describe("Http reader", func() { defer ts.Close() ep, err := url.Parse(ts.URL) Expect(err).ToNot(HaveOccurred()) - r, total, _, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil) + r, total, _, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil, cdiv1.DataVolumeKubeVirt) Expect(err).ToNot(HaveOccurred()) Expect(uint64(0)).To(Equal(total)) err = r.Close() @@ -339,7 +339,7 @@ var _ = Describe("Http reader", func() { defer ts.Close() ep, err := url.Parse(ts.URL) Expect(err).ToNot(HaveOccurred()) - r, total, brokenForQemuImg, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil) + r, total, brokenForQemuImg, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil, cdiv1.DataVolumeKubeVirt) Expect(brokenForQemuImg).To(BeTrue()) Expect(err).ToNot(HaveOccurred()) Expect(uint64(25)).To(Equal(total)) @@ -359,7 +359,7 @@ var _ = Describe("Http reader", func() { defer ts.Close() ep, err := url.Parse(ts.URL) Expect(err).ToNot(HaveOccurred()) - r, total, brokenForQemuImg, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil) + r, total, brokenForQemuImg, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil, cdiv1.DataVolumeKubeVirt) Expect(brokenForQemuImg).To(BeTrue()) Expect(err).ToNot(HaveOccurred()) Expect(uint64(25)).To(Equal(total)) @@ -374,7 +374,7 @@ var _ = Describe("Http reader", func() { defer ts.Close() ep, err := url.Parse(ts.URL) Expect(err).ToNot(HaveOccurred()) - _, total, _, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil) + _, total, _, err := createHTTPReader(context.Background(), ep, "", "", "", nil, nil, cdiv1.DataVolumeKubeVirt) Expect(err).To(HaveOccurred()) Expect(uint64(0)).To(Equal(total)) Expect("expected status code 200, got 500. Status: 500 Internal Server Error").To(Equal(err.Error())) @@ -391,7 +391,7 @@ var _ = Describe("Http reader", func() { defer ts.Close() ep, err := url.Parse(ts.URL) Expect(err).ToNot(HaveOccurred()) - r, total, _, err := createHTTPReader(context.Background(), ep, "", "", "", []string{"Extra-Header: 123"}, nil) + r, total, _, err := createHTTPReader(context.Background(), ep, "", "", "", []string{"Extra-Header: 123"}, nil, cdiv1.DataVolumeKubeVirt) Expect(err).ToNot(HaveOccurred()) Expect(uint64(0)).To(Equal(total)) err = r.Close()