Skip to content

Commit

Permalink
Fix c/image fails to pull OCI image with non-http(s):// urls
Browse files Browse the repository at this point in the history
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
  • Loading branch information
ktock committed Nov 9, 2021
1 parent f5b23d3 commit 0fc15bc
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 10 deletions.
25 changes: 20 additions & 5 deletions docker/docker_image_src.go
Expand Up @@ -236,13 +236,23 @@ func (s *dockerImageSource) ensureManifestIsLoaded(ctx context.Context) error {
return nil
}

func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string) (io.ReadCloser, int64, error) {
func supportedHTTPURLs(urls []string) (supported []string) {
for _, s := range urls {
if u, err := url.Parse(s); err == nil && (u.Scheme == "http" || u.Scheme == "https") {
supported = append(supported, s)
}
}
return
}

func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string) (_ io.ReadCloser, _ int64, fallback bool, _ error) {
urls = supportedHTTPURLs(urls)
var (
resp *http.Response
err error
)
if len(urls) == 0 {
return nil, 0, errors.New("internal error: getExternalBlob called with no URLs")
return nil, 0, true, errors.New("internal error: getExternalBlob called with no URLs")
}
for _, url := range urls {
// NOTE: we must not authenticate on additional URLs as those
Expand All @@ -260,9 +270,9 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
}
}
if err != nil {
return nil, 0, err
return nil, 0, false, err
}
return resp.Body, getBlobSize(resp), nil
return resp.Body, getBlobSize(resp), false, nil
}

func getBlobSize(resp *http.Response) int64 {
Expand Down Expand Up @@ -408,7 +418,12 @@ func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo,
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
if len(info.URLs) != 0 {
return s.getExternalBlob(ctx, info.URLs)
r, s, fallback, err := s.getExternalBlob(ctx, info.URLs)
if err == nil {
return r, s, nil
} else if !fallback {
return nil, 0, err
}
}

path := fmt.Sprintf(blobsPath, reference.Path(s.physicalRef.ref), info.Digest.String())
Expand Down
26 changes: 21 additions & 5 deletions oci/layout/oci_src.go
Expand Up @@ -5,6 +5,7 @@ import (
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"strconv"

Expand Down Expand Up @@ -113,7 +114,12 @@ func (s *ociImageSource) HasThreadSafeGetBlob() bool {
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
func (s *ociImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
if len(info.URLs) != 0 {
return s.getExternalBlob(ctx, info.URLs)
r, s, fallback, err := s.getExternalBlob(ctx, info.URLs)
if err == nil {
return r, s, nil
} else if !fallback {
return nil, 0, err
}
}

path, err := s.ref.blobPath(info.Digest, s.sharedBlobDir)
Expand All @@ -140,9 +146,19 @@ func (s *ociImageSource) GetSignatures(ctx context.Context, instanceDigest *dige
return [][]byte{}, nil
}

func (s *ociImageSource) getExternalBlob(ctx context.Context, urls []string) (io.ReadCloser, int64, error) {
func supportedHTTPURLs(urls []string) (supported []string) {
for _, s := range urls {
if u, err := url.Parse(s); err == nil && (u.Scheme == "http" || u.Scheme == "https") {
supported = append(supported, s)
}
}
return
}

func (s *ociImageSource) getExternalBlob(ctx context.Context, urls []string) (_ io.ReadCloser, _ int64, fallback bool, _ error) {
urls = supportedHTTPURLs(urls)
if len(urls) == 0 {
return nil, 0, errors.New("internal error: getExternalBlob called with no URLs")
return nil, 0, true, errors.New("internal error: getExternalBlob called with no URLs")
}

errWrap := errors.New("failed fetching external blob from all urls")
Expand All @@ -166,10 +182,10 @@ func (s *ociImageSource) getExternalBlob(ctx context.Context, urls []string) (io
continue
}

return resp.Body, getBlobSize(resp), nil
return resp.Body, getBlobSize(resp), false, nil
}

return nil, 0, errWrap
return nil, 0, false, errWrap
}

// LayerInfosForCopy returns either nil (meaning the values in the manifest are fine), or updated values for the layer
Expand Down

0 comments on commit 0fc15bc

Please sign in to comment.