...

Source file src/github.com/docker/distribution/registry/storage/ocimanifesthandler.go

Documentation: github.com/docker/distribution/registry/storage

     1  package storage
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/url"
     7  
     8  	"github.com/docker/distribution"
     9  	dcontext "github.com/docker/distribution/context"
    10  	"github.com/docker/distribution/manifest/ocischema"
    11  	"github.com/opencontainers/go-digest"
    12  	v1 "github.com/opencontainers/image-spec/specs-go/v1"
    13  )
    14  
    15  // ocischemaManifestHandler is a ManifestHandler that covers ocischema manifests.
    16  type ocischemaManifestHandler struct {
    17  	repository   distribution.Repository
    18  	blobStore    distribution.BlobStore
    19  	ctx          context.Context
    20  	manifestURLs manifestURLs
    21  }
    22  
    23  var _ ManifestHandler = &ocischemaManifestHandler{}
    24  
    25  func (ms *ocischemaManifestHandler) Unmarshal(ctx context.Context, dgst digest.Digest, content []byte) (distribution.Manifest, error) {
    26  	dcontext.GetLogger(ms.ctx).Debug("(*ocischemaManifestHandler).Unmarshal")
    27  
    28  	m := &ocischema.DeserializedManifest{}
    29  	if err := m.UnmarshalJSON(content); err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	return m, nil
    34  }
    35  
    36  func (ms *ocischemaManifestHandler) Put(ctx context.Context, manifest distribution.Manifest, skipDependencyVerification bool) (digest.Digest, error) {
    37  	dcontext.GetLogger(ms.ctx).Debug("(*ocischemaManifestHandler).Put")
    38  
    39  	m, ok := manifest.(*ocischema.DeserializedManifest)
    40  	if !ok {
    41  		return "", fmt.Errorf("non-ocischema manifest put to ocischemaManifestHandler: %T", manifest)
    42  	}
    43  
    44  	if err := ms.verifyManifest(ms.ctx, *m, skipDependencyVerification); err != nil {
    45  		return "", err
    46  	}
    47  
    48  	mt, payload, err := m.Payload()
    49  	if err != nil {
    50  		return "", err
    51  	}
    52  
    53  	revision, err := ms.blobStore.Put(ctx, mt, payload)
    54  	if err != nil {
    55  		dcontext.GetLogger(ctx).Errorf("error putting payload into blobstore: %v", err)
    56  		return "", err
    57  	}
    58  
    59  	return revision.Digest, nil
    60  }
    61  
    62  // verifyManifest ensures that the manifest content is valid from the
    63  // perspective of the registry. As a policy, the registry only tries to store
    64  // valid content, leaving trust policies of that content up to consumers.
    65  func (ms *ocischemaManifestHandler) verifyManifest(ctx context.Context, mnfst ocischema.DeserializedManifest, skipDependencyVerification bool) error {
    66  	var errs distribution.ErrManifestVerification
    67  
    68  	if mnfst.Manifest.SchemaVersion != 2 {
    69  		return fmt.Errorf("unrecognized manifest schema version %d", mnfst.Manifest.SchemaVersion)
    70  	}
    71  
    72  	if skipDependencyVerification {
    73  		return nil
    74  	}
    75  
    76  	manifestService, err := ms.repository.Manifests(ctx)
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	blobsService := ms.repository.Blobs(ctx)
    82  
    83  	for _, descriptor := range mnfst.References() {
    84  		var err error
    85  
    86  		switch descriptor.MediaType {
    87  		case v1.MediaTypeImageLayer, v1.MediaTypeImageLayerGzip, v1.MediaTypeImageLayerNonDistributable, v1.MediaTypeImageLayerNonDistributableGzip:
    88  			allow := ms.manifestURLs.allow
    89  			deny := ms.manifestURLs.deny
    90  			for _, u := range descriptor.URLs {
    91  				var pu *url.URL
    92  				pu, err = url.Parse(u)
    93  				if err != nil || (pu.Scheme != "http" && pu.Scheme != "https") || pu.Fragment != "" || (allow != nil && !allow.MatchString(u)) || (deny != nil && deny.MatchString(u)) {
    94  					err = errInvalidURL
    95  					break
    96  				}
    97  			}
    98  			if err == nil && len(descriptor.URLs) == 0 {
    99  				// If no URLs, require that the blob exists
   100  				_, err = blobsService.Stat(ctx, descriptor.Digest)
   101  			}
   102  
   103  		case v1.MediaTypeImageManifest:
   104  			var exists bool
   105  			exists, err = manifestService.Exists(ctx, descriptor.Digest)
   106  			if err != nil || !exists {
   107  				err = distribution.ErrBlobUnknown // just coerce to unknown.
   108  			}
   109  
   110  			fallthrough // double check the blob store.
   111  		default:
   112  			// forward all else to blob storage
   113  			if len(descriptor.URLs) == 0 {
   114  				_, err = blobsService.Stat(ctx, descriptor.Digest)
   115  			}
   116  		}
   117  
   118  		if err != nil {
   119  			if err != distribution.ErrBlobUnknown {
   120  				errs = append(errs, err)
   121  			}
   122  
   123  			// On error here, we always append unknown blob errors.
   124  			errs = append(errs, distribution.ErrManifestBlobUnknown{Digest: descriptor.Digest})
   125  		}
   126  	}
   127  
   128  	if len(errs) != 0 {
   129  		return errs
   130  	}
   131  
   132  	return nil
   133  }
   134  

View as plain text