diff --git a/manifest/ocischema/manifest.go b/manifest/ocischema/manifest.go index f1a05f0a9..a5b199d47 100644 --- a/manifest/ocischema/manifest.go +++ b/manifest/ocischema/manifest.go @@ -61,7 +61,7 @@ func (m Manifest) References() []distribution.Descriptor { return references } -// Target returns the target of this signed manifest. +// Target returns the target of this manifest. func (m Manifest) Target() distribution.Descriptor { return m.Config } diff --git a/manifest/schema2/manifest.go b/manifest/schema2/manifest.go index a2708c750..26a6a334d 100644 --- a/manifest/schema2/manifest.go +++ b/manifest/schema2/manifest.go @@ -79,7 +79,7 @@ func (m Manifest) References() []distribution.Descriptor { return references } -// Target returns the target of this signed manifest. +// Target returns the target of this manifest. func (m Manifest) Target() distribution.Descriptor { return m.Config } diff --git a/registry/handlers/manifests.go b/registry/handlers/manifests.go index 07fd6f8c6..c6e17ada4 100644 --- a/registry/handlers/manifests.go +++ b/registry/handlers/manifests.go @@ -111,13 +111,11 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) } supportsOCI := supportsOCISchema || supportsOCIImageIndex - var manifest distribution.Manifest if imh.Tag != "" { tags := imh.Repository.Tags(imh) var desc distribution.Descriptor - if !supportsOCI { - desc, err = tags.Get(imh, imh.Tag) - } else { + desc, err = tags.Get(imh, imh.annotatedTag(supportsOCI)) + if err != nil && supportsOCI { // in the supportsOCI case fall back to the non OCI image desc, err = tags.Get(imh, imh.annotatedTag(false)) } if err != nil { @@ -140,7 +138,12 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) if imh.Tag != "" { options = append(options, distribution.WithTag(imh.annotatedTag(supportsOCI))) } + var manifest distribution.Manifest manifest, err = manifests.Get(imh, imh.Digest, options...) + if err != nil && supportsOCI && imh.Tag != "" { // in the supportsOCI case fall back to the non OCI image + options = append(options[:0], distribution.WithTag(imh.annotatedTag(false))) + manifest, err = manifests.Get(imh, imh.Digest, options...) + } if err != nil { if _, ok := err.(distribution.ErrManifestUnknownRevision); ok { imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err)) @@ -238,183 +241,6 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) w.Write(p) } -// GetImageManifest fetches the image manifest from the storage backend, if it exists. -func (imh *manifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Request) { - fmt.Printf("\n\nGetting a manifest!\n\n\n") - supportsSchema2 := false - supportsManifestList := false - supportsOCISchema := false - supportsOCIImageIndex := false - - // this parsing of Accept headers is not quite as full-featured as godoc.org's parser, but we don't care about "q=" values - // https://github.com/golang/gddo/blob/e91d4165076d7474d20abda83f92d15c7ebc3e81/httputil/header/header.go#L165-L202 - for _, acceptHeader := range r.Header["Accept"] { - // r.Header[...] is a slice in case the request contains the same header more than once - // if the header isn't set, we'll get the zero value, which "range" will handle gracefully - - // we need to split each header value on "," to get the full list of "Accept" values (per RFC 2616) - // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 - for _, mediaType := range strings.Split(acceptHeader, ",") { - // remove "; q=..." if present - if i := strings.Index(mediaType, ";"); i >= 0 { - mediaType = mediaType[:i] - } - - // it's common (but not required) for Accept values to be space separated ("a/b, c/d, e/f") - mediaType = strings.TrimSpace(mediaType) - - if mediaType == schema2.MediaTypeManifest { - supportsSchema2 = true - } - if mediaType == manifestlist.MediaTypeManifestList { - supportsManifestList = true - } - if mediaType == v1.MediaTypeImageManifest { - supportsOCISchema = true - } - if mediaType == v1.MediaTypeImageIndex { - supportsOCIImageIndex = true - } - } - } - supportsOCI := supportsOCISchema || supportsOCIImageIndex - - ctxu.GetLogger(imh).Debug("GetImageManifest") - manifests, err := imh.Repository.Manifests(imh) - if err != nil { - imh.Errors = append(imh.Errors, err) - return - } - - var manifest distribution.Manifest - if imh.Tag != "" { - tags := imh.Repository.Tags(imh) - var desc distribution.Descriptor - if !supportsOCI { - desc, err = tags.Get(imh, imh.Tag) - if err != nil { - imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err)) - return - } - } else { - desc, err = tags.Get(imh, imh.annotatedTag(supportsOCI)) - if err != nil { - desc, err = tags.Get(imh, imh.annotatedTag(false)) - if err != nil { - imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err)) - return - } - } - } - imh.Digest = desc.Digest - } - - if etagMatch(r, imh.Digest.String()) { - w.WriteHeader(http.StatusNotModified) - return - } - - var options []distribution.ManifestServiceOption - if imh.Tag != "" { - options = append(options, distribution.WithTag(imh.annotatedTag(supportsOCI))) - } - manifest, err = manifests.Get(imh, imh.Digest, options...) - if err != nil { - imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err)) - return - } - - schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest) - manifestList, isManifestList := manifest.(*manifestlist.DeserializedManifestList) - isAnOCIManifest := isSchema2 && (schema2Manifest.MediaType == v1.MediaTypeImageManifest) - isAnOCIImageIndex := isManifestList && (manifestList.MediaType == v1.MediaTypeImageIndex) - - badCombinations := [][]bool{ - {isSchema2 && !isAnOCIManifest, supportsOCISchema && !supportsSchema2}, - {isManifestList && !isAnOCIImageIndex, supportsOCIImageIndex && !supportsManifestList}, - {isAnOCIManifest, !supportsOCISchema && supportsSchema2}, - {isAnOCIImageIndex, !supportsOCIImageIndex && supportsManifestList}, - } - for i, combo := range badCombinations { - if combo[0] && combo[1] { - fmt.Printf("\n\nbad combo! %d\n\n\n", i) - w.WriteHeader(http.StatusNotFound) - return - } - } - if isAnOCIManifest { - fmt.Print("\n\nreturning OCI manifest\n\n") - } else if isSchema2 { - fmt.Print("\n\nreturning schema 2 manifest\n\n") - } else { - fmt.Print("\n\nreturning schema 1 manifest\n\n") - } - - // Only rewrite schema2 manifests when they are being fetched by tag. - // If they are being fetched by digest, we can't return something not - // matching the digest. - if imh.Tag != "" && isSchema2 && !(supportsSchema2 || supportsOCISchema) { - // Rewrite manifest in schema1 format - dcontext.GetLogger(imh).Infof("rewriting manifest %s in schema1 format to support old client", imh.Digest.String()) - - manifest, err = imh.convertSchema2Manifest(schema2Manifest) - if err != nil { - return - } - } else if imh.Tag != "" && isManifestList && !(supportsManifestList || supportsOCIImageIndex) { - // Rewrite manifest in schema1 format - dcontext.GetLogger(imh).Infof("rewriting manifest list %s in schema1 format to support old client", imh.Digest.String()) - - // Find the image manifest corresponding to the default - // platform - var manifestDigest digest.Digest - for _, manifestDescriptor := range manifestList.Manifests { - if manifestDescriptor.Platform.Architecture == defaultArch && manifestDescriptor.Platform.OS == defaultOS { - manifestDigest = manifestDescriptor.Digest - break - } - } - - if manifestDigest == "" { - imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown) - return - } - - manifest, err = manifests.Get(imh, manifestDigest) - if err != nil { - if _, ok := err.(distribution.ErrManifestUnknownRevision); ok { - imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err)) - } else { - imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown.WithDetail(err)) - } - return - } - - // If necessary, convert the image manifest - if schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest); isSchema2 && !supportsSchema2 { - manifest, err = imh.convertSchema2Manifest(schema2Manifest) - if err != nil { - return - } - } else { - imh.Digest = manifestDigest - } - } - - ct, p, err := manifest.Payload() - if err != nil { - return - } - - w.Header().Set("Content-Type", ct) - w.Header().Set("Content-Length", fmt.Sprint(len(p))) - w.Header().Set("Docker-Content-Digest", imh.Digest.String()) - w.Header().Set("Etag", fmt.Sprintf(`"%s"`, imh.Digest)) - w.Write(p) - - fmt.Printf("\n\nSucceeded in getting the manifest!\n\n\n") -} - func (imh *manifestHandler) convertSchema2Manifest(schema2Manifest *schema2.DeserializedManifest) (distribution.Manifest, error) { targetDescriptor := schema2Manifest.Target() blobs := imh.Repository.Blobs(imh)