Skip to content

Commit

Permalink
Merge pull request #721 from sjdaws/use-HEAD
Browse files Browse the repository at this point in the history
Prefer HEAD over GET for manifest digest
  • Loading branch information
rusenask authored Apr 21, 2023
2 parents 70c1b89 + 5cd202f commit a9c1a4c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
32 changes: 25 additions & 7 deletions registry/docker/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,24 @@ func (r *Registry) ManifestDigest(repository, reference string) (digest.Digest,
url := r.url("/v2/%s/manifests/%s", repository, reference)
r.Logf("registry.manifest.head url=%s repository=%s reference=%s", url, repository, reference)

req, err := http.NewRequest("GET", url, nil)
// Try HEAD request first because it's free
resp, err := r.request("HEAD", url)
if err != nil {
return "", err
}

req.Header.Set("Accept", strings.Join([]string{manifestv2.MediaTypeManifest, oci.MediaTypeImageIndex, oci.MediaTypeImageManifest}, ","))
resp, err := r.Client.Do(req)
if hdr := resp.Header.Get("Docker-Content-Digest"); hdr != "" {
return digest.Parse(hdr)
}

// HEAD request didn't return a digest, attempt to fetch digest from body
r.Logf("registry.manifest.get url=%s repository=%s reference=%s", url, repository, reference)
resp, err = r.request("GET", url)
if err != nil {
return "", err
}
defer resp.Body.Close()

if hdr := resp.Header.Get("Docker-Content-Digest"); hdr != "" {
return digest.Parse(hdr)
}

// Try to get digest from body instead, should be equal to what would be presented
// in Docker-Content-Digest
body, err := ioutil.ReadAll(resp.Body)
Expand All @@ -39,3 +41,19 @@ func (r *Registry) ManifestDigest(repository, reference string) (digest.Digest,
}
return digest.FromBytes(body), nil
}

// request performs a request against a url
func (r *Registry) request(method string, url string) (*http.Response, error) {
req, err := http.NewRequest(method, url, nil)
if err != nil {
return nil, err
}

req.Header.Set("Accept", strings.Join([]string{manifestv2.MediaTypeManifest, oci.MediaTypeImageIndex, oci.MediaTypeImageManifest}, ","))
resp, err := r.Client.Do(req)
if err != nil {
return nil, err
}

return resp, nil
}
6 changes: 6 additions & 0 deletions registry/docker/manifest_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package docker

import (
"bytes"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
Expand All @@ -24,9 +26,13 @@ func TestGetDigest(t *testing.T) {
}
defer resp.Body.Close()

bodyBytes, _ := ioutil.ReadAll(resp.Body)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("content-type", "application/vnd.docker.distribution.manifest.v2+json; charset=ISO-8859-1")
io.Copy(w, resp.Body)

// Reset body for additional calls
resp.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
}))
defer ts.Close()

Expand Down

0 comments on commit a9c1a4c

Please sign in to comment.