From 1bfbeca7269121e55d2b7a66853563aa25973790 Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Sat, 18 Nov 2017 21:50:22 -0800 Subject: [PATCH] Properly follow relative links when listing tags The previous code assumed that the link returned when listing tags was always absolute. However, some registries, such as quay.io, return the link as a relative link (e.g. the second page for the quay.io/coreos/etcd image is /v2/coreos/etcd/tags/list?next_page=&n=50). Because the relative link was retrieved directly, the fetch failed (with the error `unsupported protocol scheme ""`). Signed-off-by: Kevin Lin --- registry/client/repository.go | 17 ++++++++++++++--- registry/client/repository_test.go | 18 ++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/registry/client/repository.go b/registry/client/repository.go index ed29cf3f5..d8e2c795d 100644 --- a/registry/client/repository.go +++ b/registry/client/repository.go @@ -205,13 +205,18 @@ type tags struct { func (t *tags) All(ctx context.Context) ([]string, error) { var tags []string - u, err := t.ub.BuildTagsURL(t.name) + listURLStr, err := t.ub.BuildTagsURL(t.name) + if err != nil { + return tags, err + } + + listURL, err := url.Parse(listURLStr) if err != nil { return tags, err } for { - resp, err := t.client.Get(u) + resp, err := t.client.Get(listURL.String()) if err != nil { return tags, err } @@ -231,7 +236,13 @@ func (t *tags) All(ctx context.Context) ([]string, error) { } tags = append(tags, tagsResponse.Tags...) if link := resp.Header.Get("Link"); link != "" { - u = strings.Trim(strings.Split(link, ";")[0], "<>") + linkURLStr := strings.Trim(strings.Split(link, ";")[0], "<>") + linkURL, err := url.Parse(linkURLStr) + if err != nil { + return tags, err + } + + listURL = listURL.ResolveReference(linkURL) } else { return tags, nil } diff --git a/registry/client/repository_test.go b/registry/client/repository_test.go index 3bcf63e17..4018a9285 100644 --- a/registry/client/repository_test.go +++ b/registry/client/repository_test.go @@ -1136,13 +1136,27 @@ func TestManifestTagsPaginated(t *testing.T) { queryParams["n"] = []string{"1"} queryParams["last"] = []string{tagsList[i-1]} } + + // Test both relative and absolute links. + relativeLink := "/v2/" + repo.Name() + "/tags/list?n=1&last=" + tagsList[i] + var link string + switch i { + case 0: + link = relativeLink + case len(tagsList) - 1: + link = "" + default: + link = s.URL + relativeLink + } + headers := http.Header(map[string][]string{ "Content-Length": {fmt.Sprint(len(body))}, "Last-Modified": {time.Now().Add(-1 * time.Second).Format(time.ANSIC)}, }) - if i < 2 { - headers.Set("Link", "<"+s.URL+"/v2/"+repo.Name()+"/tags/list?n=1&last="+tagsList[i]+`>; rel="next"`) + if link != "" { + headers.Set("Link", fmt.Sprintf(`<%s>; rel="next"`, link)) } + m = append(m, testutil.RequestResponseMapping{ Request: testutil.Request{ Method: "GET",