Support HEAD requests without Docker-Content-Digest header
A statically hosted registry that responds correctly to GET with a manifest will load the right digest (by looking at the manifest body and calculating the digest). If the registry returns a HEAD without `Docker-Content-Digest`, then the client Tags().Get() call will return an empty digest. This commit changes the client to fallback to loading the tag via GET if the `Docker-Content-Digest` header is not set. Signed-off-by: Clayton Coleman <ccoleman@redhat.com>master
							parent
							
								
									d9e0121fef
								
							
						
					
					
						commit
						a2015272c1
					
				|  | @ -321,7 +321,8 @@ func (t *tags) Get(ctx context.Context, tag string) (distribution.Descriptor, er | |||
| 	defer resp.Body.Close() | ||||
| 
 | ||||
| 	switch { | ||||
| 	case resp.StatusCode >= 200 && resp.StatusCode < 400: | ||||
| 	case resp.StatusCode >= 200 && resp.StatusCode < 400 && len(resp.Header.Get("Docker-Content-Digest")) > 0: | ||||
| 		// if the response is a success AND a Docker-Content-Digest can be retrieved from the headers
 | ||||
| 		return descriptorFromResponse(resp) | ||||
| 	default: | ||||
| 		// if the response is an error - there will be no body to decode.
 | ||||
|  |  | |||
|  | @ -647,7 +647,38 @@ func addTestManifest(repo reference.Named, reference string, mediatype string, c | |||
| 			}), | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func addTestManifestWithoutDigestHeader(repo reference.Named, reference string, mediatype string, content []byte, m *testutil.RequestResponseMap) { | ||||
| 	*m = append(*m, testutil.RequestResponseMapping{ | ||||
| 		Request: testutil.Request{ | ||||
| 			Method: "GET", | ||||
| 			Route:  "/v2/" + repo.Name() + "/manifests/" + reference, | ||||
| 		}, | ||||
| 		Response: testutil.Response{ | ||||
| 			StatusCode: http.StatusOK, | ||||
| 			Body:       content, | ||||
| 			Headers: http.Header(map[string][]string{ | ||||
| 				"Content-Length": {fmt.Sprint(len(content))}, | ||||
| 				"Last-Modified":  {time.Now().Add(-1 * time.Second).Format(time.ANSIC)}, | ||||
| 				"Content-Type":   {mediatype}, | ||||
| 			}), | ||||
| 		}, | ||||
| 	}) | ||||
| 	*m = append(*m, testutil.RequestResponseMapping{ | ||||
| 		Request: testutil.Request{ | ||||
| 			Method: "HEAD", | ||||
| 			Route:  "/v2/" + repo.Name() + "/manifests/" + reference, | ||||
| 		}, | ||||
| 		Response: testutil.Response{ | ||||
| 			StatusCode: http.StatusOK, | ||||
| 			Headers: http.Header(map[string][]string{ | ||||
| 				"Content-Length": {fmt.Sprint(len(content))}, | ||||
| 				"Last-Modified":  {time.Now().Add(-1 * time.Second).Format(time.ANSIC)}, | ||||
| 				"Content-Type":   {mediatype}, | ||||
| 			}), | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func checkEqualManifest(m1, m2 *schema1.SignedManifest) error { | ||||
|  | @ -994,6 +1025,36 @@ func TestObtainsErrorForMissingTag(t *testing.T) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestObtainsManifestForTagWithoutHeaders(t *testing.T) { | ||||
| 	repo, _ := reference.WithName("test.example.com/repo") | ||||
| 
 | ||||
| 	var m testutil.RequestResponseMap | ||||
| 	m1, dgst, _ := newRandomSchemaV1Manifest(repo, "latest", 6) | ||||
| 	_, pl, err := m1.Payload() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	addTestManifestWithoutDigestHeader(repo, "1.0.0", schema1.MediaTypeSignedManifest, pl, &m) | ||||
| 
 | ||||
| 	e, c := testServer(m) | ||||
| 	defer c() | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
| 	r, err := NewRepository(ctx, repo, e, nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	tagService := r.Tags(ctx) | ||||
| 
 | ||||
| 	desc, err := tagService.Get(ctx, "1.0.0") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Expected no error") | ||||
| 	} | ||||
| 	if desc.Digest != dgst { | ||||
| 		t.Fatalf("Unexpected digest") | ||||
| 	} | ||||
| } | ||||
| func TestManifestTagsPaginated(t *testing.T) { | ||||
| 	s := httptest.NewServer(http.NotFoundHandler()) | ||||
| 	defer s.Close() | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue