...
1 package storage
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "net/url"
8
9 "github.com/docker/distribution"
10 dcontext "github.com/docker/distribution/context"
11 "github.com/docker/distribution/manifest/schema1"
12 "github.com/docker/distribution/manifest/schema2"
13 "github.com/opencontainers/go-digest"
14 )
15
16 var (
17 errMissingURL = errors.New("missing URL on layer")
18 errInvalidURL = errors.New("invalid URL on layer")
19 )
20
21
22 type schema2ManifestHandler struct {
23 repository distribution.Repository
24 blobStore distribution.BlobStore
25 ctx context.Context
26 manifestURLs manifestURLs
27 }
28
29 var _ ManifestHandler = &schema2ManifestHandler{}
30
31 func (ms *schema2ManifestHandler) Unmarshal(ctx context.Context, dgst digest.Digest, content []byte) (distribution.Manifest, error) {
32 dcontext.GetLogger(ms.ctx).Debug("(*schema2ManifestHandler).Unmarshal")
33
34 m := &schema2.DeserializedManifest{}
35 if err := m.UnmarshalJSON(content); err != nil {
36 return nil, err
37 }
38
39 return m, nil
40 }
41
42 func (ms *schema2ManifestHandler) Put(ctx context.Context, manifest distribution.Manifest, skipDependencyVerification bool) (digest.Digest, error) {
43 dcontext.GetLogger(ms.ctx).Debug("(*schema2ManifestHandler).Put")
44
45 m, ok := manifest.(*schema2.DeserializedManifest)
46 if !ok {
47 return "", fmt.Errorf("non-schema2 manifest put to schema2ManifestHandler: %T", manifest)
48 }
49
50 if err := ms.verifyManifest(ms.ctx, *m, skipDependencyVerification); err != nil {
51 return "", err
52 }
53
54 mt, payload, err := m.Payload()
55 if err != nil {
56 return "", err
57 }
58
59 revision, err := ms.blobStore.Put(ctx, mt, payload)
60 if err != nil {
61 dcontext.GetLogger(ctx).Errorf("error putting payload into blobstore: %v", err)
62 return "", err
63 }
64
65 return revision.Digest, nil
66 }
67
68
69
70
71 func (ms *schema2ManifestHandler) verifyManifest(ctx context.Context, mnfst schema2.DeserializedManifest, skipDependencyVerification bool) error {
72 var errs distribution.ErrManifestVerification
73
74 if mnfst.Manifest.SchemaVersion != 2 {
75 return fmt.Errorf("unrecognized manifest schema version %d", mnfst.Manifest.SchemaVersion)
76 }
77
78 if skipDependencyVerification {
79 return nil
80 }
81
82 manifestService, err := ms.repository.Manifests(ctx)
83 if err != nil {
84 return err
85 }
86
87 blobsService := ms.repository.Blobs(ctx)
88
89 for _, descriptor := range mnfst.References() {
90 var err error
91
92 switch descriptor.MediaType {
93 case schema2.MediaTypeForeignLayer:
94
95
96 if len(descriptor.URLs) == 0 {
97 err = errMissingURL
98 }
99 allow := ms.manifestURLs.allow
100 deny := ms.manifestURLs.deny
101 for _, u := range descriptor.URLs {
102 var pu *url.URL
103 pu, err = url.Parse(u)
104 if err != nil || (pu.Scheme != "http" && pu.Scheme != "https") || pu.Fragment != "" || (allow != nil && !allow.MatchString(u)) || (deny != nil && deny.MatchString(u)) {
105 err = errInvalidURL
106 break
107 }
108 }
109 case schema2.MediaTypeManifest, schema1.MediaTypeManifest:
110 var exists bool
111 exists, err = manifestService.Exists(ctx, descriptor.Digest)
112 if err != nil || !exists {
113 err = distribution.ErrBlobUnknown
114 }
115
116 fallthrough
117 default:
118
119 if len(descriptor.URLs) == 0 {
120 _, err = blobsService.Stat(ctx, descriptor.Digest)
121 }
122 }
123
124 if err != nil {
125 if err != distribution.ErrBlobUnknown {
126 errs = append(errs, err)
127 }
128
129
130 errs = append(errs, distribution.ErrManifestBlobUnknown{Digest: descriptor.Digest})
131 }
132 }
133
134 if len(errs) != 0 {
135 return errs
136 }
137
138 return nil
139 }
140
View as plain text