From 9fa5a00421d0e7a8a5c5b05a5b6838a96206dfbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3=20=D0=91=D0=BE=D1=80=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 27 Feb 2026 19:04:57 +0200 Subject: [PATCH] working commit --- blobexist.go | 15 ++----- client.go | 88 +++++++++++++++++++++++++++++++++++------- client_test.go | 103 ++++++++++++++++++++++++++++++------------------- delman.go | 17 ++------ getblob.go | 16 ++------ getman.go | 16 ++------ getupload.go | 17 +++----- manexist.go | 16 ++------ pathupload.go | 13 +------ putman.go | 14 ++----- putupload.go | 13 +------ referer.go | 75 +++++++++++++++++------------------ 12 files changed, 200 insertions(+), 203 deletions(-) diff --git a/blobexist.go b/blobexist.go index bc69013..1656680 100644 --- a/blobexist.go +++ b/blobexist.go @@ -7,17 +7,16 @@ import ( "strconv" ) -func (cli *Client) BlobExists(ctx context.Context, rawref string) (bool, int64, error) { +func (cli *Client) BlobExists(ctx context.Context, rawrepo string, digest string) (bool, int64, error) { var err error var exist bool var size int64 - ref, err := NewReference(rawref) + ref, err := NewRepository(rawrepo) if err != nil { return exist, size, err } - uri := ref.Blob() - user, pass := ref.Userinfo() + uri := ref.Blob(digest) fmt.Println(uri) req, err := http.NewRequestWithContext(ctx, http.MethodHead, uri, nil) @@ -27,14 +26,6 @@ func (cli *Client) BlobExists(ctx context.Context, rawref string) (bool, int64, req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Accept", "*/*") - if cli.authenticator != nil { - authHeader, authKey, err := cli.authenticator.MakeHeader(user, pass) - if err != nil { - return exist, size, err - } - req.Header.Set(authHeader, authKey) - } - resp, err := cli.httpClient.Do(req) if err != nil { return exist, size, err diff --git a/client.go b/client.go index 5439c48..70f792c 100644 --- a/client.go +++ b/client.go @@ -2,13 +2,13 @@ package client import ( "crypto/tls" + "encoding/base64" "net/http" ) type Client struct { - httpClient *http.Client - authenticator Authenticator - userAgent string + httpClient *http.Client + userAgent string } func NewClient() *Client { @@ -22,28 +22,88 @@ func NewClient() *Client { } } -func (cli *Client) SetAuthenticator(auth Authenticator) { - cli.authenticator = auth -} - func (cli *Client) SetTransport(transport http.RoundTripper) { cli.httpClient.Transport = transport } -type WrapTransport struct { - transport http.RoundTripper +type MiddlewareFunc func(next http.RoundTripper) http.RoundTripper + +func (cli *Client) UseMiddleware(mwFunc MiddlewareFunc) { + cli.httpClient.Transport = mwFunc(cli.httpClient.Transport) } -func NewWrapTransport(transport http.RoundTripper) *WrapTransport { - return &WrapTransport{ - transport: transport, +// ExampleMiddleware +func NewExampleMiddleware() MiddlewareFunc { + return func(next http.RoundTripper) http.RoundTripper { + return newExampleTransport(next) } } -func (wrap *WrapTransport) RoundTrip(req *http.Request) (*http.Response, error) { - return wrap.transport.RoundTrip(req) +type ExampleTransport struct { + next http.RoundTripper +} + +func newExampleTransport(next http.RoundTripper) *ExampleTransport { + return &ExampleTransport{ + next: next, + } +} + +func (tran ExampleTransport) RoundTrip(req *http.Request) (*http.Response, error) { + return tran.next.RoundTrip(req) +} + +// BasicAuthMiddleware +func NewBasicAuthMiddleware(user, pass string) MiddlewareFunc { + return func(next http.RoundTripper) http.RoundTripper { + return newBasicAuthMW(next, user, pass) + } +} + +type BasicAuthMW struct { + user, pass string + next http.RoundTripper +} + +func newBasicAuthMW(next http.RoundTripper, user, pass string) *BasicAuthMW { + return &BasicAuthMW{ + user: user, + pass: pass, + next: next, + } +} + +func (tran BasicAuthMW) RoundTrip(req *http.Request) (*http.Response, error) { + pair := base64.StdEncoding.EncodeToString([]byte(tran.user + ":" + tran.pass)) + req.Header.Set("Authorization", "Basic "+pair) + return tran.next.RoundTrip(req) +} + +// BearerAuthMiddleware +func NewBearerAuthMiddleware(token string) MiddlewareFunc { + return func(next http.RoundTripper) http.RoundTripper { + return newBearerAuthMW(next, token) + } +} + +type BearerAuthMW struct { + token string + next http.RoundTripper +} + +func newBearerAuthMW(next http.RoundTripper, token string) *BearerAuthMW { + return &BearerAuthMW{ + token: token, + next: next, + } +} + +func (tran BearerAuthMW) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Set("Authorization", "Bearer "+tran.token) + return tran.next.RoundTrip(req) } +// DefaultTransport type DefaultTransport struct { transport http.RoundTripper } diff --git a/client_test.go b/client_test.go index 4e40da7..00f4fe2 100644 --- a/client_test.go +++ b/client_test.go @@ -12,15 +12,16 @@ import ( "time" ) -func TestClientGetManifest(t *testing.T) { - rawrefs := []string{ - "mirror.gcr.io/alpine:3.20.0", - "mirror.gcr.io/alpine:sha256:29e5ba63e79337818e6c63cfcc68e2ab4e9ca483853b2de303bfbfba9372426c", +func xxxTestClientGetManifest(t *testing.T) { + rawrepo := "mirror.gcr.io/alpine" + tags := []string{ + "3.20.0", + "sha256:29e5ba63e79337818e6c63cfcc68e2ab4e9ca483853b2de303bfbfba9372426c", } - for _, rawref := range rawrefs { + for _, tag := range tags { cli := NewClient() ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - exist, mime, man, err := cli.GetManifest(ctx, rawref) + exist, mime, man, err := cli.GetManifest(ctx, rawrepo, tag) require.NoError(t, err) require.True(t, exist) @@ -32,15 +33,17 @@ func TestClientGetManifest(t *testing.T) { } } -func xxxTestClientManifestExists(t *testing.T) { - rawrefs := []string{ - "mirror.gcr.io/alpine:3.20.0", - "mirror.gcr.io/alpine:sha256:29e5ba63e79337818e6c63cfcc68e2ab4e9ca483853b2de303bfbfba9372426c", +func TestClientManifestExists(t *testing.T) { + rawrepo := "mirror.gcr.io/alpine" + tags := []string{ + "3.20.0", + "sha256:29e5ba63e79337818e6c63cfcc68e2ab4e9ca483853b2de303bfbfba9372426c", } - for _, rawref := range rawrefs { + for _, tag := range tags { + cli := NewClient() ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - exist, mime, size, csum, err := cli.ManifestExists(ctx, rawref) + exist, mime, size, csum, err := cli.ManifestExists(ctx, rawrepo, tag) require.NoError(t, err) require.True(t, exist) @@ -52,13 +55,14 @@ func xxxTestClientManifestExists(t *testing.T) { } func xxxTestClientBlobExists(t *testing.T) { - rawrefs := []string{ - "mirror.gcr.io/alpine:sha256:3b8747b05489980f63da1d2b8e5a444c55777f69540394397b0bc1c76c3e41f2", + rawrepos := []string{ + "mirror.gcr.io/alpine", } - for _, rawref := range rawrefs { + for _, rawrepo := range rawrepos { cli := NewClient() ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - exist, size, err := cli.BlobExists(ctx, rawref) + digest := "sha256:3b8747b05489980f63da1d2b8e5a444c55777f69540394397b0bc1c76c3e41f2" + exist, size, err := cli.BlobExists(ctx, rawrepo, digest) require.NoError(t, err) require.True(t, exist) @@ -66,52 +70,51 @@ func xxxTestClientBlobExists(t *testing.T) { } } -func xxxTestClientGetBlob(t *testing.T) { - rawrefs := []string{ - "mirror.gcr.io/alpine:sha256:3b8747b05489980f63da1d2b8e5a444c55777f69540394397b0bc1c76c3e41f2", +func TestClientGetBlob(t *testing.T) { + rawrepos := []string{ + "mirror.gcr.io/alpine", } - for _, rawref := range rawrefs { + for _, rawrepo := range rawrepos { cli := NewClient() ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) buffer := bytes.NewBuffer(nil) - exist, err := cli.GetBlob(ctx, rawref, buffer) + digest := "sha256:3b8747b05489980f63da1d2b8e5a444c55777f69540394397b0bc1c76c3e41f2" + exist, err := cli.GetBlob(ctx, rawrepo, buffer, digest) require.NoError(t, err) require.True(t, exist) fmt.Printf("Size: %d\n", len(buffer.Bytes())) } } -func TestClientGetUpload(t *testing.T) { - rawrefs := []string{ +func xxxxTestClientGetUpload(t *testing.T) { + rawrepos := []string{ "mstore:mstore@localhost:1025/alpine:3.20.0", } - for _, rawref := range rawrefs { + cli := NewClient() + cli.UseMiddleware(NewBasicAuthMiddleware("mstore", "mstore")) + + for _, rawrepo := range rawrepos { var err error var loc string { - cli := NewClient() - cli.SetAuthenticator(NewBasicAuthenticator()) ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - loc, err = cli.GetUpload(ctx, rawref) + loc, err = cli.GetUpload(ctx, rawrepo) require.NoError(t, err) - fmt.Printf("Location: %s\n", loc) + fmt.Printf("Upload Location: %s\n", loc) } { - srcsize := 1024 + 145 srcdata := make([]byte, srcsize) _, err = rand.Read(srcdata) require.NoError(t, err) src := bytes.NewReader(srcdata) - digest := SHA256Digest(srcdata) + //digest := SHA256Digest(srcdata) - cli := NewClient() - cli.SetAuthenticator(NewBasicAuthenticator()) ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - bloc, err := cli.PutUpload(ctx, rawref, src, loc, digest, int64(len(srcdata))) + bloc, err := cli.PatchUpload(ctx, rawrepo, src, loc, int64(len(srcdata))) require.NoError(t, err) - fmt.Printf("Location: %s\n", bloc) + fmt.Printf("Path Location: %s\n", bloc) } { srcsize := 1024 + 145 @@ -120,15 +123,37 @@ func TestClientGetUpload(t *testing.T) { require.NoError(t, err) src := bytes.NewReader(srcdata) - //digest := SHA256Digest(srcdata) + digest := SHA256Digest(srcdata) - cli := NewClient() - cli.SetAuthenticator(NewBasicAuthenticator()) ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - bloc, err := cli.PatchUpload(ctx, rawref, src, loc, int64(len(srcdata))) + bloc, err := cli.PutUpload(ctx, rawrepo, src, loc, digest, int64(len(srcdata))) require.NoError(t, err) - fmt.Printf("Location: %s\n", bloc) + fmt.Printf("Put blob Location: %s\n", bloc) } } } + +func xxxxTestClientGetToken(t *testing.T) { + var token string + var err error + { + cli := NewClient() + cli.UseMiddleware(NewBasicAuthMiddleware("onborodin", "2Albert334")) + ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) + token, err = cli.GetToken(ctx, "https://auth.docker.io/token") + require.NoError(t, err) + + } + fmt.Printf("Token: %s\n", token) + { + rawrepo := "docker.io/onborodin/toolbox:0.18" + cli := NewClient() + cli.UseMiddleware(NewBearerAuthMiddleware(token)) + ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) + loc, err := cli.GetUpload(ctx, rawrepo) + require.NoError(t, err) + fmt.Printf("Upload Location: %s\n", loc) + } + +} diff --git a/delman.go b/delman.go index f5b3c61..979666d 100644 --- a/delman.go +++ b/delman.go @@ -6,32 +6,21 @@ import ( "net/http" ) -func (cli *Client) DeleteManifest(ctx context.Context, rawref string) (bool, error) { +func (cli *Client) DeleteManifest(ctx context.Context, rawrepo, tag string) (bool, error) { var err error var exist bool - ref, err := NewReference(rawref) + ref, err := NewRepository(rawrepo) if err != nil { return exist, err } - uri := ref.Manifest() - user, pass := ref.Userinfo() - + uri := ref.Manifest(tag) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri, nil) if err != nil { return exist, err } req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Accept", "*/*") - - if cli.authenticator != nil { - authHeader, authKey, err := cli.authenticator.MakeHeader(user, pass) - if err != nil { - return exist, err - } - req.Header.Set(authHeader, authKey) - } - resp, err := cli.httpClient.Do(req) if err != nil { return exist, err diff --git a/getblob.go b/getblob.go index a314331..9d6617e 100644 --- a/getblob.go +++ b/getblob.go @@ -8,16 +8,15 @@ import ( "strconv" ) -func (cli *Client) GetBlob(ctx context.Context, rawref string, writer io.Writer) (bool, error) { +func (cli *Client) GetBlob(ctx context.Context, rawrepo string, writer io.Writer, digest string) (bool, error) { var err error var exist bool - ref, err := NewReference(rawref) + ref, err := NewRepository(rawrepo) if err != nil { return exist, err } - uri := ref.Blob() - user, pass := ref.Userinfo() + uri := ref.Blob(digest) req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { @@ -25,15 +24,6 @@ func (cli *Client) GetBlob(ctx context.Context, rawref string, writer io.Writer) } req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Accept", "*/*") - - if cli.authenticator != nil { - authHeader, authKey, err := cli.authenticator.MakeHeader(user, pass) - if err != nil { - return exist, err - } - req.Header.Set(authHeader, authKey) - } - resp, err := cli.httpClient.Do(req) if err != nil { return exist, err diff --git a/getman.go b/getman.go index c4a05cd..89fdfba 100644 --- a/getman.go +++ b/getman.go @@ -9,18 +9,17 @@ import ( "strings" ) -func (cli *Client) GetManifest(ctx context.Context, rawref string) (bool, string, []byte, error) { +func (cli *Client) GetManifest(ctx context.Context, rawrepo, tag string) (bool, string, []byte, error) { var err error var exist bool var mime string var man []byte - ref, err := NewReference(rawref) + ref, err := NewRepository(rawrepo) if err != nil { return exist, mime, man, err } - uri := ref.Manifest() - user, pass := ref.Userinfo() + uri := ref.Manifest(tag) req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { @@ -28,15 +27,6 @@ func (cli *Client) GetManifest(ctx context.Context, rawref string) (bool, string } req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Accept", "*/*") - - if cli.authenticator != nil { - authHeader, authKey, err := cli.authenticator.MakeHeader(user, pass) - if err != nil { - return exist, mime, man, err - } - req.Header.Set(authHeader, authKey) - } - resp, err := cli.httpClient.Do(req) if err != nil { return exist, mime, man, err diff --git a/getupload.go b/getupload.go index 7903ac6..05634d5 100644 --- a/getupload.go +++ b/getupload.go @@ -6,16 +6,15 @@ import ( "net/http" ) -func (cli *Client) GetUpload(ctx context.Context, rawref string) (string, error) { +func (cli *Client) GetUpload(ctx context.Context, rawrepo string) (string, error) { var err error var loc string - ref, err := NewReference(rawref) + ref, err := NewRepository(rawrepo) if err != nil { return loc, err } uri := ref.Upload() - user, pass := ref.Userinfo() req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil) if err != nil { @@ -23,26 +22,20 @@ func (cli *Client) GetUpload(ctx context.Context, rawref string) (string, error) } req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Accept", "*/*") - - if cli.authenticator != nil { - authHeader, authKey, err := cli.authenticator.MakeHeader(user, pass) - if err != nil { - return loc, err - } - req.Header.Set(authHeader, authKey) - } - resp, err := cli.httpClient.Do(req) if err != nil { return loc, err } defer resp.Body.Close() + fmt.Printf("=== %++v\n", resp.Header) + if resp.StatusCode != http.StatusAccepted { err := fmt.Errorf("Unxected response code %s", resp.Status) return loc, err } loc = resp.Header.Get("Location") + if loc == "" { err := fmt.Errorf("Empty location declaration") return loc, err diff --git a/manexist.go b/manexist.go index 9292e3c..25d2a23 100644 --- a/manexist.go +++ b/manexist.go @@ -7,19 +7,18 @@ import ( "strconv" ) -func (cli *Client) ManifestExists(ctx context.Context, rawref string) (bool, string, int64, string, error) { +func (cli *Client) ManifestExists(ctx context.Context, rawrepo, tag string) (bool, string, int64, string, error) { var err error var exist bool var mime string var size int64 var csum string - ref, err := NewReference(rawref) + ref, err := NewRepository(rawrepo) if err != nil { return exist, mime, size, csum, err } - uri := ref.Manifest() - user, pass := ref.Userinfo() + uri := ref.Manifest(tag) req, err := http.NewRequestWithContext(ctx, http.MethodHead, uri, nil) if err != nil { @@ -27,15 +26,6 @@ func (cli *Client) ManifestExists(ctx context.Context, rawref string) (bool, str } req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Accept", "*/*") - - if cli.authenticator != nil { - authHeader, authKey, err := cli.authenticator.MakeHeader(user, pass) - if err != nil { - return exist, mime, size, csum, err - } - req.Header.Set(authHeader, authKey) - } - resp, err := cli.httpClient.Do(req) if err != nil { return exist, mime, size, csum, err diff --git a/pathupload.go b/pathupload.go index cf665bb..11238cd 100644 --- a/pathupload.go +++ b/pathupload.go @@ -8,11 +8,11 @@ import ( "strconv" ) -func (cli *Client) PatchUpload(ctx context.Context, rawref string, src io.Reader, uploc string, size int64) (string, error) { +func (cli *Client) PatchUpload(ctx context.Context, rawrepo string, src io.Reader, uploc string, size int64) (string, error) { var err error var ouloc string - ref, err := NewReference(rawref) + ref, err := NewRepository(rawrepo) if err != nil { return ouloc, err } @@ -20,8 +20,6 @@ func (cli *Client) PatchUpload(ctx context.Context, rawref string, src io.Reader if err != nil { return ouloc, err } - user, pass := ref.Userinfo() - req, err := http.NewRequestWithContext(ctx, http.MethodPatch, uri, src) if err != nil { return ouloc, err @@ -29,13 +27,6 @@ func (cli *Client) PatchUpload(ctx context.Context, rawref string, src io.Reader req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Content-Type", "application/octet-stream") req.Header.Set("Content-Length", strconv.FormatInt(size, 10)) - if cli.authenticator != nil { - authHeader, authKey, err := cli.authenticator.MakeHeader(user, pass) - if err != nil { - return ouloc, err - } - req.Header.Set(authHeader, authKey) - } resp, err := cli.httpClient.Do(req) if err != nil { return ouloc, err diff --git a/putman.go b/putman.go index 6dcb1a7..8d1e73a 100644 --- a/putman.go +++ b/putman.go @@ -7,15 +7,14 @@ import ( "net/http" ) -func (cli *Client) PutManifest(ctx context.Context, rawref string, man []byte, mime string) error { +func (cli *Client) PutManifest(ctx context.Context, rawrepo, tag string, man []byte, mime string) error { var err error - ref, err := NewReference(rawref) + ref, err := NewRepository(rawrepo) if err != nil { return err } - uri := ref.Manifest() - user, pass := ref.Userinfo() + uri := ref.Manifest(tag) buffer := bytes.NewBuffer(man) req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, buffer) @@ -25,13 +24,6 @@ func (cli *Client) PutManifest(ctx context.Context, rawref string, man []byte, m req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Docker-Content-Digest", SHA256Digest(man)) req.Header.Set("Content-Type", mime) - if cli.authenticator != nil { - authHeader, authKey, err := cli.authenticator.MakeHeader(user, pass) - if err != nil { - return err - } - req.Header.Set(authHeader, authKey) - } resp, err := cli.httpClient.Do(req) if err != nil { return err diff --git a/putupload.go b/putupload.go index 8578457..0e6768a 100644 --- a/putupload.go +++ b/putupload.go @@ -8,11 +8,11 @@ import ( "strconv" ) -func (cli *Client) PutUpload(ctx context.Context, rawref string, src io.Reader, uploc, digest string, size int64) (string, error) { +func (cli *Client) PutUpload(ctx context.Context, rawrepo string, src io.Reader, uploc, digest string, size int64) (string, error) { var err error var bloc string - ref, err := NewReference(rawref) + ref, err := NewRepository(rawrepo) if err != nil { return bloc, err } @@ -20,8 +20,6 @@ func (cli *Client) PutUpload(ctx context.Context, rawref string, src io.Reader, if err != nil { return bloc, err } - user, pass := ref.Userinfo() - req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, src) if err != nil { return bloc, err @@ -29,13 +27,6 @@ func (cli *Client) PutUpload(ctx context.Context, rawref string, src io.Reader, req.Header.Set("User-Agent", cli.userAgent) req.Header.Set("Content-Type", "application/octet-stream") req.Header.Set("Content-Length", strconv.FormatInt(size, 10)) - if cli.authenticator != nil { - authHeader, authKey, err := cli.authenticator.MakeHeader(user, pass) - if err != nil { - return bloc, err - } - req.Header.Set(authHeader, authKey) - } resp, err := cli.httpClient.Do(req) if err != nil { return bloc, err diff --git a/referer.go b/referer.go index 8756e12..43bf861 100644 --- a/referer.go +++ b/referer.go @@ -1,88 +1,87 @@ package client import ( - "errors" "net/url" "strings" ) -type Reference struct { +type Repository struct { urlobj *url.URL user, pass string - repo, tag string + base string } -func NewReference(rawref string) (*Reference, error) { - ref := &Reference{} - if !strings.Contains(rawref, "://") { - rawref = "https://" + rawref +func NewRepository(rawrepo string) (*Repository, error) { + repo := &Repository{} + if !strings.Contains(rawrepo, "://") { + rawrepo = "https://" + rawrepo } - urlobj, err := url.Parse(rawref) + urlobj, err := url.Parse(rawrepo) if err != nil { - return ref, err + return repo, err } if urlobj.User != nil { - ref.user = urlobj.User.Username() - ref.pass, _ = urlobj.User.Password() + repo.user = urlobj.User.Username() + repo.pass, _ = urlobj.User.Password() urlobj.User = nil } - repotag := strings.SplitN(urlobj.Path, ":", 2) - if len(repotag) != 2 { - err = errors.New("Incorrect repo") - return ref, err - } - ref.urlobj = urlobj - ref.urlobj.Path = "/" - ref.repo = repotag[0] - ref.tag = repotag[1] - ref.urlobj = urlobj + repo.urlobj = urlobj + repo.base = repo.urlobj.Path + repo.urlobj.Path = "/" + repo.urlobj = urlobj - return ref, err + return repo, err } -func (ref *Reference) Manifest() string { - curl := ref.urlobj.JoinPath("/v2", ref.repo, "/manifests", ref.tag) +func (repo *Repository) Manifest(tag string) string { + curl := repo.urlobj.JoinPath("/v2", repo.base, "/manifests", tag) return curl.String() } -func (ref *Reference) Blob() string { - curl := ref.urlobj.JoinPath("/v2", ref.repo, "/blobs", ref.tag) +func (repo *Repository) Blob(digest string) string { + curl := repo.urlobj.JoinPath("/v2", repo.base, "/blobs", digest) return curl.String() } -func (ref *Reference) Upload() string { - curl := ref.urlobj.JoinPath("/v2", ref.repo, "/blobs/uploads/") +func (repo *Repository) Upload() string { + curl := repo.urlobj.JoinPath("/v2", repo.base, "/blobs/uploads/") return curl.String() } -func (ref *Reference) Patch(loc string) (string, error) { +func (repo *Repository) Patch(loc string) (string, error) { var curl *url.URL var out string var err error - + if isUUID(loc) { + curl = repo.urlobj.JoinPath("/v2/", repo.base, "/blobs/uploads/", loc) + return curl.String(), nil + } if strings.Contains(loc, "://") { curl, err = url.Parse(loc) if err != nil { return out, err } } else { - curl = ref.urlobj.JoinPath(loc) + curl = repo.urlobj.JoinPath(loc) } out = curl.String() return out, err } -func (ref *Reference) Put(loc, digest string) (string, error) { +func (repo *Repository) Put(loc, digest string) (string, error) { var curl *url.URL var out string var err error - if strings.Contains(loc, "://") { + + if isUUID(loc) { + curl = repo.urlobj.JoinPath("/v2/", repo.base, "/blobs/uploads/", loc) + } else if strings.Contains(loc, "://") { curl, err = url.Parse(loc) if err != nil { return out, err } } else { - curl = ref.urlobj.JoinPath(loc) + curl = repo.urlobj.JoinPath(loc) } query := curl.Query() query.Set("digest", digest) @@ -91,10 +90,6 @@ func (ref *Reference) Put(loc, digest string) (string, error) { return out, err } -func (ref *Reference) Tag() string { - return ref.tag -} - -func (ref *Reference) Userinfo() (string, string) { - return ref.user, ref.pass +func (repo *Repository) Userinfo() (string, string) { + return repo.user, repo.pass }