diff --git a/src/pkg/registry/client.go b/src/pkg/registry/client.go index 6b4447e6f..9d971dc4d 100644 --- a/src/pkg/registry/client.go +++ b/src/pkg/registry/client.go @@ -351,16 +351,24 @@ func (c *client) PullBlob(repository, digest string) (int64, io.ReadCloser, erro if err != nil { return 0, nil, err } + + req.Header.Add(http.CanonicalHeaderKey("Accept-Encoding"), "identity") resp, err := c.do(req) if err != nil { return 0, nil, err } + + var size int64 n := resp.Header.Get(http.CanonicalHeaderKey("Content-Length")) - size, err := strconv.ParseInt(n, 10, 64) - if err != nil { - defer resp.Body.Close() - return 0, nil, err + // no content-length is acceptable, which can taken from manifests + if len(n) > 0 { + size, err = strconv.ParseInt(n, 10, 64) + if err != nil { + defer resp.Body.Close() + return 0, nil, err + } } + return size, resp.Body, nil } diff --git a/src/replication/transfer/image/transfer.go b/src/replication/transfer/image/transfer.go index 7a02cdc7c..57ccf86ac 100644 --- a/src/replication/transfer/image/transfer.go +++ b/src/replication/transfer/image/transfer.go @@ -16,12 +16,13 @@ package image import ( "errors" + "net/http" + "strings" + "github.com/docker/distribution/manifest/manifestlist" "github.com/docker/distribution/manifest/schema1" common_http "github.com/goharbor/harbor/src/common/http" v1 "github.com/opencontainers/image-spec/specs-go/v1" - "net/http" - "strings" "github.com/docker/distribution" "github.com/docker/distribution/manifest/schema2" @@ -243,12 +244,13 @@ func (t *transfer) copyContent(content distribution.Descriptor, srcRepo, dstRepo // the media type of the layer or config can be "application/octet-stream", // schema1.MediaTypeManifestLayer, schema2.MediaTypeLayer, schema2.MediaTypeImageConfig default: - return t.copyBlob(srcRepo, dstRepo, digest) + return t.copyBlob(srcRepo, dstRepo, digest, content.Size) } } // copy the layer or artifact config from the source registry to destination -func (t *transfer) copyBlob(srcRepo, dstRepo, digest string) error { +// the size parameter is taken from manifests. +func (t *transfer) copyBlob(srcRepo, dstRepo, digest string, sizeFromDescriptor int64) error { if t.shouldStop() { return nil } @@ -269,6 +271,12 @@ func (t *transfer) copyBlob(srcRepo, dstRepo, digest string) error { return err } defer data.Close() + // get size 0 from PullBlob, use size from distribution.Descriptor instead. + if size == 0 { + size = sizeFromDescriptor + t.logger.Debugf("the blob size from remote registry is 0, use size %d from manifests instead", size) + } + if err = t.dst.PushBlob(dstRepo, digest, size, data); err != nil { t.logger.Errorf("failed to pushing the blob %s: %v", digest, err) return err