Skip to content

Commit

Permalink
cache: Create an internal "urlWithIntegrity" API, use better filename
Browse files Browse the repository at this point in the history
Prep for openshift/os#477
Clarify internally that this sha256 is uncompressed; the stream
will also have the compressed sha256 which we should support
verifying too (as well as the size).

Since we're now parsing the URL better, use the uncompressed
filename as the target name.  This makes it much *much* more
obvious to users how to manually clean up old images in
the cache.  We can do this because for both FCOS/RHCOS
the filenames contain versions and are immutable - we will
never go back and change an image.
  • Loading branch information
cgwalters committed Jan 21, 2021
1 parent 164a2a3 commit 3a733a5
Showing 1 changed file with 30 additions and 19 deletions.
49 changes: 30 additions & 19 deletions pkg/tfvars/internal/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ package cache
import (
"bytes"
"compress/gzip"
"crypto/md5"
"crypto/sha256"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"

"github.com/h2non/filetype/matchers"
"github.com/pkg/errors"
Expand Down Expand Up @@ -172,14 +172,23 @@ func cacheFile(reader io.Reader, filePath string, sha256Checksum string) (err er
return os.Rename(tempPath, filePath)
}

// downloadFile obtains a file from a given URL, puts it in the cache folder, defined by dataType parameter,
// and returns the local file path.
// urlWithIntegrity pairs a URL with an optional expected sha256 checksum (after decompression, if any)
// If the query string contains sha256 parameter (i.e. https://example.com/data.bin?sha256=098a5a...),
// then the downloaded data checksum will be compared with the provided value.
func downloadFile(baseURL string, dataType string) (string, error) {
// Convert the given URL into a file name using md5 algorithm
fileName := fmt.Sprintf("%x", md5.Sum([]byte(baseURL)))
type urlWithIntegrity struct {
location url.URL
uncompressedSHA256 string
}

func (u *urlWithIntegrity) uncompressedName() string {
n := filepath.Base(u.location.Path)
return strings.TrimSuffix(strings.TrimSuffix(n, ".gz"), ".xz")
}

// download obtains a file from a given URL, puts it in the cache folder, defined by dataType parameter,
// and returns the local file path.
func (u *urlWithIntegrity) download(dataType string) (string, error) {
fileName := u.uncompressedName()
cacheDir, err := getCacheDir(dataType)
if err != nil {
return "", err
Expand All @@ -197,7 +206,7 @@ func downloadFile(baseURL string, dataType string) (string, error) {
}

// Send a request
resp, err := http.Get(baseURL)
resp, err := http.Get(u.location.String())
if err != nil {
return "", err
}
Expand All @@ -208,17 +217,7 @@ func downloadFile(baseURL string, dataType string) (string, error) {
return "", errors.Errorf("bad status: %s", resp.Status)
}

// Get sha256 checksum if it was provided as a part of the URL
var sha256Checksum string
parsedURL, err := url.ParseRequestURI(baseURL)
if err != nil {
return "", err
}
if sha256Checksums, ok := parsedURL.Query()["sha256"]; ok {
sha256Checksum = sha256Checksums[0]
}

err = cacheFile(resp.Body, filePath, sha256Checksum)
err = cacheFile(resp.Body, filePath, u.uncompressedSHA256)
if err != nil {
return "", err
}
Expand All @@ -232,5 +231,17 @@ func downloadFile(baseURL string, dataType string) (string, error) {
func DownloadImageFile(baseURL string) (string, error) {
logrus.Infof("Obtaining RHCOS image file from '%v'", baseURL)

return downloadFile(baseURL, imageDataType)
var u urlWithIntegrity
parsedURL, err := url.ParseRequestURI(baseURL)
if err != nil {
return "", err
}
q := parsedURL.Query()
if uncompressedSHA256, ok := q["sha256"]; ok {
u.uncompressedSHA256 = uncompressedSHA256[0]
delete(q, "sha256")
}
u.location = *parsedURL

return u.download(imageDataType)
}

0 comments on commit 3a733a5

Please sign in to comment.