diff --git a/internal/releasesjson/checksum_downloader.go b/internal/releasesjson/checksum_downloader.go index 4936dda..2b85ea3 100644 --- a/internal/releasesjson/checksum_downloader.go +++ b/internal/releasesjson/checksum_downloader.go @@ -121,12 +121,23 @@ func fileMapFromChecksums(checksums strings.Builder) (ChecksumFileMap, error) { return csMap, nil } -func compareChecksum(logger *log.Logger, r io.Reader, verifiedHashSum HashSum) error { +func compareChecksum(logger *log.Logger, r io.Reader, verifiedHashSum HashSum, filename string, expectedSize int64) error { h := sha256.New() - _, err := io.Copy(h, r) + + // This may take a while depending on network connection as the io.Reader + // is expected to be http.Response.Body which streams the bytes + // on demand over the network. + logger.Printf("copying %q (%d bytes) to calculate checksum", filename, expectedSize) + bytesCopied, err := io.Copy(h, r) if err != nil { return err } + logger.Printf("copied %d bytes of %q", bytesCopied, filename) + + if expectedSize != 0 && bytesCopied != int64(expectedSize) { + return fmt.Errorf("unexpected size (downloaded: %d, expected: %d)", + bytesCopied, expectedSize) + } calculatedSum := h.Sum(nil) if !bytes.Equal(calculatedSum, verifiedHashSum) { diff --git a/internal/releasesjson/downloader.go b/internal/releasesjson/downloader.go index 62ed6af..e9cd94e 100644 --- a/internal/releasesjson/downloader.go +++ b/internal/releasesjson/downloader.go @@ -12,7 +12,6 @@ import ( "os" "path/filepath" "runtime" - "strconv" "github.com/hashicorp/hc-install/internal/httpclient" ) @@ -95,14 +94,16 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, contentType, zipMimeTypes) } + expectedSize := resp.ContentLength + if d.VerifyChecksum { - d.Logger.Printf("calculating checksum of %q", pb.Filename) + d.Logger.Printf("verifying checksum of %q", pb.Filename) // provide extra reader to calculate & compare checksum var buf bytes.Buffer r := io.TeeReader(resp.Body, &buf) pkgReader = &buf - err := compareChecksum(d.Logger, r, verifiedChecksum) + err := compareChecksum(d.Logger, r, verifiedChecksum, pb.Filename, expectedSize) if err != nil { return err } @@ -114,21 +115,17 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, } defer pkgFile.Close() - d.Logger.Printf("copying downloaded file to %s", pkgFile.Name()) + d.Logger.Printf("copying %q (%d bytes) to %s", pb.Filename, expectedSize, pkgFile.Name()) + // Unless the bytes were already downloaded above for checksum verification + // this may take a while depending on network connection as the io.Reader + // is expected to be http.Response.Body which streams the bytes + // on demand over the network. bytesCopied, err := io.Copy(pkgFile, pkgReader) if err != nil { return err } d.Logger.Printf("copied %d bytes to %s", bytesCopied, pkgFile.Name()) - expectedSize := 0 - if length := resp.Header.Get("content-length"); length != "" { - var err error - expectedSize, err = strconv.Atoi(length) - if err != nil { - return err - } - } if expectedSize != 0 && bytesCopied != int64(expectedSize) { return fmt.Errorf("unexpected size (downloaded: %d, expected: %d)", bytesCopied, expectedSize)