diff --git a/app/handler/aaafunc.go b/app/handler/aaafunc.go index c3bff77..dfb9ea3 100644 --- a/app/handler/aaafunc.go +++ b/app/handler/aaafunc.go @@ -52,7 +52,7 @@ func (hand *Handler) CheckAccess(rctx *router.Context) (bool, string, error) { accountID = terms.AnonymousID - hand.logg.Debugf("URL: %s", rctx.URL().String()) + //hand.logg.Debugf("URL: %s", rctx.URL().String()) authHeader := rctx.GetHeader("Authorization") hand.logg.Debugf("Authorization: %s", authHeader) if authHeader != "" { diff --git a/app/handler/blob.go b/app/handler/blob.go index cd89b66..381772e 100644 --- a/app/handler/blob.go +++ b/app/handler/blob.go @@ -62,7 +62,7 @@ func (hand *Handler) BlobExists(rctx *router.Context) { func (hand *Handler) PostUpload(rctx *router.Context) { name, _ := rctx.GetSubpath("name") - hand.DumpHeaders("PostUploads", rctx) + //hand.DumpHeaders("PostUploads", rctx) authorization := rctx.GetHeader("Authorization") if authorization == "" { diff --git a/app/imageoper/putman.go b/app/imageoper/putman.go index 28b4c81..8818508 100644 --- a/app/imageoper/putman.go +++ b/app/imageoper/putman.go @@ -88,6 +88,7 @@ func (oper *Operator) PutManifest(ctx context.Context, params *PutManifestParams } incomingManifestBytes := buffer.Bytes() + if int64(len(incomingManifestBytes)) != contentLength { err = fmt.Errorf("Mismatch Content-Length and received manifest size: %d vs %d", contentLength, len(incomingManifestBytes)) @@ -163,11 +164,14 @@ func (oper *Operator) PutManifest(ctx context.Context, params *PutManifestParams if err != nil { return res, http.StatusInternalServerError, err } + // Starting manifest and blobs transaction err = oper.mdb.UpdateManifestWithBlobs(ctx, &incomingManifestDescr, addedBlobDescrs, uselessBlobDescrs) if err != nil { return res, http.StatusInternalServerError, err } + + //goto end for _, blob := range uselessBlobDescrs { exists, _, err := oper.store.BlobExists(blob.Digest) if err != nil { @@ -201,6 +205,8 @@ func (oper *Operator) PutManifest(ctx context.Context, params *PutManifestParams } } + //end: + res.Location = fmt.Sprintf(`/v2/%s/manifests/%s`, params.Name, params.Reference) return res, http.StatusCreated, err } diff --git a/app/maindb/manifest.go b/app/maindb/manifest.go index 8766c55..4943c21 100644 --- a/app/maindb/manifest.go +++ b/app/maindb/manifest.go @@ -129,7 +129,8 @@ func (db *Database) UpdateManifestWithBlobs(ctx context.Context, manifest *descr // Manifest request = `UPDATE manifests SET contentType = $1, payload = $2, digest = $3, updated_at = $4, updated_by = $5 - WHERE name = $6 AND reference = $7, architecture = $8, os = $9, variant = $10` + WHERE name = $6 AND reference = $7 + AND architecture = $8 AND os = $9 AND variant = $10` _, err = tx.Exec(request, manifest.ContentType, manifest.Payload, manifest.Digest, manifest.UpdatedAt, manifest.UpdatedBy, manifest.Name, manifest.Reference, diff --git a/app/service/service.go b/app/service/service.go index 1a1240e..8d8dec8 100644 --- a/app/service/service.go +++ b/app/service/service.go @@ -97,7 +97,7 @@ func (svc *Service) Build() error { svc.rout.Post(`/v2/{name}/blobs/uploads/`, svc.hand.PostUpload) svc.rout.Patch(`/v2/{name}/blobs/uploads/{reference}`, svc.hand.PatchUpload) - svc.rout.Put(`/v2/{name}/uploads/{reference}`, svc.hand.PutUpload) + svc.rout.Put(`/v2/{name}/blobs/uploads/{reference}`, svc.hand.PutUpload) svc.rout.Get(`/v2/{name}/blobs/{digest}`, svc.hand.GetBlob) svc.rout.Delete(`/v2/{name}/blobs/{digest}`, svc.hand.DeleteBlob) diff --git a/pkg/client/servaux.go b/pkg/client/servaux.go deleted file mode 100644 index 22e0cf1..0000000 --- a/pkg/client/servaux.go +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2026 Oleg Borodin - * - * This work is published and licensed under a Creative Commons - * Attribution-NonCommercial-NoDerivatives 4.0 International License. - * - * Distribution of this work is permitted, but commercial use and - * modifications are strictly prohibited. - */ -package client - -import ( - "net/url" - "path" - "strings" -) - -func repackServiceURI(fileuri string) (string, string, string, error) { - var err error - var res, username, password string - if !strings.Contains(fileuri, "://") { - fileuri = "https://" + fileuri - } - uri, err := url.Parse(fileuri) - if err != nil { - return res, username, password, err - } - uri.Path = path.Clean(uri.Path) - if uri.User != nil { - username = uri.User.Username() - password, _ = uri.User.Password() - } - uri.User = nil - //uri.Scheme = "https" - res = uri.String() - return res, username, password, err -} diff --git a/pkg/repocli/getman.go b/pkg/repocli/getman.go index b7f59da..1efef8d 100644 --- a/pkg/repocli/getman.go +++ b/pkg/repocli/getman.go @@ -13,61 +13,62 @@ import ( ocidigest "github.com/opencontainers/go-digest" ) -func (cli *Client) GetRawManifest(ctx context.Context, rawrepo string) (bool, string, []byte, error) { +func (cli *Client) GetRawManifest(ctx context.Context, rawrepo string) (bool, string, []byte, string, error) { var err error var exist bool var mime string var man []byte + var digstr string fmt.Printf("=== %s\n", rawrepo) ref, err := NewReferer(rawrepo) if err != nil { - return exist, mime, man, err + return exist, mime, man, digstr, err } uri := ref.ManifestEP() req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { - return exist, mime, man, err + return exist, mime, man, digstr, err } req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Accept", "*/*") resp, err := cli.httpClient.Do(req) if err != nil { - return exist, mime, man, err + return exist, mime, man, digstr, err } defer resp.Body.Close() if resp.StatusCode == http.StatusNotFound { - return exist, mime, man, err + return exist, mime, man, digstr, err } if resp.StatusCode != http.StatusOK { err := fmt.Errorf("Unxected response code %s", resp.Status) - return exist, mime, man, err + return exist, mime, man, digstr, err } - digstr := resp.Header.Get("Docker-Content-Digest") + digstr = resp.Header.Get("Docker-Content-Digest") if digstr == "" { err := fmt.Errorf("Empty digest declaration") - return exist, mime, man, err + return exist, mime, man, digstr, err } contentLength := resp.Header.Get("Content-Length") if contentLength == "" { err = errors.New("Empty Content-Length header") - return exist, mime, man, err + return exist, mime, man, digstr, err } manSize, err := strconv.ParseInt(contentLength, 10, 64) if err != nil { - return exist, mime, man, err + return exist, mime, man, digstr, err } mime = resp.Header.Get("Content-Type") if mime == "" { err := fmt.Errorf("Empty MIME type declaration") - return exist, mime, man, err + return exist, mime, man, digstr, err } digstr = strings.ToLower(digstr) digobj, err := ocidigest.Parse(digstr) if err != nil { - return exist, mime, man, err + return exist, mime, man, digstr, err } verifier := digobj.Verifier() buffer := bytes.NewBuffer(nil) @@ -75,13 +76,13 @@ func (cli *Client) GetRawManifest(ctx context.Context, rawrepo string) (bool, st recSize, err := Copy(ctx, mwriter, resp.Body) if manSize != recSize { err := fmt.Errorf("Mismatch declared and actual size") - return exist, mime, man, err + return exist, mime, man, digstr, err } man = buffer.Bytes() if !verifier.Verified() { err := fmt.Errorf("Mismatch digest declaration and actual") - return exist, mime, man, err + return exist, mime, man, digstr, err } exist = true - return exist, mime, man, err + return exist, mime, man, digstr, err } diff --git a/pkg/repocli/getman_test.go b/pkg/repocli/getman_test.go index 797a3dd..7f9c527 100644 --- a/pkg/repocli/getman_test.go +++ b/pkg/repocli/getman_test.go @@ -11,7 +11,7 @@ import ( "time" ) -func xxxTestClientGetManifest(t *testing.T) { +func TestClientGetManifest(t *testing.T) { rawrepo := "mirror.gcr.io/alpine" tags := []string{ "3.20.0", @@ -20,11 +20,12 @@ func xxxTestClientGetManifest(t *testing.T) { for _, tag := range tags { cli := NewClient(nil, nil) ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - exist, mime, man, err := cli.GetRawManifest(ctx, rawrepo+":"+tag) + exist, mime, man, digstr, err := cli.GetRawManifest(ctx, rawrepo+":"+tag) require.NoError(t, err) require.True(t, exist) fmt.Printf("Type: %s\n", mime) + fmt.Printf("Digest: %s\n", digstr) buffer := bytes.NewBuffer(nil) err = json.Indent(buffer, man, " ", " ") require.NoError(t, err) diff --git a/pkg/repocli/pullimage.go b/pkg/repocli/pullimage.go index 1378ed7..9290317 100644 --- a/pkg/repocli/pullimage.go +++ b/pkg/repocli/pullimage.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "errors" - "fmt" "os" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -35,9 +34,8 @@ func (down *Loader) Pull(ctx context.Context, rawref, dir, osname, arch string) return err } rawrepo := ref.RawRepo() - tag := ref.Tag() - exist, mime, man, err := down.cli.GetRawManifest(ctx, ref.Raw()) + exist, mime, man, digstr, err := down.cli.GetRawManifest(ctx, ref.Raw()) if err != nil { return err } @@ -45,8 +43,7 @@ func (down *Loader) Pull(ctx context.Context, rawref, dir, osname, arch string) err = errors.New("Manifest not found") return err } - - var digstr string + tag := ref.Tag() if mime == MediaTypeOIIv1 || mime == MediaTypeDDMLv2 { var index ocispec.Index err = json.Unmarshal(man, &index) @@ -63,25 +60,24 @@ func (down *Loader) Pull(ctx context.Context, rawref, dir, osname, arch string) } } } - } - if digstr == "" { - err = errors.New("Manifest for required arch and OS not found") - return err - } - fmt.Printf("Tag: %s\n", tag) - exist, mime, man, err = down.cli.GetRawManifest(ctx, ref.RawWithTag(digstr)) - if err != nil { - return err - } - fmt.Printf("Mime: %s\n", mime) - if !exist { - err = errors.New("Manifest not found") - return err - } - if mime != MediaTypeOIMv1 && mime != MediaTypeDDMv2 { + if tag == "" { + err = errors.New("Manifest for required arch and OS not found") + return err + } + + exist, mime, man, digstr, err = down.cli.GetRawManifest(ctx, ref.RawWithTag(tag)) + if err != nil { + return err + } + if !exist { + err = errors.New("Manifest not found") + return err + } + } else if mime != MediaTypeOIMv1 && mime != MediaTypeDDMv2 { err = errors.New("Unknown manifest media type") return err } + var manifest ocispec.Manifest err = json.Unmarshal(man, &manifest) if err != nil { diff --git a/pkg/repocli/pullimage_test.go b/pkg/repocli/pullimage_test.go index c1c63f0..c6742bb 100644 --- a/pkg/repocli/pullimage_test.go +++ b/pkg/repocli/pullimage_test.go @@ -22,4 +22,5 @@ func xxxTestPullImage(t *testing.T) { destdir := "aaa" err := down.Pull(ctx, rawref, destdir, "linux", "amd64") require.NoError(t, err) + } diff --git a/pkg/repocli/pushimage.go b/pkg/repocli/pushimage.go index 0cd7ae7..0030d87 100644 --- a/pkg/repocli/pushimage.go +++ b/pkg/repocli/pushimage.go @@ -21,7 +21,7 @@ func (down *Loader) Push(ctx context.Context, rawref, dir, osname, arch string) index := imager.Index() for _, descr := range index.Manifests { digstr := descr.Digest.String() - + mime := descr.MediaType _, _, mandata, err := imager.ReadManifest(ctx, digstr) if err != nil { return err @@ -54,8 +54,10 @@ func (down *Loader) Push(ctx context.Context, rawref, dir, osname, arch string) return err } } + err = down.cli.PutManifest(ctx, ref.Raw(), mandata, mime) + if err != nil { + return err + } } - return err - } diff --git a/pkg/repocli/putman.go b/pkg/repocli/putman.go index e370a12..6d6fc6b 100644 --- a/pkg/repocli/putman.go +++ b/pkg/repocli/putman.go @@ -9,17 +9,17 @@ import ( ocidigest "github.com/opencontainers/go-digest" ) -func (cli *Client) PutManifest(ctx context.Context, rawrepo, tag string, man []byte, mime string) error { +func (cli *Client) PutManifest(ctx context.Context, rawref string, man []byte, mime string) error { var err error - ref, err := NewReferer(rawrepo) + ref, err := NewReferer(rawref) if err != nil { return err } uri := ref.ManifestEP() - buffer := bytes.NewBuffer(man) - req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, buffer) + reader := bytes.NewReader(man) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, reader) if err != nil { return err } @@ -33,7 +33,7 @@ func (cli *Client) PutManifest(ctx context.Context, rawrepo, tag string, man []b return err } resp.Body.Close() - if resp.StatusCode != http.StatusAccepted { + if resp.StatusCode != http.StatusAccepted && resp.StatusCode != http.StatusCreated { err = fmt.Errorf("Manifest not accepted, code %d", resp.StatusCode) return err } diff --git a/pkg/terms/terms.go b/pkg/terms/terms.go index c00bc78..9531cc5 100644 --- a/pkg/terms/terms.go +++ b/pkg/terms/terms.go @@ -11,9 +11,9 @@ package terms const ( - AsFinePath string = "asFinePath" - AsPrefix string = "asPrefix" - AsRegexp string = "asRegexp" + xxxAsFinePath string = "asFinePath" + xxxAsPrefix string = "asPrefix" + xxxAsRegexp string = "asRegexp" ) const (