Skip to content

Commit

Permalink
Resolve ambiguity on registry v2 ping
Browse files Browse the repository at this point in the history
v2 ping now checks for a Docker-Distribution-API-Version
header that identifies the endpoint as "registry/2.0"

Docker-DCO-1.1-Signed-off-by: Josh Hawn <[email protected]> (github: jlhawn)
  • Loading branch information
Josh Hawn committed Jan 21, 2015
1 parent 5f5e02d commit f46923b
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ RUN set -x \
COPY pkg/tarsum /go/src/github.com/docker/docker/pkg/tarsum
# REGISTRY_COMMIT gives us the repeatability guarantees we need
# (so that we're all testing the same version of the registry)
ENV REGISTRY_COMMIT 21a69f53b5c7986b831f33849d551cd59ec8cbd1
ENV REGISTRY_COMMIT c448e0416925a9876d5576e412703c9b8b865e19
RUN set -x \
&& git clone https://github.com/docker/distribution.git /go/src/github.com/docker/distribution \
&& (cd /go/src/github.com/docker/distribution && git checkout -q $REGISTRY_COMMIT) \
Expand Down
15 changes: 15 additions & 0 deletions registry/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,21 @@ func (e *Endpoint) pingV2() (RegistryInfo, error) {
}
defer resp.Body.Close()

// The endpoint may have multiple supported versions.
// Ensure it supports the v2 Registry API.
var supportsV2 bool

for _, versionName := range resp.Header[http.CanonicalHeaderKey("Docker-Distribution-API-Version")] {
if versionName == "registry/2.0" {
supportsV2 = true
break
}
}

if !supportsV2 {
return RegistryInfo{}, fmt.Errorf("%s does not appear to be a v2 registry endpoint", e)
}

if resp.StatusCode == http.StatusOK {
// It would seem that no authentication/authorization is required.
// So we don't need to parse/add any authorization schemes.
Expand Down
63 changes: 62 additions & 1 deletion registry/endpoint_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package registry

import "testing"
import (
"net/http"
"net/http/httptest"
"net/url"
"testing"
)

func TestEndpointParse(t *testing.T) {
testData := []struct {
Expand All @@ -27,3 +32,59 @@ func TestEndpointParse(t *testing.T) {
}
}
}

// Ensure that a registry endpoint that responds with a 401 only is determined
// to be a v1 registry unless it includes a valid v2 API header.
func TestValidateEndpointAmbiguousAPIVersion(t *testing.T) {
requireBasicAuthHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("WWW-Authenticate", `Basic realm="localhost"`)
w.WriteHeader(http.StatusUnauthorized)
})

requireBasicAuthHandlerV2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Docker-Distribution-API-Version", "registry/2.0")
requireBasicAuthHandler.ServeHTTP(w, r)
})

// Make a test server which should validate as a v1 server.
testServer := httptest.NewServer(requireBasicAuthHandler)
defer testServer.Close()

testServerURL, err := url.Parse(testServer.URL)
if err != nil {
t.Fatal(err)
}

testEndpoint := Endpoint{
URL: testServerURL,
Version: APIVersionUnknown,
}

if err = validateEndpoint(&testEndpoint); err != nil {
t.Fatal(err)
}

if testEndpoint.Version != APIVersion1 {
t.Fatalf("expected endpoint to validate to %s, got %s", APIVersion1, testEndpoint.Version)
}

// Make a test server which should validate as a v2 server.
testServer = httptest.NewServer(requireBasicAuthHandlerV2)
defer testServer.Close()

testServerURL, err = url.Parse(testServer.URL)
if err != nil {
t.Fatal(err)
}

testEndpoint.URL = testServerURL
testEndpoint.Version = APIVersionUnknown

if err = validateEndpoint(&testEndpoint); err != nil {
t.Fatal(err)
}

if testEndpoint.Version != APIVersion2 {
t.Fatalf("expected endpoint to validate to %s, got %s", APIVersion2, testEndpoint.Version)
}
}

0 comments on commit f46923b

Please sign in to comment.