diff --git a/docker/data_source_docker_registry_image.go b/docker/data_source_docker_registry_image.go index 0aebe8f2..37d2e276 100644 --- a/docker/data_source_docker_registry_image.go +++ b/docker/data_source_docker_registry_image.go @@ -1,6 +1,7 @@ package docker import ( + "crypto/sha256" "crypto/tls" "encoding/json" "fmt" @@ -119,7 +120,7 @@ func getImageDigest(registry, image, tag, username, password string, fallback bo switch resp.StatusCode { // Basic auth was valid or not needed case http.StatusOK: - return resp.Header.Get("Docker-Content-Digest"), nil + return getDigestFromResponse(resp) // Either OAuth is required or the basic auth creds were invalid case http.StatusUnauthorized: @@ -170,7 +171,7 @@ func getImageDigest(registry, image, tag, username, password string, fallback bo return "", fmt.Errorf("Got bad response from registry: " + digestResponse.Status) } - return digestResponse.Header.Get("Docker-Content-Digest"), nil + return getDigestFromResponse(digestResponse) } return "", fmt.Errorf("Bad credentials: " + resp.Status) @@ -200,3 +201,18 @@ func parseAuthHeader(header string) map[string]string { return opts } + +func getDigestFromResponse(response *http.Response) (string, error) { + header := response.Header.Get("Docker-Content-Digest") + + if header == "" { + body, err := ioutil.ReadAll(response.Body) + if err != nil { + return "", fmt.Errorf("Error reading registry response body: %s", err) + } + + return fmt.Sprintf("sha256:%x", sha256.Sum256(body)), nil + } + + return header, nil +} diff --git a/docker/data_source_docker_registry_image_test.go b/docker/data_source_docker_registry_image_test.go index 138ab06d..d56fd76c 100644 --- a/docker/data_source_docker_registry_image_test.go +++ b/docker/data_source_docker_registry_image_test.go @@ -1,7 +1,10 @@ package docker import ( + "bytes" "fmt" + "io/ioutil" + "net/http" "regexp" "testing" @@ -82,3 +85,27 @@ data "docker_registry_image" "foobar" { name = "%s" } ` + +func TestGetDigestFromResponse(t *testing.T) { + headerContent := "sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae" + respWithHeaders := &http.Response{ + Header: http.Header{ + "Docker-Content-Digest": []string{headerContent}, + }, + Body: ioutil.NopCloser(bytes.NewReader([]byte("foo"))), + } + + if digest, _ := getDigestFromResponse(respWithHeaders); digest != headerContent { + t.Errorf("Expected digest from header to be %s, but was %s", headerContent, digest) + } + + bodyDigest := "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9" + respWithoutHeaders := &http.Response{ + Header: make(http.Header), + Body: ioutil.NopCloser(bytes.NewReader([]byte("bar"))), + } + + if digest, _ := getDigestFromResponse(respWithoutHeaders); digest != bodyDigest { + t.Errorf("Expected digest calculated from body to be %s, but was %s", bodyDigest, digest) + } +}