forked from TrueCloudLab/distribution
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=<truncated>&n=50). Because the relative link was retrieved directly, the fetch failed (with the error `unsupported protocol scheme ""`). Signed-off-by: Kevin Lin <kevin@kelda.io>
This commit is contained in:
parent
e5b5e44386
commit
1bfbeca726
2 changed files with 30 additions and 5 deletions
|
@ -205,13 +205,18 @@ type tags struct {
|
||||||
func (t *tags) All(ctx context.Context) ([]string, error) {
|
func (t *tags) All(ctx context.Context) ([]string, error) {
|
||||||
var tags []string
|
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 {
|
if err != nil {
|
||||||
return tags, err
|
return tags, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
resp, err := t.client.Get(u)
|
resp, err := t.client.Get(listURL.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tags, err
|
return tags, err
|
||||||
}
|
}
|
||||||
|
@ -231,7 +236,13 @@ func (t *tags) All(ctx context.Context) ([]string, error) {
|
||||||
}
|
}
|
||||||
tags = append(tags, tagsResponse.Tags...)
|
tags = append(tags, tagsResponse.Tags...)
|
||||||
if link := resp.Header.Get("Link"); link != "" {
|
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 {
|
} else {
|
||||||
return tags, nil
|
return tags, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1136,13 +1136,27 @@ func TestManifestTagsPaginated(t *testing.T) {
|
||||||
queryParams["n"] = []string{"1"}
|
queryParams["n"] = []string{"1"}
|
||||||
queryParams["last"] = []string{tagsList[i-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{
|
headers := http.Header(map[string][]string{
|
||||||
"Content-Length": {fmt.Sprint(len(body))},
|
"Content-Length": {fmt.Sprint(len(body))},
|
||||||
"Last-Modified": {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
|
"Last-Modified": {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
|
||||||
})
|
})
|
||||||
if i < 2 {
|
if link != "" {
|
||||||
headers.Set("Link", "<"+s.URL+"/v2/"+repo.Name()+"/tags/list?n=1&last="+tagsList[i]+`>; rel="next"`)
|
headers.Set("Link", fmt.Sprintf(`<%s>; rel="next"`, link))
|
||||||
}
|
}
|
||||||
|
|
||||||
m = append(m, testutil.RequestResponseMapping{
|
m = append(m, testutil.RequestResponseMapping{
|
||||||
Request: testutil.Request{
|
Request: testutil.Request{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
|
|
Loading…
Reference in a new issue