diff --git a/src/controller/proxy/controller.go b/src/controller/proxy/controller.go index 25d1162fd..aec60758a 100644 --- a/src/controller/proxy/controller.go +++ b/src/controller/proxy/controller.go @@ -60,7 +60,9 @@ type Controller interface { ProxyBlob(ctx context.Context, p *models.Project, art lib.ArtifactInfo) (int64, io.ReadCloser, error) // ProxyManifest proxy the manifest request to the remote server, p is the proxy project, // art is the ArtifactInfo which includes the tag or digest of the manifest - ProxyManifest(ctx context.Context, p *models.Project, art lib.ArtifactInfo, remote RemoteInterface) (distribution.Manifest, error) + ProxyManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (distribution.Manifest, error) + // HeadManifest send manifest head request to the remote server + HeadManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (bool, string, error) } type controller struct { blobCtl blob.Controller @@ -121,7 +123,7 @@ func (c *controller) UseLocalManifest(ctx context.Context, art lib.ArtifactInfo, return dig == a.Digest, nil // digest matches } -func (c *controller) ProxyManifest(ctx context.Context, p *models.Project, art lib.ArtifactInfo, remote RemoteInterface) (distribution.Manifest, error) { +func (c *controller) ProxyManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (distribution.Manifest, error) { var man distribution.Manifest remoteRepo := getRemoteRepo(art) ref := getReference(art) @@ -166,7 +168,11 @@ func (c *controller) ProxyManifest(ctx context.Context, p *models.Project, art l return man, nil } - +func (c *controller) HeadManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (bool, string, error) { + remoteRepo := getRemoteRepo(art) + ref := getReference(art) + return remote.ManifestExist(remoteRepo, ref) +} func (c *controller) ProxyBlob(ctx context.Context, p *models.Project, art lib.ArtifactInfo) (int64, io.ReadCloser, error) { remoteRepo := getRemoteRepo(art) log.Debugf("The blob doesn't exist, proxy the request to the target server, url:%v", remoteRepo) diff --git a/src/server/middleware/repoproxy/proxy.go b/src/server/middleware/repoproxy/proxy.go index 1877e12d1..d95e1ac3a 100644 --- a/src/server/middleware/repoproxy/proxy.go +++ b/src/server/middleware/repoproxy/proxy.go @@ -83,8 +83,8 @@ func preCheck(ctx context.Context) (art lib.ArtifactInfo, p *models.Project, ctl return } -// ManifestGetMiddleware middleware handle request for get manifest -func ManifestGetMiddleware() func(http.Handler) http.Handler { +// ManifestMiddleware middleware handle request for get or head manifest +func ManifestMiddleware() func(http.Handler) http.Handler { return middleware.New(func(w http.ResponseWriter, r *http.Request, next http.Handler) { if err := handleManifest(w, r, next); err != nil { httpLib.SendError(w, err) @@ -115,7 +115,11 @@ func handleManifest(w http.ResponseWriter, r *http.Request, next http.Handler) e return nil } log.Debugf("the tag is %v, digest is %v", art.Tag, art.Digest) - err = proxyManifest(ctx, w, proxyCtl, p, art, remote) + if r.Method == http.MethodHead { + err = proxyManifestHead(ctx, w, proxyCtl, p, art, remote) + } else if r.Method == http.MethodGet { + err = proxyManifestGet(ctx, w, proxyCtl, p, art, remote) + } if err != nil { if errors.IsNotFoundErr(err) { return err @@ -126,8 +130,8 @@ func handleManifest(w http.ResponseWriter, r *http.Request, next http.Handler) e return nil } -func proxyManifest(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *models.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error { - man, err := ctl.ProxyManifest(ctx, p, art, remote) +func proxyManifestGet(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *models.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error { + man, err := ctl.ProxyManifest(ctx, art, remote) if err != nil { return err } @@ -200,3 +204,16 @@ func DisableBlobAndManifestUploadMiddleware() func(http.Handler) http.Handler { return }) } + +func proxyManifestHead(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *models.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error { + exist, dig, err := ctl.HeadManifest(ctx, art, remote) + if err != nil { + return err + } + if !exist { + return errors.NotFoundError(fmt.Errorf("The tag %v:%v is not found", art.Repository, art.Tag)) + } + w.Header().Set("Docker-Content-Digest", dig) + w.Header().Set("Etag", dig) + return nil +} diff --git a/src/server/registry/route.go b/src/server/registry/route.go index d744f42e8..87b24a501 100644 --- a/src/server/registry/route.go +++ b/src/server/registry/route.go @@ -46,13 +46,14 @@ func RegisterRoutes() { root.NewRoute(). Method(http.MethodGet). Path("/*/manifests/:reference"). - Middleware(repoproxy.ManifestGetMiddleware()). + Middleware(repoproxy.ManifestMiddleware()). Middleware(contenttrust.Middleware()). Middleware(vulnerable.Middleware()). HandlerFunc(getManifest) root.NewRoute(). Method(http.MethodHead). Path("/*/manifests/:reference"). + Middleware(repoproxy.ManifestMiddleware()). HandlerFunc(getManifest) root.NewRoute(). Method(http.MethodDelete).