|  |  |  | @ -30,6 +30,17 @@ const ( | 
		
	
		
			
				|  |  |  |  | 	imageClass          = "image" | 
		
	
		
			
				|  |  |  |  | ) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | type storageType int | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const ( | 
		
	
		
			
				|  |  |  |  | 	manifestSchema1     storageType = iota // 0
 | 
		
	
		
			
				|  |  |  |  | 	manifestSchema2                        // 1
 | 
		
	
		
			
				|  |  |  |  | 	manifestlistSchema                     // 2
 | 
		
	
		
			
				|  |  |  |  | 	ociSchema                              // 3
 | 
		
	
		
			
				|  |  |  |  | 	ociImageIndexSchema                    // 4
 | 
		
	
		
			
				|  |  |  |  | 	numStorageTypes                        // 5
 | 
		
	
		
			
				|  |  |  |  | ) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | // manifestDispatcher takes the request context and builds the
 | 
		
	
		
			
				|  |  |  |  | // appropriate handler for handling manifest requests.
 | 
		
	
		
			
				|  |  |  |  | func manifestDispatcher(ctx *Context, r *http.Request) http.Handler { | 
		
	
	
		
			
				
					|  |  |  | @ -75,10 +86,8 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) | 
		
	
		
			
				|  |  |  |  | 		imh.Errors = append(imh.Errors, err) | 
		
	
		
			
				|  |  |  |  | 		return | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	supportsSchema2 := false | 
		
	
		
			
				|  |  |  |  | 	supportsManifestList := false | 
		
	
		
			
				|  |  |  |  | 	supportsOCISchema := false | 
		
	
		
			
				|  |  |  |  | 	supportsOCIImageIndex := false | 
		
	
		
			
				|  |  |  |  | 	var supports [numStorageTypes]bool | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	// 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"] { | 
		
	
	
		
			
				
					|  |  |  | @ -97,16 +106,16 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) | 
		
	
		
			
				|  |  |  |  | 			mediaType = strings.TrimSpace(mediaType) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 			if mediaType == schema2.MediaTypeManifest { | 
		
	
		
			
				|  |  |  |  | 				supportsSchema2 = true | 
		
	
		
			
				|  |  |  |  | 				supports[manifestSchema2] = true | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			if mediaType == manifestlist.MediaTypeManifestList { | 
		
	
		
			
				|  |  |  |  | 				supportsManifestList = true | 
		
	
		
			
				|  |  |  |  | 				supports[manifestlistSchema] = true | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			if mediaType == v1.MediaTypeImageManifest { | 
		
	
		
			
				|  |  |  |  | 				supportsOCISchema = true | 
		
	
		
			
				|  |  |  |  | 				supports[ociSchema] = true | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			if mediaType == v1.MediaTypeImageIndex { | 
		
	
		
			
				|  |  |  |  | 				supportsOCIImageIndex = true | 
		
	
		
			
				|  |  |  |  | 				supports[ociImageIndexSchema] = true | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
	
		
			
				
					|  |  |  | @ -145,36 +154,34 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		return | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	// determine the type of the returned manifest
 | 
		
	
		
			
				|  |  |  |  | 	manifestType := manifestSchema1 | 
		
	
		
			
				|  |  |  |  | 	schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest) | 
		
	
		
			
				|  |  |  |  | 	manifestList, isManifestList := manifest.(*manifestlist.DeserializedManifestList) | 
		
	
		
			
				|  |  |  |  | 	isAnOCIManifest := isSchema2 && (schema2Manifest.MediaType == v1.MediaTypeImageManifest) | 
		
	
		
			
				|  |  |  |  | 	isAnOCIImageIndex := isManifestList && (manifestList.MediaType == v1.MediaTypeImageIndex) | 
		
	
		
			
				|  |  |  |  | 	if isSchema2 { | 
		
	
		
			
				|  |  |  |  | 		manifestType = manifestSchema2 | 
		
	
		
			
				|  |  |  |  | 	} else if _, isOCImanifest := manifest.(*ocischema.DeserializedManifest); isOCImanifest { | 
		
	
		
			
				|  |  |  |  | 		manifestType = ociSchema | 
		
	
		
			
				|  |  |  |  | 	} else if isManifestList { | 
		
	
		
			
				|  |  |  |  | 		if manifestList.MediaType == manifestlist.MediaTypeManifestList { | 
		
	
		
			
				|  |  |  |  | 			manifestType = manifestlistSchema | 
		
	
		
			
				|  |  |  |  | 		} else if manifestList.MediaType == v1.MediaTypeImageIndex { | 
		
	
		
			
				|  |  |  |  | 			manifestType = ociImageIndexSchema | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (isSchema2 && !isAnOCIManifest) && (supportsOCISchema && !supportsSchema2) { | 
		
	
		
			
				|  |  |  |  | 		ctxu.GetLogger(imh).Debug("manifest is schema2, but accept header only supports OCISchema") | 
		
	
		
			
				|  |  |  |  | 		w.WriteHeader(http.StatusNotFound) | 
		
	
		
			
				|  |  |  |  | 	if manifestType == ociSchema && !supports[ociSchema] { | 
		
	
		
			
				|  |  |  |  | 		imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithMessage("OCI manifest found, but accept header does not support OCI manifests")) | 
		
	
		
			
				|  |  |  |  | 		return | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	if (isManifestList && !isAnOCIImageIndex) && (supportsOCIImageIndex && !supportsManifestList) { | 
		
	
		
			
				|  |  |  |  | 		ctxu.GetLogger(imh).Debug("manifestlist is not OCI, but accept header only supports an OCI manifestlist") | 
		
	
		
			
				|  |  |  |  | 		w.WriteHeader(http.StatusNotFound) | 
		
	
		
			
				|  |  |  |  | 		return | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	if isAnOCIManifest && (!supportsOCISchema && supportsSchema2) { | 
		
	
		
			
				|  |  |  |  | 		ctxu.GetLogger(imh).Debug("manifest is OCI, but accept header only supports schema2") | 
		
	
		
			
				|  |  |  |  | 		w.WriteHeader(http.StatusNotFound) | 
		
	
		
			
				|  |  |  |  | 		return | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	if isAnOCIImageIndex && (!supportsOCIImageIndex && supportsManifestList) { | 
		
	
		
			
				|  |  |  |  | 		ctxu.GetLogger(imh).Debug("manifestlist is OCI, but accept header only supports non-OCI manifestlists") | 
		
	
		
			
				|  |  |  |  | 		w.WriteHeader(http.StatusNotFound) | 
		
	
		
			
				|  |  |  |  | 	if manifestType == ociImageIndexSchema && !supports[ociImageIndexSchema] { | 
		
	
		
			
				|  |  |  |  | 		imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithMessage("OCI index found, but accept header does not support OCI indexes")) | 
		
	
		
			
				|  |  |  |  | 		return | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	// 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) { | 
		
	
		
			
				|  |  |  |  | 	if imh.Tag != "" && manifestType == manifestSchema2 && !supports[manifestSchema2] { | 
		
	
		
			
				|  |  |  |  | 		// Rewrite manifest in schema1 format
 | 
		
	
		
			
				|  |  |  |  | 		ctxu.GetLogger(imh).Infof("rewriting manifest %s in schema1 format to support old client", imh.Digest.String()) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -182,7 +189,7 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) | 
		
	
		
			
				|  |  |  |  | 		if err != nil { | 
		
	
		
			
				|  |  |  |  | 			return | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} else if imh.Tag != "" && isManifestList && !(supportsManifestList || supportsOCIImageIndex) { | 
		
	
		
			
				|  |  |  |  | 	} else if imh.Tag != "" && manifestType == manifestlistSchema && !supports[manifestlistSchema] { | 
		
	
		
			
				|  |  |  |  | 		// Rewrite manifest in schema1 format
 | 
		
	
		
			
				|  |  |  |  | 		ctxu.GetLogger(imh).Infof("rewriting manifest list %s in schema1 format to support old client", imh.Digest.String()) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -212,7 +219,7 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 		// If necessary, convert the image manifest
 | 
		
	
		
			
				|  |  |  |  | 		if schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest); isSchema2 && !(supportsSchema2 || supportsOCISchema) { | 
		
	
		
			
				|  |  |  |  | 		if schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest); isSchema2 && !supports[manifestSchema2] { | 
		
	
		
			
				|  |  |  |  | 			manifest, err = imh.convertSchema2Manifest(schema2Manifest) | 
		
	
		
			
				|  |  |  |  | 			if err != nil { | 
		
	
		
			
				|  |  |  |  | 				return | 
		
	
	
		
			
				
					|  |  |  | 
 |